asp.net core mvc剖析:路由

在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具体执行过程。

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值