一个 http 请求过来后,首先经过路由规则的匹配,找到最符合条件的的 IRouter,然后调用 IRouter.RouteAsync 来设置 RouteContext.Handler,最后把请求交给 RouteContext.Handler 来处理。在 MVC 中提供了两个 IRouter 实现,分别如下:
1,MvcAttributeRouteHandler
2,MvcRouteHandler
我们再来看一下 UseMvc 的实现逻辑
- public static IApplicationBuilder UseMvc(
- this IApplicationBuilder app,
- Action<IRouteBuilder> configureRoutes)
- {
- 。。。。。。
- //实例化路由构造器
- var routes = new RouteBuilder(app)
- {
- //设置默认处理器,就是路由符合条件时使用MvcRouteHandler来处理请求
- DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
- };
- //配置路由规则
- configureRoutes(routes);
- //这句很重要,上面配置的全局的路由规则,我们同样可以在控制器或者控制器方法上使用RouteAttribute配置路由规则,这些规则会优先采用
- routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));
- //routes.Build方法生成IRouter对象,一会我们在看具体细节,然后通过UseRouter注册一个RouterMiddleware中间件
- return app.UseRouter(routes.Build());
- }
上面的 configureRoutes(routes) 语句注册 Route 关联上了 MvcRouteHandler,而 routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices)) 注册 AttributeRoute 关联上了 MvcAttributeRouteHandler,并且后者优先被匹配选择。
在这两个 RouterHanlder 里做的一个最重要的工作就是进行动作选择,以 MvcRouterHandler 为例,代码如下:
- 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;
- }
在这里面借助一个 ActionSelector 来根据路由数据进行动作选择,得到符合要求的 ActionDescriptor。ActionDescriptor 是什么?它是一个动作的描述类,包含动作名称,约束条件等。它是如何得到的?
我们从 IActionSelector.SelectCandidates 开始进行跟踪,并根据 MvcCoreServiceCollectionExtensions 提供的 AddMvcCoreServices 的依赖注入配置,我们不难得到下面的调用关系:
在 DefaultApplicationModelProvider.OnProvidersExecuting 方法中通过反射方式解析程序集中的类信息。我们分析下控制器类分析的代码,这部分代码在 CreateControllerModel 方法中
- protected virtual ControllerModel CreateControllerModel(TypeInfo typeInfo)
- {
- 。。。。。。
- //获取RouteAttribute特性信息,这里是采用循环的方式,直到找到第一个定义了IRouteTemplateProvider特性的类为止,所以如果子类没有配置RouteAttribute,就会采用父类的配置
- 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>());
- //获取路由规则数据,要求请求时某个路由数据必须等于设置的值,比如在控制器上设置[Area("test")],那只有当路由数据中包含了area且值等于test才用当前这个动作处理,当然大家可以自定义一些限制
- 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
得到最终的 ApplicationModel 后,再有 ControllerActionDescriptorBuilder.Build(applicationModel) 生成对应的 ControllerActionDescriptor 集合。
再回到 ActionSelector.SelectCandidates 方法,在这个方法里面通过调用 ActionSelectionDecisionTree.Select 方法来选择符合要求的 ActionDescriptor,实现代码如下:
- 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 生成的一个查找树。
DecisionTreeNode 定义如下:
- internal class DecisionTreeNode < TItem > {
- //符合条件的ActionDescriptor集合
- public IList < TItem > Matches {
- get;
- set;
- }
- // 分支规则
- public IList < DecisionCriterion < TItem >> Criteria {
- get;
- set;
- }
- }
一个分支规则定义如下:
- internal class DecisionCriterion < TItem > {
- public string Key {
- get;
- set;
- }
- public Dictionary < object,
- DecisionTreeNode < TItem >> Branches {
- get;
- set;
- }
- }
查找逻辑:
1,判断当前结点上是否存在 Matches,如果存在放到查找结果集里。
2,循环分支规则,获取分支规则 key,按照 key 从路由数据中获取对应 key 的值,在通过这个值从 Branches 字典中查找对应 DecisionTreeNode<TItem>
3,在分支 Node 上执行 1,2 步
4,返回最后的查找结果
通过上面的步骤会得到所有符合要求的 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();
- };
在 Hander 中,根据查找到的 ActionDescriptor 实例化 ActionContext, 然后通过 ActionInvokerFactory 创建 invoker,通过 invoker 执行 ActionDescriptor 对应的动作,并返回结果。
先到这里,下面再继续介绍 Invoker 相关内容。
来源: http://www.cnblogs.com/dxp909/p/6535791.html