Endpoint路由

在ASP.NET Core 2.2中,新增了一种路由,叫做Endpoint(终结点)路由。本文将以往的路由系统称为传统路由。

本文通过源码的方式介绍传统路由和Endpoint路由部分核心功能和实现方法,具体功能上的差异见官方文档。

在升级到ASP.NET Core 2.2后,会自动启用Endpoint路由。如果要恢复以往的实现逻辑,需要加入以下代码:

services.AddMvc(options => options.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

本文分析的源代码基于ASP.NET Core 2.2.3版本的源代码。

Endpoint作用

Endpoint路由与传统路由的区别在于,传统路由Url与Action对应关系的处理是在UseMvc中做的。我们无法根据Url获取对应的Action然后进行处理。

Endpoint就是将Url与Action的映射关系从Mvc中拆离,作为独立使用的中间件。

由此带来的好处是我们可以在其他的中间件中使用Controller和Action上的一些信息,例如Attruibute。

框架也提供了LinkGenerator类来直接根据Endpoint生成链接,不再需要HttpContext的信息。

另外也提升了一些RPS(Requests per Second)。

不过目前Endpoint依然是在UseMvc中调用,更多开放的使用方式会在ASP.NET Core 3.0中实现。

启用Endpoint路由

源代码见Github。也可以获取源代码到本地看。

在MvcApplicationBuilderExtensions.cs文件72行的UseMvc方法中我们可以看到以下代码:

var options = app.ApplicationServices.GetRequiredService<IOptions<MvcOptions>>();

if (options.Value.EnableEndpointRouting)
{
...
}
else
{
...
}

if之中是Endpoint路由的逻辑,else是传统路由的逻辑。

而MvcOptions的构造方法如下所示,EnableEndpointRouting是通过CompatibilitySwitch来控制默认值的,这就是CompatibilityVersion.Version_2_2启用Endpoint路由的原因。

public MvcOptions()
{
// ...
_enableEndpointRouting = new CompatibilitySwitch<bool>(nameof(EnableEndpointRouting));
// ...
}

Endpoint路由实现原理

在MvcApplicationBuilderExtensions.cs文件的92-123行的代码是将所有的Controller中的Action转换成Endpoint。

在129行的UseEndpointRouting中,添加了一个EndpointRoutingMiddleware的中间件,这个中间件就是从所有的Endpoint中找到当前路由对应的Endpoint,然后放到Feature集合中。

在132行的UseEndpoint中,添加了一个EndpointMiddleware中间件,这个中间件是将EndpointRoutingMiddleware中找到的Endpoint取出,并调用RequestDelegate。RequestDelegate是预处理过的Url对应的Action方法。

在UseMvc方法里,UseEndpointRouting和UseEndpoint是连续的两个中间件,而UseEndpoint是请求的结束,这意味着我们自定义的中间件无法取得Endpoint信息。

但是通过手动调用UseEndpointRouting,我们还是可以拿到Endpoint路由信息的。

使用示例

下面展示一个使用示例。

定义一个LogAttribute类,并包含一个Message属性,在Action上声明使用。

定义一个EndpointTestMiddleware中间件,输出LogAttribute的Message属性。

手动调用UseEndpointRouting,然后调用我们定义的EndpointTestMiddleware中间件。

// Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseEndpointRouting(); app.UseMiddleware<EndpointTestMiddleware>(); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
// EndpointTestMiddleware.cs
public class EndpointTestMiddleware
{
private RequestDelegate _next; public EndpointTestMiddleware(RequestDelegate next)
{
_next = next;
} public async Task Invoke(HttpContext httpContext)
{
var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
if (endpoint == null)
{
await _next(httpContext);
return;
}
var attruibutes = endpoint.Metadata.OfType<LogAttribute>();
foreach (var attribute in attruibutes)
{
Debug.WriteLine("------------------------------------------------------------------------");
Debug.WriteLine(attribute.Message);
Debug.WriteLine("------------------------------------------------------------------------");
}
await _next(httpContext);
}
}
// LogAttribute.cs
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public sealed class LogAttribute : Attribute
{
public LogAttribute(string message)
{
Message = message;
} public string Message { get; set; }
}
// HomeController.cs
public class HomeController : Controller
{
[Log("Index")]
public IActionResult Index()
{
return View();
} [Log("Privacy")]
public IActionResult Privacy()
{
return View();
}
}

这样的话,我们可以在我们自己的中间件中拿到Endpoint信息,然后找到Controller上的LogAttribute,然后输出Message。

总结

Endpoint是ASP.NET Core 2.2中一种新的路由机制,它解决了传统路由难以扩展的问题,解决了传统路由与MVC过于耦合的问题,并提升了一定的RPS。

本文介绍了Endpoint路由,简单分析了Endpoint的实现原理,并给出了一个使用的示例。

参考链接:

  1. https://devblogs.microsoft.com/aspnet/asp-net-core-2-2-0-preview1-endpoint-routing/
  2. https://www.stevejgordon.co.uk/asp-net-core-first-look-at-global-routing-dispatcher
  3. https://rolandguijt.com/endpoint-routing-in-asp-net-core-2-2-explained/

ASP.NET Core 2.2中的Endpoint路由的更多相关文章

  1. ASP.NET Core 3.0中使用动态控制器路由

    原文:Dynamic controller routing in ASP.NET Core 3.0 作者:Filip W 译文:https://www.cnblogs.com/lwqlun/p/114 ...

  2. 避免在ASP.NET Core 3.0中为启动类注入服务

    本篇是如何升级到ASP.NET Core 3.0系列文章的第二篇. Part 1 - 将.NET Standard 2.0类库转换为.NET Core 3.0类库 Part 2 - IHostingE ...

  3. asp.net core 3.0 中使用 swagger

    asp.net core 3.0 中使用 swagger Intro 上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口 ...

  4. 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs

    原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...

  5. 将终结点图添加到你的ASP.NET Core应用程序中

    在本文中,我将展示如何使用DfaGraphWriter服务在ASP.NET Core 3.0应用程序中可视化你的终结点路由.上面文章我向您演示了如何生成一个有向图(如我上篇文章中所示),可以使用Gra ...

  6. ASP.NET Core HTTP 管道中的那些事儿

    前言 马上2016年就要过去了,时间可是真快啊. 上次写完 Identity 系列之后,反响还不错,所以本来打算写一个 ASP.NET Core 中间件系列的,但是中间遇到了很多事情.首先是 NPOI ...

  7. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  8. 在ASP.NET Core 1.0中如何发送邮件

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:目前.NET Core 1.0中并没有提供SMTP相关的类库,那么要如何从ASP.NE ...

  9. ASP.NET Core 1.0 中使用 Swagger 生成文档

    github:https://github.com/domaindrivendev/Ahoy 之前文章有介绍在ASP.NET WebAPI 中使用Swagger生成文档,ASP.NET Core 1. ...

随机推荐

  1. uname命令详解

    1.简介: uname命令用于打印当前系统相关信息(内核版本号.硬件架构.主机名称和操作系统类型等). 2.命令语法: uname (选项) 3.选项: -a或--all:显示全部的信息: -m或-- ...

  2. rpm包安装的nginx热升级

    文章目录一.本地环境基本介绍二.yum升级命令说明三.升级好nginx后如何不中断业务切换3.1.nginx相关的信号说明3.2.在线热升级nginx可执行文件程序一.本地环境基本介绍本次测试环境,是 ...

  3. ADC采样间隔问题+TRGO作为ADC的触发源头

    为了控制采样时间,可以使用一个定时器的TRGO(定时器里每次发生更新事件时会有这个信号产生)作为定时器的外部触发. 从定时器框图可以看出,TRGO为TIMx的一个输出.不过这个输出是内部使用的. vo ...

  4. 加入 Jungle Testnet

    [加入 Jungle Testnet] 主网测试需要消耗大量 EOS,JungleTestnet为我们提供了一个测试用的EOS主链,上面的EOS可以通过申请获得.每6小时可以申请100EOS. [创建 ...

  5. cdnbest日志分析显示404的原因

    日志分析报404原因 报这个提示一般是日志没有开启或还没有日志 检查下面几点: 开启和关闭站点日志在节点3311中显示如下图nolog是关闭  日志翻转目前默认是1个小时以后会默认改成20分钟,翻转时 ...

  6. python调用webservice接口

    使用suds这个第三方模块 from suds.client import Clienturl = 'http://ip:port/?wsdl'cilent=Client(url)print cile ...

  7. Codeforces Round #449 (Div. 2)

    Codeforces Round #449 (Div. 2) https://codeforces.com/contest/897 A #include<bits/stdc++.h> us ...

  8. php Pthread 多线程 Worker

    <?php //PHP 高级编程之多线程 http://www.netkiller.cn/journal/thread.php.html#idp57489856 //worker 是一个具有持久 ...

  9. ImportError: No module named MySQLdb问题的解决

    今天在windows上撸python代码,遇到ImportError: No module named MySQLdb的问题,遂赶紧pip install mysql-python,结果还是不行,查看 ...

  10. Spring源码-循环依赖源码解读

    Spring源码-循环依赖源码解读 笔者最近无论是看书还是从网上找资料,都没发现对Spring源码是怎么解决循环依赖这一问题的详解,大家都是解释了Spring解决循环依赖的想法(有的解释也不准确,在& ...