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/
相關文章
相關標籤/搜索