// 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 { /// /// A default implementation of . /// public class DefaultControllerModelBuilder : IControllerModelBuilder { private readonly IActionModelBuilder _actionModelBuilder; /// /// Creates a new . /// /// The used to create actions. public DefaultControllerModelBuilder(IActionModelBuilder actionModelBuilder) { _actionModelBuilder = actionModelBuilder; } /// 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; } /// /// Returns true if the is a controller. Otherwise false. /// /// The . /// true if the is a controller. Otherwise false. /// /// Override this method to provide custom logic to determine which types are considered controllers. /// 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); } /// /// Creates an for the given . /// /// The . /// A for the given . protected virtual ControllerModel CreateControllerModel([NotNull] TypeInfo typeInfo) { // CoreCLR returns IEnumerable from GetCustomAttributes - the OfType // is needed to so that the result of ToArray() is object var attributes = typeInfo.GetCustomAttributes(inherit: true).OfType().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()); controllerModel.Filters.AddRange(attributes.OfType()); controllerModel.RouteConstraints.AddRange(attributes.OfType()); controllerModel.AttributeRoutes.AddRange( attributes.OfType().Select(rtp => new AttributeRouteModel(rtp))); var apiVisibility = attributes.OfType().FirstOrDefault(); if (apiVisibility != null) { controllerModel.ApiExplorer.IsVisible = !apiVisibility.IgnoreApi; } var apiGroupName = attributes.OfType().FirstOrDefault(); if (apiGroupName != null) { controllerModel.ApiExplorer.GroupName = apiGroupName.GroupName; } return controllerModel; } } }