ASP.NET Core 2.2中的Endpoint路由

Endpoint路由

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

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

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

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

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

Endpoint做用

Endpoint路由与传统路由的区别在于,传统路由UrlAction对应关系的处理是在UseMvc中作的。咱们没法根据Url获取对应的Action而后进行处理。框架

Endpoint就是将UrlAction的映射关系从Mvc中拆离,做为独立使用的中间件。async

由此带来的好处是咱们能够在其余的中间件中使用ControllerAction上的一些信息,例如Attruibuteui

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

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

不过目前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取出,并调用RequestDelegateRequestDelegate是预处理过的Url对应的Action方法。

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

可是经过手动调用UseEndpointRouting,咱们仍是能够拿到Endpoint路由信息的。

使用示例

下面展现一个使用示例。

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

定义一个EndpointTestMiddleware中间件,输出LogAttributeMessage属性。

手动调用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/
相关文章
相关标签/搜索