一、概述

路由主要有两个主要功能:

1、将请求的URL与已定义的路由进行匹配,找到该URL对应的处理程序并传入该请求进行处理。

2、根据已定义的路由生成URL

这两个功能看起来这两个是相反的。

A.路由的配置

路由的两个功能都离不开一个基本的操作:路由的基本配置。在Startup中默认通过 routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}")定义,

当然我们还可以继续 routes.MapRoute(。。。);  这样就定义了一系列的路由匹配方式组成一个路由表,例如这样:

app.UseMvc(routes =>
{
routes.MapRoute(name: "test", template: "Hello");
routes.MapRoute("flylolo/{code}/{name}", MyRouteHandler.Handler);
routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
});

每一个MapRoute会生成一个Route,第二个MapRoute看起来有些特殊,我们可以传入一个自定义的RequestDelegate(本例为MyRouteHandler.Handler)来处理“flylolo/{code}/{name}”这样的请求,

    public static class MyRouteHandler
{
public static async Task Handler(HttpContext context)
{
await context.Response.WriteAsync("MyRouteHandler");
}
}

它会被封装成一个RouteHandler(new RouteHandler(MyRouteHandler.Handler))赋值给Route的target属性,而对于另外两种没有指定的,Route的target属性默认会被指定为MvcRouteHandler ,如下图:

B.Handler的选择

当请求进入之后,根据此路由表对该URL进行逐一匹配,并将请求交给匹配到的路由的target(即MvcRouteHandler或RouteHandler),调用_target.RouteAsync(context); ,在这个方法中,若是MvcRouteHandler会对请求的Controller和Action验证,若验证成功,则对context(是一个RouteContext)的Handler属性赋值一个匿名方法;若是RouteHandler则会直接将其封装的RequestDelegate(本例为MyRouteHandler.Handler)赋值给RouteContext.Handler.

C.请求处理

经过Handler的选择后,若RouteContext.Handler不为空,则调用RouteContext.Handler(HttpContext)对请求进行处理。

D.其他

回想一下中间件,这个是不是和app.Map("/test", XXHandle)这样配置中间件的方式有点像,当请求路径是/test的时候,请求交由XXHandle处理,同样是Map,对比着更容易理解。

下面通过一张图看一下路由配置和请求处理的流程。

二、流程及解析

为了方便查看,对几个“重点对象”做了颜色标识(点击图片可以看大图):

1、路由的初始化配置

一切从Startup开始,之前在中间件的文章中介绍过,一般是通过多个UseXXX的方式将多个中间件组成“请求处理管道”,而在这里通过UseMvc方法进行配置,传入routes.MapRoute(...)这样的一个或多个配置。接下来会New一个RouteBuilder,顾名思义就是一个Route的创建者,通过调用传进来的一个或多个routes.MapRoute()方法生成多个Route,并配置默认的Handler。

                var routes = new RouteBuilder(app)
{
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
}; configureRoutes(routes);//调用Startup中的routes.MapRoute(...)方法

①调用RouteBuilder的Build方法,生成一个RouteCollection。

        public IRouter Build()
{
var routeCollection = new RouteCollection(); foreach (var route in Routes)
{
routeCollection.Add(route);
} return routeCollection;
}

②RouteCollection实现IRouteCollection和IRouter接口,他是在Startup中的配置组成的集合。

③RouterMiddleWare就是专门用于进行路由处理的中间件,在此将RouteCollection作为中间件RouterMiddleWare的参数,并将这个中间件插入管道中。

    public class RouterMiddleware
{
private readonly IRouter _router; //就是RouteCollection public async Task Invoke(HttpContext httpContext); }

2. 请求处理流程

        ④请求的处理流程在RouterMiddleWare的invoke()方法中。

     ⑤请求首先会被封装成一个RouteContext,本质就是将httpContext、_router(也就是RouteCollection)包装到一个对象里。

  var context = new RouteContext(httpContext);
context.RouteData.Routers.Add(_router);
public class RouteContext
{
private RouteData _routeData;
public RequestDelegate Handler ;
public HttpContext HttpContext;//简单的赋值
public RouteData RouteData;
}

⑥调用_router(也就是RouteCollection)的RouteAsync(context)方法,在其中遍历每一个路由

⑦若与请求URL匹配,则将对应的Handler赋值给context.Handler。

        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
{
await route.RouteAsync(context);//若匹配,则给context.Handler赋值 if (context.Handler != null)
{
break;
}
}
finally
{
if (context.Handler == null)
{
snapshot.Restore();//通过快照还原
}
}
}
}

⑧在RouterMiddleWare的invoke()方法中,调用新赋值的context.Handler处理HttpContext;

httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature()
{
RouteData = context.RouteData,
}; await context.Handler(context.HttpContext);

Net core学习系列(六)——Net Core路由的更多相关文章

  1. 【.Net Core 学习系列】-- EF Core 实践(Code First)

    一.开发环境: VS2015, .Net Core 1.0.0-preview2-003156 二解决方案: 新建项目: File --> New --> Project -->   ...

  2. 【.Net Core 学习系列】-- EF Core实践(DB First)

    一.开发环境: VS2015, .Net Core 1.0.0-preview2-003156 二.准备数据: CREATE DATABASE [Blogging]; GO USE [Blogging ...

  3. EntityFramework Core 学习系列(一)Creating Model

    EntityFramework Core 学习系列(一)Creating Model Getting Started 使用Command Line 来添加 Package  dotnet add pa ...

  4. ASP.NET Core学习系列

    .NET Core ASP.NET Core ASP.NET Core学习之一 入门简介 ASP.NET Core学习之二 菜鸟踩坑 ASP.NET Core学习之三 NLog日志 ASP.NET C ...

  5. Net core学习系列(一)——Net Core介绍

    一.什么是Net Core .NET Core是适用于 windows.linux 和 macos 操作系统的免费.开源托管的计算机软件框架,是微软开发的第一个官方版本,具有跨平台 (Windows. ...

  6. Net core学习系列(八)——Net Core日志

    一.简介# 日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息.ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如 Conso ...

  7. Net core学习系列(二)——Net Core项目文件简介

    一. ASP.NET Core 项目文件夹解读 ASP.NET Core 1.0 发布以来,相较于传统项目编码发布的行为,新项目中的操作已经有了很大的变化,如解析依赖,选择运行平台和Runtime等等 ...

  8. Net core学习系列(十)——Net Core配置

    一.前言 选项(Options)模式是对配置(Configuration)的功能的延伸.在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定到实体类.绑定至对 ...

  9. Net core学习系列(七)——Net Core中间件

    一.什么是中间件(Middleware)? 中间件是组装到应用程序管道中以处理请求和响应的软件. 每个组件: 选择是否将请求传递给管道中的下一个组件. 可以在调用管道中的下一个组件之前和之后执行工作. ...

随机推荐

  1. Python人工智能第二篇:人脸检测和图像识别

    Python人工智能第二篇:人脸检测和图像识别 人脸检测 详细内容请看技术文档:https://ai.baidu.com/docs#/Face-Python-SDK/top from aip impo ...

  2. webpack+vue-cil跨域配置接口地址代理

    在vue项目开发的时候,接口联调的时候一般都是同域名下,且不存在跨域的情况下进行接口联调,但是当我们现在使用vue-cli进行项目打包的时候,我们在本地启动服务器后,比如本地开发服务下是 http:/ ...

  3. php通过curl发送XML数据,并获取XML数据

    php编程中经常会用到用xml格式传送数据,如调用微信等第三方接口经常用到,这里演示下php以curl形式发送xml,并通过服务器接收 一.发送xml数据 -- postXml.php <?ph ...

  4. slf4j的正确使用

    头两天领导分配个任务是要把项目中所有try catch里的异常处理收集到elk中,由于之前的处理方式五花八门,就集中处理了下, 事后还被批评了. 不是所有的异常信息都需要被记录到log中 使用SLF4 ...

  5. Openlayers学习开始前序

    Openlayers将抽象事物具体化为类,其核心类是Map.Layers.Source.View,几乎所有的动作都是围绕这几个核心类展开.Map的实例就是内嵌于网页的交互式地图,因此,最关键的是Map ...

  6. java requestmapping中关于路径的问题

    需要这种url写的方式才能映射

  7. myEclipse项目部署点击Finish按钮没反应

    -- 问题描述:myEclipse项目部署点击Finish按钮没反应. -- 问题原因:Tomcat没有不熟JDK. -- 解决办法:window->preferences->servic ...

  8. golang版本管理工具GO111MODULE

    在go1.11版本前,想要对go语言包进行管理,只能依赖第三方库实现,比如Vendor,GoVendor,GoDep,Dep,Glide等等. 1. 开启GO111MODULE 用环境变量 GO111 ...

  9. requests+unittest+ddt+xlrd+pymysql+BeautifulReport数据驱动

    # ddcapitestpython XXX接口自动化测试 # 一.数据驱动的思路 1.采用requests+unittest+ddt+xlrd+pymysql+BeautifulReport 2.r ...

  10. 倍增法求lca(最近公共祖先)

    倍增法求lca(最近公共祖先) 基本上每篇博客都会有参考文章,一是弥补不足,二是这本身也是我学习过程中找到的觉得好的资料 思路: 大致上算法的思路是这样发展来的. 想到求两个结点的最小公共祖先,我们可 ...