前面介绍了路由的过程,我们再来看下 MvcRouteHandler 的代码:
- public Task RouteAsync(RouteContext context)
- {
- 。。。。。。
- //根据路由信息查找符合要求的ActionDescriptor集合
- var candidates = _actionSelector.SelectCandidates(context);
- if (candidates == null || candidates.Count == 0)
- {
- _logger.NoActionsMatched(context.RouteData.Values);
- return TaskCache.CompletedTask;
- }
- //按照约束规则选择最符合要求的一个ActionDescriptor
- var actionDescriptor = _actionSelector.SelectBestCandidate(context, candidates);
- if (actionDescriptor == null)
- {
- _logger.NoActionsMatched(context.RouteData.Values);
- return TaskCache.CompletedTask;
- }
- context.Handler = (c) =>
- {
- var routeData = c.GetRouteData();
- var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
- if (_actionContextAccessor != null)
- {
- _actionContextAccessor.ActionContext = actionContext;
- }
- var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
- if (invoker == null)
- {
- throw new InvalidOperationException(
- Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
- actionDescriptor.DisplayName));
- }
- return invoker.InvokeAsync();
- };
- return TaskCache.CompletedTask;
- }
在详细介绍 ActionDescriptor 查找逻辑前,我们得先来看下 ActionDescriptor 是什么,它是如何得到的?
我们从 IActionSelector.SelectCandidates 开始进行跟踪,并根据 MvcCoreServiceCollectionExtensions 提供的 AddMvcCoreServices 的依赖注入配置,我们不难得到下面的调用关系:
在 DefaultApplicationModelProvider.OnProvidersExecuting 方法中通过反射方式解析程序集中的类信息。
- protected virtual ControllerModel CreateControllerModel(TypeInfo typeInfo)
- {
- 。。。。。。
- //获取RouteAttribute特性信息,这里是采用循环的方式,直到找到第一个定义了IRouteTemplateProvider特性的类为止
- IRouteTemplateProvider[] routeAttributes = null;
- 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);
- 。。。。。。
- var controllerModel = new ControllerModel(typeInfo, attributes);
- //创建Selectors,这个要在查找ActionDescriptor时使用
- AddRange(controllerModel.Selectors, CreateSelectors(attributes));
- //获取控制器名称
- controllerModel.ControllerName =
- typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ?
- typeInfo.Name.Substring(0, typeInfo.Name.Length - "Controller".Length) :
- typeInfo.Name;
- //把过滤器特性加入到Filters集合中
- AddRange(controllerModel.Filters, attributes.OfType<IFilterMetadata>());
- //获取路由规则数据,要求请求时某个路由数据必须等于设置的值
- foreach (var routeValueProvider in attributes.OfType<IRouteValueProvider>())
- {
- controllerModel.RouteValues.Add(routeValueProvider.RouteKey, routeValueProvider.RouteValue);
- }
- //api相关配置
- 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;
- }
- // 分析控制器是否实现了动作过滤器和结果过滤器接口,如果我们需要对一个控制器实现一个特殊的动作过滤器或结果过滤器,就不用再单独创建过滤器特性类了,直接让控制器实现接口即可,这个很方便
- 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;
- }
上面的方法结束后,就得到了一个 ControllerModel 对象,CreateActionModel 方法是创建 ActionModel 对象,分析过程基本跟 CreateControllerModel 方法类似,就不再介绍,结果分析后,最后得到了下面的层次关系对象:
ApplicationModel->ControllerModel->ActionModel
再回到 ActionSelector.SelectCandidates 方法,在这里面调用 ActionSelectionDecisionTree.Select 方法,代码如下:
- public IReadOnlyList<ActionDescriptor> Select(IDictionary<string, object> routeValues)
- {
- var results = new List<ActionDescriptor>();
- Walk(results, routeValues, _root);
- return results;
- }
_root 是一个 DecisionTreeNode<ActionDescriptor> 类型,它是通过 DecisionTreeBuilder<ActionDescriptor>.GenerateTree 生成的一个查找树。DecisionTreeBuilder 类位于 Route 应用程序中。通过查看 DecisionBuilder 的代码,我们发现在 GenerateTree 时需要一个 IClassifier,在 mvc 框架中的实现是 ActionDescriptorClassifier,GetCriteria 方法中就是循环 RouteValue 生成对应的 IDictionary<string, DecisionCriterionValue>,这个在生成查找树时,会作为树的分支存在,大家可以查看 DecisionTreeBuilder<TItem>.GenerateTree 就会理解。
查找树有了,ActionSelector.SelectCandidates 就使用这个树根据当前请求的路由数据在树上进行匹配,会得到所有符合要求的 ActionDescriptor,然后调用 SelectBestCandidate 获取最符合条件的 ActionDescriptor,如果最后查找到的 ActionDescriptor 不是一个,则报 AmbiguousActionException 异常。
继续 MvcRouteHandler,在查找到 ActionDescriptor 之后,就设置 context.Handler
- context.Handler = (c) =>
- {
- var routeData = c.GetRouteData();
- //根据actiondescriptor实例化ActionContext对象
- var actionContext = new ActionContext(context.HttpContext, routeData, actionDescriptor);
- if (_actionContextAccessor != null)
- {
- _actionContextAccessor.ActionContext = actionContext;
- }
- //创建IActionInvoker
- var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
- if (invoker == null)
- {
- throw new InvalidOperationException(
- Resources.FormatActionInvokerFactory_CouldNotCreateInvoker(
- actionDescriptor.DisplayName));
- }
- //执行invoker处理请求
- return invoker.InvokeAsync();
- };
先到这里,下篇文章,继续分析 invoker 之后做了什么。
来源: http://www.cnblogs.com/dxp909/p/6423854.html