• asp.net core mvc剖析:路由


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

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

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

      这部分代码的作用我们都清楚,就是配置路由规则,把用户的请求,路由到控制器方法上,我们来看它里面怎么做到的。首先看下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());
            }
    

      

      我们来看下Build方法代码:

    public IRouter Build()
            {
                //创建一个路由规则集合
                var routeCollection = new RouteCollection();
                //把配置的路由规则加入到集合中,这个Routes就是上面configureRoutes(routes)配置的
                foreach (var route in Routes)
                {
                    routeCollection.Add(route);
                }
                
                return routeCollection;
            }
    

      

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

    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方法的代码:

    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方法实现:

    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();
                        }
                    }
                }
            }
    

      

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

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

      

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

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

      

  • 相关阅读:
    搜索能力
    sublimetext中文论坛
    Sublime Text添加插入带当前时间说明
    X86平台简称
    centos 下如何加入sudo 用户
    Git Shell 安装版本
    Git 使用教程
    CentOS 下安装配置mongodb
    Mysql 解决left join 数据重复的问题
    CentOS 下安装翻译软件星际译 StarDict
  • 原文地址:https://www.cnblogs.com/dxp909/p/6413679.html
Copyright © 2020-2023  润新知