asp.net core mvc剖析:路由

xiaoxiao2021-02-27  342

在mvc框架中,任何一个动作请求都会被映射到具体控制器中的方法上,那框架是如何完成这样一个过程的,现在我们就来简单分析下流程。

我们紧跟上面的主题,任何一个请求都会交给处理管道进行处理,那mvc处理的流程自然也应该处于这个管道中,在startup.cs文件的Configure方法中,我们会看到这样的代码

1 2 3 4 5 6 7 app.UseMvc(routes =>              {                  routes.MapRoute(                      name:  "default" ,                      template:  "{controller=Home}/{action=Index}/{id?}" ,                      defaults:  new  { area =  "admin"  });              });

  这部分代码的作用我们都清楚,就是配置路由规则,把用户的请求,路由到控制器方法上,我们来看它里面怎么做到的。首先看下UseMvc方法,直接上代码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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());          }

  

  我们来看下Build方法代码:

1 2 3 4 5 6 7 8 9 10 11 12 public  IRouter Build()          {              //创建一个路由规则集合              var  routeCollection =  new  RouteCollection();              //把配置的路由规则加入到集合中,这个Routes就是上面configureRoutes(routes)配置的              foreach  ( var  route  in  Routes)              {                  routeCollection.Add(route);              }                            return  routeCollection;          }

  

  configureRoutes中,通过MapRoute方法注册规则,我们看一下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  static  IRouteBuilder MapRoute(              this  IRouteBuilder routeBuilder,              string  name,              string  template,              object  defaults,              object  constraints,              object  dataTokens)          {              if  (routeBuilder.DefaultHandler ==  null )              {                  throw  new  RouteCreationException(Resources.FormatDefaultHandler_MustBeSet(nameof(IRouteBuilder)));              }              var  inlineConstraintResolver = routeBuilder                  .ServiceProvider                  .GetRequiredService<IInlineConstraintResolver>();              //new了一个Route对象,把这个对象加入到routeBuilder.Routes集合中              routeBuilder.Routes.Add( new  Route(                  routeBuilder.DefaultHandler,                  name,                  template,                  new  RouteValueDictionary(defaults),                  new  RouteValueDictionary(constraints),                  new  RouteValueDictionary(dataTokens),                  inlineConstraintResolver));              return  routeBuilder;          }

  路由规则配置好了,当用户请求过来后,又是如何进行匹配的?上面我们提到了RouterMiddleware中间件,用户请求会通过这个中间件进行处理,这个中间件Invoke方法的代码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public  async Task Invoke(HttpContext httpContext)          {              var  context =  new  RouteContext(httpContext);              //这句目前没有搞清楚作用是什么              context.RouteData.Routers.Add(_router);              //_router就是我们上面通过Build方法创建的,它就是RouteCollection              await _router.RouteAsync(context);              //判断是否找到了匹配的规则,这里的Handler只有当规则匹配了,才会赋值,Handler是什么?留一个疑问              if  (context.Handler ==  null )              {                  _logger.RequestDidNotMatchRoutes();                  //如果没有任何路由符合要求,直接执行下一个中间件                  await _next.Invoke(httpContext);              }              else              {                  httpContext.Features[ typeof (IRoutingFeature)] =  new  RoutingFeature()                  {                      RouteData = context.RouteData,                  };                  //使用Handler处理请求                  await context.Handler(context.HttpContext);              }          }

  

  下面来看RouteCollection的RouteAsync方法实现:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  async  virtual  Task RouteAsync(RouteContext context)          {              var  snapshot = context.RouteData.PushState( null , values:  null , dataTokens:  null );         //循环所有的路由规则配置              for  ( var  i = 0; i < Count; i++)              {                  var  route =  this [i];                  context.RouteData.Routers.Add(route);                  try                  {                      //调用Route对象的RouteAsync方法,匹配规则                      await route.RouteAsync(context);                      //规则匹配成功,直接break                      if  (context.Handler !=  null )                      {                          break ;                      }                  }                  finally                  {                      if  (context.Handler ==  null )                      {                          snapshot.Restore();                      }                  }              }          }

  

  具体匹配方式不再介绍了,就是根据请求的路径跟设置的地址规则进行对比,我们只看匹配成功后,做了什么?

1 2 3 4 5 6 protected  override  Task OnRouteMatched(RouteContext context) {              context.RouteData.Routers.Add(_target);         //_target是routeBuilder.DefaultHandler,这个是在上面创建routeBuilder时设置的,是一个MvcRouteHandler         return  _target.RouteAsync(context); }

  

  在MvcRouteHandler里完成了context.Handler的设置,下面是这个Handler的具体代码:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 context.Handler = (c) =>              {                  var  routeData = c.GetRouteData();                  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));                  }                  //完成动作执行                  return  invoker.InvokeAsync();              };

  上面调用过程如下图:

  后面再详细介绍mvc具体执行过程。

  

转载请注明原文地址: https://www.6miu.com/read-1880.html

最新回复(0)