开始

回顾上一篇文章:dotnet core开发体验之开始MVC 里面体验了一把mvc,然后我们知道了aspnet mvc是靠Routing来驱动起来的,所以感觉需要研究一下Routing是什么鬼。

Routing简单使用体验

首先我们用命令yo aspnet创建一个新的空web项目。(Yeoman的使用自己研究,参考:https://docs.asp.net/en/latest/client-side/yeoman.html?#building-projects-with-yeoman)

创建完项目后,在project.json里面添加Routing依赖。

"dependencies": {
...
"Microsoft.AspNetCore.Routing": "1.0.0-*"
},

添加完依赖后,修改Startup里面的Configure,和ConfigureServices里面添加Routing的使用依赖

修改前:

public void Configure(IApplicationBuilder app)
{
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}

修改后:

public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
} public void Configure(IApplicationBuilder app)
{
var endpoint = new RouteHandler((c) => c.Response.WriteAsync("Hello, I am Routing!")); app.UseRouter(endpoint);
}

dotnet run 然后浏览器访问http://localhost:5000/ 显示为Hello, I am Routing! 接下来我们在http://localhost:5000/ 后面加入一些其他的东西来访问,发现其实还是一样打印Hello, I am Routing! 这让我们感觉好像并没有什么卵用的样子。不着急我们先来看看Routing是怎么运行起来的。在开始这话题之前需要先了解到什么是中间件,参考:https://docs.asp.net/en/latest/fundamentals/middleware.html

Routing的最基本运行原理

Routing的驱动入口就是基于middleware的。可以先看看 app.UseRouter(endpoint)的内部实现,参考一个扩展方法类RoutingBuilderExtensions,可以看到最后有一句代码return builder.UseMiddleware<RouterMiddleware>(router) 。这里可以很明显看到,入口在RouterMiddleware的Invoke方法。

    public async Task Invoke(HttpContext httpContext)
{
var context = new RouteContext(httpContext);
context.RouteData.Routers.Add(_router); await _router.RouteAsync(context); if (context.Handler == null)
{
_logger.RequestDidNotMatchRoutes();
await _next.Invoke(httpContext);
}
else
{
httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature()
{
RouteData = context.RouteData,
}; await context.Handler(context.HttpContext);
}
}

这个入口的实现是这样的:

Invoke入口 ===>>> 实例化一个 RouteContext ===>>> 把我们传进来的 IRouter 存到 RouteContext里面的 RouteData =>>> 再执行IRouter的RouteAsync方法把RouteContext对象传进去提供给具体实现使用。=>>> 如果context.Handler没有东西,就执行下一个RequestDelegate,如果有的话就把RouteData保存起来然后执行这个RequestDelegate。

看到了这里我们已经可以明白下面这个代码运行起来的原理。

public void Configure(IApplicationBuilder app)
{
var endpoint = new RouteHandler((c) => c.Response.WriteAsync("Hello, I am Routing!")); app.UseRouter(endpoint);
}

可能还会有人不明白RouteHandler是个什么鬼,既然我们知道了代码的实现运行原理,那么肯定可以猜到RouteHandler是有实现接口IRouter的。我们可以看RouteHandler代码

    public Task RouteAsync(RouteContext context)
{
context.Handler = _requestDelegate;
return TaskCache.CompletedTask;
}

这里可以看到把我们的(c) => c.Response.WriteAsync("Hello, I am Routing!")赋值给context.Handler,然后由RouterMiddleware来执行我们这个事件方法。于是我们就可以在浏览器上面看到输出 Hello, I am Routing!这么一句话了。

Routing的一些使用

文章到现在,我们虽然知道了Routing运行起来的一个大概原理,但是我们一直打印出相同内容,确实也没有什么卵用呀。我们要改一下让打印内容能有点改变。这个时候可以使用到Routing提供的Route类来使用。代码修改如下:

    public void Configure(IApplicationBuilder app)
{
var endpoint = new RouteHandler((c) => c.Response.WriteAsync($"Hello, I am Routing! your item is {c.GetRouteValue("item")}"));
var resolver = app.ApplicationServices.GetRequiredService<IInlineConstraintResolver>();
var runRoute = new Route(endpoint,"{item}",resolver); app.UseRouter(runRoute);
}

修改完代码后,我们再次编译运行,然后输入http://localhost:5000/ 我们发现一片空白,然后再输入http://localhost:5000/abc 发现打印出来的是Hello, I am Routing! your item is abc。然后再输入其他的 http://localhost:5000/abc/cc 发现也是一片空白。这是因为我们给路由添加的匹配是主机地址/+{item}那其他的路径都是匹配不到,那么肯定就是不会显示任何东西啦。假设我们要给一个默认值,那么可以改成这样

var runRoute = new Route(endpoint,"{item=home}",resolver);

OK,这个时候我们再输入http://localhost:5000/ 看到的就是Hello, I am Routing! your item is home。

匹配原理相对比较复杂点,想要了解的话可以参考 RouteBase的源码,然后看相关的类,看看我们设置的模板是如何解析的,然后如何和url进行匹配的。如果要要来解释完整个过程的话,这个文章肯定是不够的,所以各位可以自己了解一下。

假如要配置多个路由支持的话,可以使用RouteCollection

    public void Configure(IApplicationBuilder app)
{
var endpoint = new RouteHandler((c) => c.Response.WriteAsync($"Hello, I am Routing! your item is {c.GetRouteValue("item")}"));
var resolver = app.ApplicationServices.GetRequiredService<IInlineConstraintResolver>();
var runRoute = new Route(endpoint,"{item=home}",resolver);
var otherRoute = new Route(endpoint,"other/{item=other_home}",resolver); var routeCollection = new RouteCollection();
routeCollection.Add(runRoute);
routeCollection.Add(otherRoute); app.UseRouter(routeCollection);
}

修改成上面的代码后就支持两个路由,假如输入的url是 http://localhost:5000/other 那么就是使用runRoute,如果输入的是http://localhost:5000/other/myother 那么使用的就是otherRoute。

这样书写暴露了很多细节东西,我们可以用 Routing提供的RouteBuilder类来编写相同的东西。代码修改一下如下:

public void Configure(IApplicationBuilder app)
{
var endpoint = new RouteHandler((c) => c.Response.WriteAsync($"Hello, I am Routing! your item is {c.GetRouteValue("item")}")); var routeBuilder = new RouteBuilder(app)
{
DefaultHandler = endpoint,
}; routeBuilder.MapRoute("default","{item=home}");
routeBuilder.MapRoute("other","other/{item=other_home}"); app.UseRouter(routeBuilder.Build());
}

如果有一些特殊的的路由配置,我们也可以使用routeBuilder.Routes.Add(route);这代码来添加。至于能配置的模板都有些什么,可以看 Routing 的 Template 的测试类:https://github.com/aspnet/Routing/tree/dev/test/Microsoft.AspNetCore.Routing.Tests/Template 看完基本就知道都有些什么样的模板格式可以使用了。

实现自己的 RouteHandler

到现在,我们已经知道了Routing大概是怎么运行起来,知道了如何简单的使用。那么接下来可以来创建一个自己的RouteHandler,来加深一下对Routing的使用体验。

创建一个类MyRouteHandler,实现接口IRoute:

public class MyRouteHandler : IRouter
{
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
return null;
} public Task RouteAsync(RouteContext context)
{ context.Handler = (c) =>
{
var printStr = $"controller:{c.GetRouteValue("controller")}," +
$"action:{c.GetRouteValue("action")},id:{c.GetRouteValue("id")}"; return c.Response.WriteAsync(printStr);
};
return TaskCache.CompletedTask;
}
}

然后我们的路由配置改成这样:

    public void Configure(IApplicationBuilder app)
{
var endpoint = new MyRouteHandler(); var routeBuilder = new RouteBuilder(app)
{
DefaultHandler = endpoint,
}; routeBuilder.MapRoute("default","{controller=Home}/{action=Index}/{id?}"); app.UseRouter(routeBuilder.Build());
}

然后打开浏览器http://localhost:5000/ 打印出来的内容是 controller:Home,action:Index,id: 。这样是不是很像我们去调用mvc的控制器和控制器的行为呢?Routing的体验文章到这来就结束了,谢谢观看。


由于本人水平有限,知识有限,文章难免会有错误,欢迎大家指正。如果有什么问题也欢迎大家回复交流。要是你觉得本文还可以,那么点击一下推荐。

dotnet core 开发体验之Routing的更多相关文章

  1. dotnet core开发体验之开始MVC

    开始 在上一篇文章:dotnet core多平台开发体验 ,体验了一把dotnet core 之后,现在想对之前做的例子进行改造,想看看加上mvc框架是一种什么样的体验,于是我就要开始诞生今天的这篇文 ...

  2. vs2017 js cordova + dotnet core 开发app

    原文:vs2017 js cordova + dotnet core 开发app 1.记得在index.html加入 <meta http-equiv="Content-Securit ...

  3. dotNet Core开发环境搭建及简要说明

    一.安装 .NET Core SDK 在 Windows 上使用 .NET Core 的最佳途径:使用Visual Studio. 免费下载地址: Visual Studio Community 20 ...

  4. 使用ubuntu做为dotnet core开发环境

    一.安装google浏览器 1.下载安装包(传送门:http://www.google.cn/intl/zh-CN/chrome/browser/desktop/index.html) 2.使用sud ...

  5. dotnet core 开发中遇到的问题

    1.发布的时候把视图cshtml文件也编译为dll了,如何控制不编译视图? 编辑功能文件(xx.csproj),加入一个选项: <PropertyGroup> <TargetFram ...

  6. WSL2 准备dotnet core开发环境

    首先我们要知道WSL Ubuntu的版本,以便进行下一步操作: 我的是18.04,所以安装dot net SDK我们参考这里: https://docs.microsoft.com/en-us/dot ...

  7. dotnet core 开发无缝兼容Http和Websocket协议的接口服务

    在应用接口开发中往往要针对不同协义开发相应的代理服务,但对于Websocket和http这两种协议来说就有些不同,从实现上来看Websocket可以说是Http的升级子协议, 两者在协议处理上基本一致 ...

  8. 基于DotNet Core的RPC框架(一) DotBPE.RPC快速开始

    0x00 简介 DotBPE.RPC是一款基于dotnet core编写的RPC框架,而它的爸爸DotBPE,目标是实现一个开箱即用的微服务框架,但是它还差点意思,还仅仅在构思和尝试的阶段.但不管怎么 ...

  9. 手把手教你使用spring cloud+dotnet core搭建微服务架构:服务治理(-)

    背景 公司去年开始使用dotnet core开发项目.公司的总体架构采用的是微服务,那时候由于对微服务的理解并不是太深,加上各种组件的不成熟,只是把项目的各个功能通过业务层面拆分,然后通过nginx代 ...

随机推荐

  1. 理解runtime system

    最近需要编译不同平台的库,因此比以前只开发C++程序关注底层更多点.先来看看术语runtime system的解释. 主要参考资料: http://en.wikipedia.org/wiki/Runt ...

  2. [T-SQL]从变量与数据类型说起

     1.变量 学习计算机语言,难免不碰到这个名词,不过咱这里说的是MSSQL(微软SQL Server产品)里的数据库语言实现. 稍微对程序比较严谨的语言都要求使用之前都要声明变量先,比如c.c++,j ...

  3. PHP文件操作常用函数总结

    一 .解析路径: 1 获得文件名: basename(); 给出一个包含有指向一个文件的全路径的字符串,本函数返回基本的文件名.如果文件名是以 suffix 结束的,那这一部分也会被去掉. eg: $ ...

  4. SQL 中having 和where的区别分析

    在select语句中可以使用groupby子句将行划分成较小的组,然后,使用聚组函数返回每一个组的汇总信息,另外,可以使用having子句限制返回的结果集 在select语句中可以使用groupby子 ...

  5. 开源的连接池技术DBCP和C3P0

    概述: Sun公司约定: 如果是连接池技术,需要实现一个接口! javax.sql.DataSource;   相关jar包和资料下载 1.1  DBCP连接池: l  DBCP 是 Apache 软 ...

  6. java 使用线程做一个简单的ATM存取款实例.(转)

    线程 Thread 类,和 Runable 接口 比较两者的特点和应用领域. 可以,直接继承线程Thread类.该方法编写简单,可以直接操作线程,适用于单重继承情况,因而不能在继承其他类 实现Runn ...

  7. 5 Ways to Use Log Data to Analyze System Performance--reference

    Recently we looked across some of the most common behaviors that our community of 25,000 users looke ...

  8. [转] React Router 使用教程

    PS:react-route就是一个决定生成什么父子关系的组件,一般和layout结合起来,保证layout不行,内部的子html进行跳转 你会发现,它不是一个库,也不是一个框架,而是一个庞大的体系. ...

  9. Properties文件,Data,Calendar类的使用

    package cn.hncu.day9; import java.io.FileInputStream;import java.io.FileNotFoundException;import jav ...

  10. HTML+CSS基础学习笔记(6)

    一.元素分类 CSS中html的标签元素大体分为三种类型 1.块状元素 @特点: #每个块级元素都从新的一行开始,并且其后的元素也另起一行(一个块级元素独占一行) #元素的高度.宽度.行高以及顶和底边 ...