aspnetcore/src/Microsoft.AspNet.Mvc.Core/ApplicationModels/DefaultControllerModelBuild...

123 lines
5.1 KiB
C#

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.Description;
using Microsoft.AspNet.Mvc.Routing;
namespace Microsoft.AspNet.Mvc.ApplicationModels
{
/// <summary>
/// A default implementation of <see cref="IControllerModelBuilder"/>.
/// </summary>
public class DefaultControllerModelBuilder : IControllerModelBuilder
{
private readonly IActionModelBuilder _actionModelBuilder;
/// <summary>
/// Creates a new <see cref="DefaultControllerModelBuilder"/>.
/// </summary>
/// <param name="actionModelBuilder">The <see cref="IActionModelBuilder"/> used to create actions.</param>
public DefaultControllerModelBuilder(IActionModelBuilder actionModelBuilder)
{
_actionModelBuilder = actionModelBuilder;
}
/// <inheritdoc />
public ControllerModel BuildControllerModel([NotNull] TypeInfo typeInfo)
{
if (!IsController(typeInfo))
{
return null;
}
var controllerModel = CreateControllerModel(typeInfo);
foreach (var methodInfo in typeInfo.AsType().GetMethods())
{
var actionModels = _actionModelBuilder.BuildActionModels(typeInfo, methodInfo);
if (actionModels != null)
{
foreach (var actionModel in actionModels)
{
actionModel.Controller = controllerModel;
controllerModel.Actions.Add(actionModel);
}
}
}
return controllerModel;
}
/// <summary>
/// Returns <c>true</c> if the <paramref name="typeInfo"/> is a controller. Otherwise <c>false</c>.
/// </summary>
/// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
/// <returns><c>true</c> if the <paramref name="typeInfo"/> is a controller. Otherwise <c>false</c>.</returns>
/// <remarks>
/// Override this method to provide custom logic to determine which types are considered controllers.
/// </remarks>
protected virtual bool IsController([NotNull] TypeInfo typeInfo)
{
if (!typeInfo.IsClass ||
typeInfo.IsAbstract ||
// We only consider public top-level classes as controllers. IsPublic returns false for nested
// classes, regardless of visibility modifiers.
!typeInfo.IsPublic ||
typeInfo.ContainsGenericParameters)
{
return false;
}
if (typeInfo.Name.Equals("Controller", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ||
typeof(Controller).GetTypeInfo().IsAssignableFrom(typeInfo);
}
/// <summary>
/// Creates an <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.
/// </summary>
/// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
/// <returns>A <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.</returns>
protected virtual ControllerModel CreateControllerModel([NotNull] TypeInfo typeInfo)
{
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
// is needed to so that the result of ToArray() is object
var attributes = typeInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
var controllerModel = new ControllerModel(typeInfo, attributes);
controllerModel.ControllerName =
typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ?
typeInfo.Name.Substring(0, typeInfo.Name.Length - "Controller".Length) :
typeInfo.Name;
controllerModel.ActionConstraints.AddRange(attributes.OfType<IActionConstraintMetadata>());
controllerModel.Filters.AddRange(attributes.OfType<IFilter>());
controllerModel.RouteConstraints.AddRange(attributes.OfType<RouteConstraintAttribute>());
controllerModel.AttributeRoutes.AddRange(
attributes.OfType<IRouteTemplateProvider>().Select(rtp => new AttributeRouteModel(rtp)));
var apiVisibility = attributes.OfType<IApiDescriptionVisibilityProvider>().FirstOrDefault();
if (apiVisibility != null)
{
controllerModel.ApiExplorer.IsVisible = !apiVisibility.IgnoreApi;
}
var apiGroupName = attributes.OfType<IApiDescriptionGroupNameProvider>().FirstOrDefault();
if (apiGroupName != null)
{
controllerModel.ApiExplorer.GroupName = apiGroupName.GroupName;
}
return controllerModel;
}
}
}