// 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.Collections.Generic; using System.Linq; using System.Reflection; using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Cors; using Microsoft.AspNet.Cors.Core; using Microsoft.AspNet.Mvc.Description; using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Routing; using Microsoft.Framework.Internal; using Microsoft.Framework.Logging; using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Mvc.ApplicationModels { /// /// A default implementation of . /// public class DefaultControllerModelBuilder : IControllerModelBuilder { private readonly IActionModelBuilder _actionModelBuilder; private readonly ILogger _logger; private readonly AuthorizationOptions _authorizationOptions; /// /// Creates a new . /// /// The used to create actions. public DefaultControllerModelBuilder( IActionModelBuilder actionModelBuilder, ILoggerFactory loggerFactory, IOptions authorizationOptions) { _actionModelBuilder = actionModelBuilder; _logger = loggerFactory.CreateLogger(); _authorizationOptions = authorizationOptions?.Options ?? new AuthorizationOptions(); } /// public ControllerModel BuildControllerModel([NotNull] TypeInfo typeInfo) { var controllerModel = CreateControllerModel(typeInfo); var controllerType = typeInfo.AsType(); foreach (var methodInfo in controllerType.GetMethods()) { var actionModels = _actionModelBuilder.BuildActionModels(typeInfo, methodInfo); if (actionModels != null) { foreach (var actionModel in actionModels) { actionModel.Controller = controllerModel; controllerModel.Actions.Add(actionModel); } } } foreach (var propertyHelper in PropertyHelper.GetProperties(controllerType)) { var propertyInfo = propertyHelper.Property; var propertyModel = CreatePropertyModel(propertyInfo); if (propertyModel != null) { propertyModel.Controller = controllerModel; controllerModel.ControllerProperties.Add(propertyModel); } } return controllerModel; } /// /// 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; AddRange(controllerModel.ActionConstraints, attributes.OfType()); AddRange(controllerModel.Filters, attributes.OfType()); AddRange(controllerModel.RouteConstraints, attributes.OfType()); var enableCors = attributes.OfType().SingleOrDefault(); if (enableCors != null) { controllerModel.Filters.Add(new CorsAuthorizationFilterFactory(enableCors.PolicyName)); } var disableCors = attributes.OfType().SingleOrDefault(); if (disableCors != null) { controllerModel.Filters.Add(new DisableCorsAuthorizationFilter()); } var policy = AuthorizationPolicy.Combine(_authorizationOptions, attributes.OfType()); if (policy != null) { controllerModel.Filters.Add(new AuthorizeFilter(policy)); } AddRange( controllerModel.AttributeRoutes, 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; } // Controllers can implement action filter and result filter interfaces. We add // a special delegating filter implementation to the pipeline to handle it. // // This is needed because filters are instantiated before the controller. if (typeof(IAsyncActionFilter).GetTypeInfo().IsAssignableFrom(typeInfo) || typeof(IActionFilter).GetTypeInfo().IsAssignableFrom(typeInfo)) { controllerModel.Filters.Add(new ControllerActionFilter()); } if (typeof(IAsyncResultFilter).GetTypeInfo().IsAssignableFrom(typeInfo) || typeof(IResultFilter).GetTypeInfo().IsAssignableFrom(typeInfo)) { controllerModel.Filters.Add(new ControllerResultFilter()); } return controllerModel; } /// /// Creates a for the given . /// /// The . /// A for the given . protected virtual PropertyModel CreatePropertyModel([NotNull] PropertyInfo propertyInfo) { // CoreCLR returns IEnumerable from GetCustomAttributes - the OfType // is needed to so that the result of ToArray() is object var attributes = propertyInfo.GetCustomAttributes(inherit: true).OfType().ToArray(); var propertyModel = new PropertyModel(propertyInfo, attributes); var bindingInfo = BindingInfo.GetBindingInfo(attributes); propertyModel.BindingInfo = bindingInfo; propertyModel.PropertyName = propertyInfo.Name; return propertyModel; } private static void AddRange(IList list, IEnumerable items) { foreach (var item in items) { list.Add(item); } } } }