asp.net core mvc 3.1 源码分析(五)

创建完ApplicationModel后,调用ControllerActionDescriptorBuilder类的Build方法创建对应的ControllerActionDescriptor

internal static class ControllerActionDescriptorBuilder
    {
        public static IList<ControllerActionDescriptor> Build(ApplicationModel application)
        {
            return ApplicationModelFactory.Flatten(application, CreateActionDescriptor);
        }

        private static ControllerActionDescriptor CreateActionDescriptor(
            ApplicationModel application,
            ControllerModel controller,
            ActionModel action,
            SelectorModel selector)
        {
            var actionDescriptor = new ControllerActionDescriptor
            {
                ActionName = action.ActionName,
                MethodInfo = action.ActionMethod,
            };

            actionDescriptor.ControllerName = controller.ControllerName;
            actionDescriptor.ControllerTypeInfo = controller.ControllerType;
            AddControllerPropertyDescriptors(actionDescriptor, controller);

            AddActionConstraints(actionDescriptor, selector);
            AddEndpointMetadata(actionDescriptor, selector);
            AddAttributeRoute(actionDescriptor, selector);
            AddParameterDescriptors(actionDescriptor, action);
            AddActionFilters(actionDescriptor, action.Filters, controller.Filters, application.Filters);
            AddApiExplorerInfo(actionDescriptor, application, controller, action);
            AddRouteValues(actionDescriptor, controller, action);
            AddProperties(actionDescriptor, action, controller, application);

            return actionDescriptor;
        }

        private static void AddControllerPropertyDescriptors(ActionDescriptor actionDescriptor, ControllerModel controller)
        {
            actionDescriptor.BoundProperties = controller.ControllerProperties
                .Where(p => p.BindingInfo != null)
                .Select(CreateParameterDescriptor)
                .ToList();
        }

        private static void AddParameterDescriptors(ActionDescriptor actionDescriptor, ActionModel action)
        {
            var parameterDescriptors = new List<ParameterDescriptor>();
            foreach (var parameter in action.Parameters)
            {
                var parameterDescriptor = CreateParameterDescriptor(parameter);
                parameterDescriptors.Add(parameterDescriptor);
            }

            actionDescriptor.Parameters = parameterDescriptors;
        }

        private static ParameterDescriptor CreateParameterDescriptor(ParameterModel parameterModel)
        {
            var parameterDescriptor = new ControllerParameterDescriptor()
            {
                Name = parameterModel.ParameterName,
                ParameterType = parameterModel.ParameterInfo.ParameterType,
                BindingInfo = parameterModel.BindingInfo,
                ParameterInfo = parameterModel.ParameterInfo,
            };

            return parameterDescriptor;
        }

        private static ParameterDescriptor CreateParameterDescriptor(PropertyModel propertyModel)
        {
            var parameterDescriptor = new ControllerBoundPropertyDescriptor()
            {
                BindingInfo = propertyModel.BindingInfo,
                Name = propertyModel.PropertyName,
                ParameterType = propertyModel.PropertyInfo.PropertyType,
                PropertyInfo = propertyModel.PropertyInfo,
            };

            return parameterDescriptor;
        }

        private static void AddApiExplorerInfo(
            ControllerActionDescriptor actionDescriptor,
            ApplicationModel application,
            ControllerModel controller,
            ActionModel action)
        {
            var isVisible =
                action.ApiExplorer?.IsVisible ??
                controller.ApiExplorer?.IsVisible ??
                application.ApiExplorer?.IsVisible ??
                false;

            var isVisibleSetOnActionOrController =
                action.ApiExplorer?.IsVisible ??
                controller.ApiExplorer?.IsVisible ??
                false;

            // ApiExplorer isn‘t supported on conventional-routed actions, but we still allow you to configure
            // it at the application level when you have a mix of controller types. We‘ll just skip over enabling
            // ApiExplorer for conventional-routed controllers when this happens.
            var isVisibleSetOnApplication = application.ApiExplorer?.IsVisible ?? false;

            if (isVisibleSetOnActionOrController && !IsAttributeRouted(actionDescriptor))
            {
                // ApiExplorer is only supported on attribute routed actions.
                throw new InvalidOperationException(Resources.FormatApiExplorer_UnsupportedAction(
                    actionDescriptor.DisplayName));
            }
            else if (isVisibleSetOnApplication && !IsAttributeRouted(actionDescriptor))
            {
                // This is the case where we‘re going to be lenient, just ignore it.
            }
            else if (isVisible)
            {
                Debug.Assert(IsAttributeRouted(actionDescriptor));

                var apiExplorerActionData = new ApiDescriptionActionData()
                {
                    GroupName = action.ApiExplorer?.GroupName ?? controller.ApiExplorer?.GroupName,
                };

                actionDescriptor.SetProperty(apiExplorerActionData);
            }
        }

        private static void AddProperties(
            ControllerActionDescriptor actionDescriptor,
            ActionModel action,
            ControllerModel controller,
            ApplicationModel application)
        {
            foreach (var item in application.Properties)
            {
                actionDescriptor.Properties[item.Key] = item.Value;
            }

            foreach (var item in controller.Properties)
            {
                actionDescriptor.Properties[item.Key] = item.Value;
            }

            foreach (var item in action.Properties)
            {
                actionDescriptor.Properties[item.Key] = item.Value;
            }
        }

        private static void AddActionFilters(
            ControllerActionDescriptor actionDescriptor,
            IEnumerable<IFilterMetadata> actionFilters,
            IEnumerable<IFilterMetadata> controllerFilters,
            IEnumerable<IFilterMetadata> globalFilters)
        {
            actionDescriptor.FilterDescriptors =
                actionFilters.Select(f => new FilterDescriptor(f, FilterScope.Action))
                .Concat(controllerFilters.Select(f => new FilterDescriptor(f, FilterScope.Controller)))
                .Concat(globalFilters.Select(f => new FilterDescriptor(f, FilterScope.Global)))
                .OrderBy(d => d, FilterDescriptorOrderComparer.Comparer)
                .ToList();
        }

        private static void AddActionConstraints(ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel)
        {
            if (selectorModel.ActionConstraints?.Count > 0)
            {
                actionDescriptor.ActionConstraints = new List<IActionConstraintMetadata>(selectorModel.ActionConstraints);
            }
        }

        private static void AddEndpointMetadata(ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel)
        {
            if (selectorModel.EndpointMetadata?.Count > 0)
            {
                actionDescriptor.EndpointMetadata = new List<object>(selectorModel.EndpointMetadata);
            }
        }

        private static void AddAttributeRoute(ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel)
        {
            if (selectorModel.AttributeRouteModel != null)
            {
                actionDescriptor.AttributeRouteInfo = new AttributeRouteInfo
                {
                    Template = selectorModel.AttributeRouteModel.Template,
                    Order = selectorModel.AttributeRouteModel.Order ?? 0,
                    Name = selectorModel.AttributeRouteModel.Name,
                    SuppressLinkGeneration = selectorModel.AttributeRouteModel.SuppressLinkGeneration,
                    SuppressPathMatching = selectorModel.AttributeRouteModel.SuppressPathMatching,
                };
            }
        }

        public static void AddRouteValues(
            ControllerActionDescriptor actionDescriptor,
            ControllerModel controller,
            ActionModel action)
        {
            // Apply all the constraints defined on the action, then controller (for example, [Area])
            // to the actions. Also keep track of all the constraints that require preventing actions
            // without the constraint to match. For example, actions without an [Area] attribute on their
            // controller should not match when a value has been given for area when matching a url or
            // generating a link.
            foreach (var kvp in action.RouteValues)
            {
                // Skip duplicates
                if (!actionDescriptor.RouteValues.ContainsKey(kvp.Key))
                {
                    actionDescriptor.RouteValues.Add(kvp.Key, kvp.Value);
                }
            }

            foreach (var kvp in controller.RouteValues)
            {
                // Skip duplicates - this also means that a value on the action will take precedence
                if (!actionDescriptor.RouteValues.ContainsKey(kvp.Key))
                {
                    actionDescriptor.RouteValues.Add(kvp.Key, kvp.Value);
                }
            }

            // Lastly add the ‘default‘ values
            if (!actionDescriptor.RouteValues.ContainsKey("action"))
            {
                actionDescriptor.RouteValues.Add("action", action.ActionName ?? string.Empty);
            }

            if (!actionDescriptor.RouteValues.ContainsKey("controller"))
            {
                actionDescriptor.RouteValues.Add("controller", controller.ControllerName);
            }
        }

        private static bool IsAttributeRouted(ActionDescriptor actionDescriptor)
        {
            return actionDescriptor.AttributeRouteInfo != null;
        }
    }
public static List<TResult> Flatten<TResult>(
            ApplicationModel application,
            Func<ApplicationModel, ControllerModel, ActionModel, SelectorModel, TResult> flattener)
        {
            var results = new List<TResult>();
            var errors = new Dictionary<MethodInfo, IList<string>>();

            var actionsByMethod = new Dictionary<MethodInfo, List<(ActionModel, SelectorModel)>>();
            var actionsByRouteName = new Dictionary<string, List<(ActionModel, SelectorModel)>>(StringComparer.OrdinalIgnoreCase);

            var routeTemplateErrors = new List<string>();

            foreach (var controller in application.Controllers)
            {
                foreach (var action in controller.Actions)
                {
                    foreach (var selector in ActionAttributeRouteModel.FlattenSelectors(action))
                    {
                        // PostProcess attribute routes so we can observe any errors.
                        ReplaceAttributeRouteTokens(controller, action, selector, routeTemplateErrors);

                        // Add to the data structures we use to find errors.
                        AddActionToMethodInfoMap(actionsByMethod, action, selector);
                        AddActionToRouteNameMap(actionsByRouteName, action, selector);

                        var result = flattener(application, controller, action, selector);
                        Debug.Assert(result != null);

                        results.Add(result);
                    }
                }
            }

            var attributeRoutingConfigurationErrors = new Dictionary<MethodInfo, string>();
            foreach (var (method, actions) in actionsByMethod)
            {
                ValidateActionGroupConfiguration(
                    method,
                    actions,
                    attributeRoutingConfigurationErrors);
            }

            if (attributeRoutingConfigurationErrors.Any())
            {
                var message = CreateAttributeRoutingAggregateErrorMessage(attributeRoutingConfigurationErrors.Values);

                throw new InvalidOperationException(message);
            }

            var namedRoutedErrors = ValidateNamedAttributeRoutedActions(actionsByRouteName);
            if (namedRoutedErrors.Any())
            {
                var message = CreateAttributeRoutingAggregateErrorMessage(namedRoutedErrors);
                throw new InvalidOperationException(message);
            }

            if (routeTemplateErrors.Any())
            {
                var message = CreateAttributeRoutingAggregateErrorMessage(routeTemplateErrors);
                throw new InvalidOperationException(message);
            }

            return results;
        }
internal static class ActionAttributeRouteModel
    {
        public static IEnumerable<SelectorModel> FlattenSelectors(ActionModel actionModel)
        {
            // Loop through all attribute routes defined on the controller.
            // These perform a cross-product with all of the action-level attribute routes.
            var controllerSelectors = actionModel.Controller.Selectors
                .Where(sm => sm.AttributeRouteModel != null)
                .ToList();

            // We also include metadata and action constraints from the controller
            // even when there are no routes, or when an action overrides the route template.
            SelectorModel additionalSelector = null;
            if (actionModel.Controller.Selectors.Count > 0)
            {
                // This logic seems arbitrary but there‘s a good reason for it.
                //
                // When we build the controller level selectors, any metadata or action constraints
                // that aren‘t IRouteTemplateProvider will be included in all selectors. So we
                // pick any selector and then grab all of the stuff that isn‘t IRouteTemplateProvider
                // then we‘ve found all of the items that aren‘t routes.
                //
                // This is fragile wrt application model customizing the data - but no one has
                // run into an issue with this and its pretty esoteric.
                additionalSelector = new SelectorModel(actionModel.Controller.Selectors.First());
                additionalSelector.AttributeRouteModel = null;

                for (var i = additionalSelector.ActionConstraints.Count - 1; i >= 0; i--)
                {
                    if (additionalSelector.ActionConstraints[i] is IRouteTemplateProvider)
                    {
                        additionalSelector.ActionConstraints.RemoveAt(i);
                    }
                }

                for (var i = additionalSelector.EndpointMetadata.Count - 1; i >= 0; i--)
                {
                    if (additionalSelector.EndpointMetadata[i] is IRouteTemplateProvider)
                    {
                        additionalSelector.EndpointMetadata.RemoveAt(i);
                    }
                }
            }

            var actionConstraints = new List<IActionConstraintMetadata>();

            foreach (var actionSelector in actionModel.Selectors)
            {
                var actionRouteModel = actionSelector.AttributeRouteModel;

                // We check the action to see if the template allows combination behavior
                // (It doesn‘t start with / or ~/) so that in the case where we have multiple
                // [Route] attributes on the controller we don‘t end up creating multiple
                if (actionRouteModel != null && actionRouteModel.IsAbsoluteTemplate)
                {
                    // We‘re overriding the routes from the controller, but any *unbound* constraints
                    // still apply.
                    var selector = new SelectorModel(actionSelector);

                    selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    AddActionConstraints(selector, additionalSelector?.ActionConstraints);
                    AddEndpointMetadata(selector, additionalSelector?.EndpointMetadata);

                    yield return selector;
                }
                else if (controllerSelectors.Count > 0)
                {
                    for (var i = 0; i < controllerSelectors.Count; i++)
                    {
                        var controllerSelector = controllerSelectors[i];

                        // We‘re using the attribute routes from the controller
                        var selector = new SelectorModel(actionSelector);

                        selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                            controllerSelector.AttributeRouteModel,
                            actionRouteModel);

                        AddActionConstraints(selector, controllerSelector.ActionConstraints);
                        AddEndpointMetadata(selector, controllerSelector.EndpointMetadata);

                        // No need to include the additional selector here because it would duplicate
                        // data in controllerSelector.

                        yield return selector;
                    }
                }
                else
                {
                    // There are no routes on the controller, but any *unbound* constraints
                    // still apply.
                    var selector = new SelectorModel(actionSelector);

                    selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    AddActionConstraints(selector, additionalSelector?.ActionConstraints);
                    AddEndpointMetadata(selector, additionalSelector?.EndpointMetadata);

                    yield return selector;
                }
            }
        }

        private static void AddActionConstraints(SelectorModel selector, IList<IActionConstraintMetadata> actionConstraints)
        {
            if (actionConstraints != null)
            {
                for (var i = 0; i < actionConstraints.Count;i++)
                {
                    selector.ActionConstraints.Add(actionConstraints[i]);
                }
            }
        }

        private static void AddEndpointMetadata(SelectorModel selector, IList<object> controllerMetadata)
        {
            if (controllerMetadata != null)
            {
                // It is criticial to get the order in which metadata appears in endpoint metadata correct. More significant metadata
                // must appear later in the sequence. In this case, the values in `controllerMetadata` should have their order
                // preserved, but appear earlier than the entries in `selector.EndpointMetadata`.
                for (var i = 0; i < controllerMetadata.Count; i++)
                {
                    selector.EndpointMetadata.Insert(i, controllerMetadata[i]);
                }
            }
        }

        public static IEnumerable<(AttributeRouteModel route, SelectorModel actionSelector, SelectorModel controllerSelector)> GetAttributeRoutes(ActionModel actionModel)
        {
            var controllerAttributeRoutes = actionModel.Controller.Selectors
                .Where(sm => sm.AttributeRouteModel != null)
                .Select(sm => sm.AttributeRouteModel)
                .ToList();

            foreach (var actionSelectorModel in actionModel.Selectors)
            {
                var actionRouteModel = actionSelectorModel.AttributeRouteModel;

                // We check the action to see if the template allows combination behavior
                // (It doesn‘t start with / or ~/) so that in the case where we have multiple
                // [Route] attributes on the controller we don‘t end up creating multiple
                if (actionRouteModel != null && actionRouteModel.IsAbsoluteTemplate)
                {
                    var route = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    yield return (route, actionSelectorModel, null);
                }
                else if (controllerAttributeRoutes.Count > 0)
                {
                    for (var i = 0; i < actionModel.Controller.Selectors.Count; i++)
                    {
                        // We‘re using the attribute routes from the controller
                        var controllerSelector = actionModel.Controller.Selectors[i];

                        var route = AttributeRouteModel.CombineAttributeRouteModel(
                            controllerSelector.AttributeRouteModel,
                            actionRouteModel);

                        yield return (route, actionSelectorModel, controllerSelector);
                    }
                }

                else
                {
                    var route = AttributeRouteModel.CombineAttributeRouteModel(
                        left: null,
                        right: actionRouteModel);

                    yield return (route, actionSelectorModel, null);
                }
            }
        }
    }

原文地址:https://www.cnblogs.com/lanpingwang/p/12642807.html

时间: 2024-10-12 17:17:38

asp.net core mvc 3.1 源码分析(五)的相关文章

asp.net core mvc 3.1 源码分析(一)

我们先看下IApplicationBuilder接口的扩展方法UseMvc public static IApplicationBuilder UseMvc( this IApplicationBuilder app, Action<IRouteBuilder> configureRoutes) { if (app == null) { throw new ArgumentNullException(nameof(app)); } if (configureRoutes == null) {

asp.net core mvc 3.1 源码分析(四)

AuthorizationApplicationModelProvider 该类主要添加授权认证的过滤器 先在Controller和Action中找到实现IAuthorizeData的特性,再根据IAuthorizeData创建AuthorizeFilter过滤器,把AuthorizeFilter添加到Controller和Action的Filters列表中 具体的授权逻辑后面分开讲 internal class AuthorizationApplicationModelProvider : I

各类最新Asp .Net Core 项目和示例源码

1.网站地址:http://www.freeboygirl.com2.网站Asp .Net Core 资料http://www.freeboygirl.com/blog/tag/asp%20net%20core3.各类最新Asp .Net Core 项目和示例源码? github.com/freeboygirl 4.微信公众号:AspNetCore 5.直接在微信公众号发消息即可.

Nouveau源码分析(五):NVIDIA设备初始化之nouveau_drm_load (2)

Nouveau源码分析(五) 接着上一篇来,先把nouveau_drm_load再贴出一遍来吧: // /drivers/gpu/drm/nouveau/nouveau_drm.c 364 static int 365 nouveau_drm_load(struct drm_device *dev, unsigned long flags) 366 { 367 struct pci_dev *pdev = dev->pdev; 368 struct nouveau_drm *drm; 369 i

baksmali和smali源码分析(五)

官方文档对于dex中的class数据结构表示如下: class_idx uint index into the type_ids list for this class. This must be a class type, and not an array or primitive type. access_flags uint access flags for the class (public, final, etc.). See "access_flags Definitions&quo

[Android] Volley源码分析(五)答疑

Volley源码分析系列出了有一段日子了,有不少看官私底下给我留言,同时抛出了一些问题.对于一些比较简单的问题我们跳过去,这两天接到网友是@smali提出的问题.不得不赞一下这位看官看源码时候的细腻程度,我引出这个问题供大家一块思考一下. Q:在写入文件头数据的时候为何不直接写入Int而是通过移位的方式来完成? 我们来看一下对应的源码: writeInt(os, CACHE_MAGIC); static void writeInt(OutputStream os, int n) throws I

Spring MVC初始化部分源码分析

首先定位到org.springframework.context.support.AbstractApplicationContext中的refresh()方法: public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh

Vue系列---理解Vue.nextTick使用及源码分析(五)

_ 阅读目录 一. 什么是Vue.nextTick()? 二. Vue.nextTick()方法的应用场景有哪些? 2.1 更改数据后,进行节点DOM操作. 2.2 在created生命周期中进行DOM操作. 三. Vue.nextTick的调用方式如下: 四:vm.$nextTick 与 setTimeout 的区别是什么? 五:理解 MutationObserver 六:nextTick源码分析 回到顶部 一. 什么是Vue.nextTick()? 官方文档解释为:在下次DOM更新循环结束之

MPTCP 源码分析(五) 接收端窗口值

简述: 在TCP协议中影响数据发送的三个因素分别为:发送端窗口值.接收端窗口值和拥塞窗口值. 本文主要分析MPTCP中各个子路径对接收端窗口值rcv_wnd的处理. 接收端窗口值的初始化 根据<MPTCP 源码分析(二) 建立子路径>中描述服务端在发送完SYN/ACK并接收到ACK的时候建立新的sock. 在内核实现中,针对连接请求分为两个步骤处理: SYN队列处理:当服务端收到SYN的时候,此连接请求request_sock将被存放于listening socket的SYN队列,服务端发送S