zoukankan      html  css  js  c++  java
  • asp.net core mvc 3.1 源码分析(三)

    前面讲到ApplicationModel对象,那接下来看看ApplicationModel

    /// <summary>
        /// A model for configuring controllers in an MVC application.
        /// </summary>
        [DebuggerDisplay("ApplicationModel: Controllers: {Controllers.Count}, Filters: {Filters.Count}")]
        public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel
        {
            /// <summary>
            /// Initializes a new instance of <see cref="ApplicationModel"/>.
            /// </summary>
            public ApplicationModel()
            {
                ApiExplorer = new ApiExplorerModel();
                Controllers = new List<ControllerModel>();
                Filters = new List<IFilterMetadata>();
                Properties = new Dictionary<object, object>();
            }
    
            /// <summary>
            /// Gets or sets the <see cref="ApiExplorerModel"/> for the application.
            /// </summary>
            /// <remarks>
            /// <see cref="ApplicationModel.ApiExplorer"/> allows configuration of default settings
            /// for ApiExplorer that apply to all actions unless overridden by 
            /// <see cref="ControllerModel.ApiExplorer"/> or <see cref="ActionModel.ApiExplorer"/>.
            /// 
            /// If using <see cref="ApplicationModel.ApiExplorer"/> to set <see cref="ApiExplorerModel.IsVisible"/> to
            /// <c>true</c>, this setting will only be honored for actions which use attribute routing.
            /// </remarks>
            public ApiExplorerModel ApiExplorer { get; set; }
    
            /// <summary>
            /// Gets the <see cref="ControllerModel"/> instances.
            /// </summary>
            public IList<ControllerModel> Controllers { get; }
    
            /// <summary>
            /// Gets the global <see cref="IFilterMetadata"/> instances.
            /// </summary>
            public IList<IFilterMetadata> Filters { get; }
    
            /// <summary>
            /// Gets a set of properties associated with all actions.
            /// These properties will be copied to <see cref="Abstractions.ActionDescriptor.Properties"/>.
            /// </summary>
            public IDictionary<object, object> Properties { get; }
        }

     上面是ApplicationModel的关系图

    首先看下DefaultApplicationModelProvider如何创建ApplicationModel

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException(nameof(context));
                }
    
                foreach (var filter in _mvcOptions.Filters)
                {
                    context.Result.Filters.Add(filter);
                }
    
                foreach (var controllerType in context.ControllerTypes)
                {
                    var controllerModel = CreateControllerModel(controllerType);
                    if (controllerModel == null)
                    {
                        continue;
                    }
    
                    context.Result.Controllers.Add(controllerModel);
                    controllerModel.Application = context.Result;
    
                    foreach (var propertyHelper in PropertyHelper.GetProperties(controllerType.AsType()))
                    {
                        var propertyInfo = propertyHelper.Property;
                        var propertyModel = CreatePropertyModel(propertyInfo);
                        if (propertyModel != null)
                        {
                            propertyModel.Controller = controllerModel;
                            controllerModel.ControllerProperties.Add(propertyModel);
                        }
                    }
    
                    foreach (var methodInfo in controllerType.AsType().GetMethods())
                    {
                        var actionModel = CreateActionModel(controllerType, methodInfo);
                        if (actionModel == null)
                        {
                            continue;
                        }
    
                        actionModel.Controller = controllerModel;
                        controllerModel.Actions.Add(actionModel);
    
                        foreach (var parameterInfo in actionModel.ActionMethod.GetParameters())
                        {
                            var parameterModel = CreateParameterModel(parameterInfo);
                            if (parameterModel != null)
                            {
                                parameterModel.Action = actionModel;
                                actionModel.Parameters.Add(parameterModel);
                            }
                        }
                    }
                }
            }

    先添加全局过滤器

    然后创建ControllerModel

    internal ControllerModel CreateControllerModel(TypeInfo typeInfo)
            {
                if (typeInfo == null)
                {
                    throw new ArgumentNullException(nameof(typeInfo));
                }
    
                // For attribute routes on a controller, we want to support 'overriding' routes on a derived
                // class. So we need to walk up the hierarchy looking for the first class to define routes.
                //
                // Then we want to 'filter' the set of attributes, so that only the effective routes apply.
                var currentTypeInfo = typeInfo;
                var objectTypeInfo = typeof(object).GetTypeInfo();
    
                IRouteTemplateProvider[] routeAttributes;
    
                do
                {
                    routeAttributes = currentTypeInfo
                        .GetCustomAttributes(inherit: false)
                        .OfType<IRouteTemplateProvider>()
                        .ToArray();
    
                    if (routeAttributes.Length > 0)
                    {
                        // Found 1 or more route attributes.
                        break;
                    }
    
                    currentTypeInfo = currentTypeInfo.BaseType.GetTypeInfo();
                }
                while (currentTypeInfo != objectTypeInfo);
    
                // 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);
    
                // This is fairly complicated so that we maintain referential equality between items in
                // ControllerModel.Attributes and ControllerModel.Attributes[*].Attribute.
                var filteredAttributes = new List<object>();
                foreach (var attribute in attributes)
                {
                    if (attribute is IRouteTemplateProvider)
                    {
                        // This attribute is a route-attribute, leave it out.
                    }
                    else
                    {
                        filteredAttributes.Add(attribute);
                    }
                }
    
                filteredAttributes.AddRange(routeAttributes);
    
                attributes = filteredAttributes.ToArray();
    
                var controllerModel = new ControllerModel(typeInfo, attributes);
    
                AddRange(controllerModel.Selectors, CreateSelectors(attributes));
    
                controllerModel.ControllerName =
                    typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ?
                        typeInfo.Name.Substring(0, typeInfo.Name.Length - "Controller".Length) :
                        typeInfo.Name;
    
                AddRange(controllerModel.Filters, attributes.OfType<IFilterMetadata>());
    
                foreach (var routeValueProvider in attributes.OfType<IRouteValueProvider>())
                {
                    controllerModel.RouteValues.Add(routeValueProvider.RouteKey, routeValueProvider.RouteValue);
                }
    
                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;
                }
    
                // 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;
            }

    再构建Controller的PropertyModel

    internal PropertyModel CreatePropertyModel(PropertyInfo propertyInfo)
            {
                if (propertyInfo == null)
                {
                    throw new ArgumentNullException(nameof(propertyInfo));
                }
    
                var attributes = propertyInfo.GetCustomAttributes(inherit: true);
    
                // BindingInfo for properties can be either specified by decorating the property with binding specific attributes.
                // ModelMetadata also adds information from the property's type and any configured IBindingMetadataProvider.
                var modelMetadata = _modelMetadataProvider.GetMetadataForProperty(propertyInfo.DeclaringType, propertyInfo.Name);
                var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
    
                if (bindingInfo == null)
                {
                    // Look for BindPropertiesAttribute on the handler type if no BindingInfo was inferred for the property.
                    // This allows a user to enable model binding on properties by decorating the controller type with BindPropertiesAttribute.
                    var declaringType = propertyInfo.DeclaringType;
                    var bindPropertiesAttribute = declaringType.GetCustomAttribute<BindPropertiesAttribute>(inherit: true);
                    if (bindPropertiesAttribute != null)
                    {
                        var requestPredicate = bindPropertiesAttribute.SupportsGet ? _supportsAllRequests : _supportsNonGetRequests;
                        bindingInfo = new BindingInfo
                        {
                            RequestPredicate = requestPredicate,
                        };
                    }
                }
    
                var propertyModel = new PropertyModel(propertyInfo, attributes)
                {
                    PropertyName = propertyInfo.Name,
                    BindingInfo = bindingInfo,
                };
    
                return propertyModel;
            }

    再创建Controller下面的ActionModel

    internal ActionModel CreateActionModel(
                TypeInfo typeInfo,
                MethodInfo methodInfo)
            {
                if (typeInfo == null)
                {
                    throw new ArgumentNullException(nameof(typeInfo));
                }
    
                if (methodInfo == null)
                {
                    throw new ArgumentNullException(nameof(methodInfo));
                }
    
                if (!IsAction(typeInfo, methodInfo))
                {
                    return null;
                }
    
                // CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
                // is needed to so that the result of ToArray() is object
                var attributes = methodInfo.GetCustomAttributes(inherit: true);
    
                var actionModel = new ActionModel(methodInfo, attributes);
    
                AddRange(actionModel.Filters, attributes.OfType<IFilterMetadata>());
    
                var actionName = attributes.OfType<ActionNameAttribute>().FirstOrDefault();
                if (actionName?.Name != null)
                {
                    actionModel.ActionName = actionName.Name;
                }
                else
                {
                    actionModel.ActionName = CanonicalizeActionName(methodInfo.Name);
                }
    
                var apiVisibility = attributes.OfType<IApiDescriptionVisibilityProvider>().FirstOrDefault();
                if (apiVisibility != null)
                {
                    actionModel.ApiExplorer.IsVisible = !apiVisibility.IgnoreApi;
                }
    
                var apiGroupName = attributes.OfType<IApiDescriptionGroupNameProvider>().FirstOrDefault();
                if (apiGroupName != null)
                {
                    actionModel.ApiExplorer.GroupName = apiGroupName.GroupName;
                }
    
                foreach (var routeValueProvider in attributes.OfType<IRouteValueProvider>())
                {
                    actionModel.RouteValues.Add(routeValueProvider.RouteKey, routeValueProvider.RouteValue);
                }
    
                // Now we need to determine the action selection info (cross-section of routes and constraints)
                //
                // For attribute routes on a action, we want to support 'overriding' routes on a
                // virtual method, but allow 'overriding'. So we need to walk up the hierarchy looking
                // for the first definition to define routes.
                //
                // Then we want to 'filter' the set of attributes, so that only the effective routes apply.
                var currentMethodInfo = methodInfo;
    
                IRouteTemplateProvider[] routeAttributes;
    
                while (true)
                {
                    routeAttributes = currentMethodInfo
                        .GetCustomAttributes(inherit: false)
                        .OfType<IRouteTemplateProvider>()
                        .ToArray();
    
                    if (routeAttributes.Length > 0)
                    {
                        // Found 1 or more route attributes.
                        break;
                    }
    
                    // GetBaseDefinition returns 'this' when it gets to the bottom of the chain.
                    var nextMethodInfo = currentMethodInfo.GetBaseDefinition();
                    if (currentMethodInfo == nextMethodInfo)
                    {
                        break;
                    }
    
                    currentMethodInfo = nextMethodInfo;
                }
    
                // This is fairly complicated so that we maintain referential equality between items in
                // ActionModel.Attributes and ActionModel.Attributes[*].Attribute.
                var applicableAttributes = new List<object>();
                foreach (var attribute in attributes)
                {
                    if (attribute is IRouteTemplateProvider)
                    {
                        // This attribute is a route-attribute, leave it out.
                    }
                    else
                    {
                        applicableAttributes.Add(attribute);
                    }
                }
    
                applicableAttributes.AddRange(routeAttributes);
                AddRange(actionModel.Selectors, CreateSelectors(applicableAttributes));
    
                return actionModel;
            }

    再创建Action参数的ParameterModel

    internal ParameterModel CreateParameterModel(ParameterInfo parameterInfo)
            {
                if (parameterInfo == null)
                {
                    throw new ArgumentNullException(nameof(parameterInfo));
                }
    
                var attributes = parameterInfo.GetCustomAttributes(inherit: true);
    
                BindingInfo bindingInfo;
                if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
                {
                    var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
                    bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
                }
                else
                {
                    // GetMetadataForParameter should only be used if the user has opted in to the 2.1 behavior.
                    bindingInfo = BindingInfo.GetBindingInfo(attributes);
                }
    
                var parameterModel = new ParameterModel(parameterInfo, attributes)
                {
                    ParameterName = parameterInfo.Name,
                    BindingInfo = bindingInfo,
                };
    
                return parameterModel;
            }
  • 相关阅读:
    Python+VSCode IDE 快速开发配置 #VSCode上配置Jupyter Notebook
    GUI Design Studio 简单通讯本设计原型 1
    GUI Design Studio 简单通讯本设计原型 2
    安装Lua For Windows
    Lua – Hello World!
    GUI Design Studio 功能面板介绍
    中文字符级转换
    Base64传输字节码转换
    这怎么是英文的?
    error? in CLR via c#
  • 原文地址:https://www.cnblogs.com/lanpingwang/p/12642605.html
Copyright © 2011-2022 走看看