在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
路由與傳統路由的區別在於,傳統路由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中實現。
原始碼見Github。也可以獲取原始碼到本地看。
在MvcApplicationBuilderExtensions.cs
檔案72行的UseMvc
方法中我們可以看到以下程式碼:
var options = app.ApplicationServices.GetRequiredService>();
if (options.Value.EnableEndpointRouting)
{
...
}
else
{
...
}
if
之中是Endpoint
路由的邏輯,else
是傳統路由的邏輯。
而MvcOptions
的構造方法如下所示,EnableEndpointRouting
是透過CompatibilitySwitch
來控制預設值的,這就是CompatibilityVersion.Version_2_2
啟用Endpoint
路由的原因。
public MvcOptions()
{
_enableEndpointRouting = new CompatibilitySwitch<bool>(nameof(EnableEndpointRouting));
}
在MvcApplicationBuilderExtensions.cs
檔案的92-123行的程式碼是將所有的Controller
中的Action
轉換成Endpoint
。
在129行的UseEndpointRouting
中,添加了一個EndpointRoutingMiddleware
的中介軟體,這個中介軟體就是從所有的Endpoint
中找到當前路由對應的Endpoint
,然後放到Feature
集合中。
在132行的UseEndpoint
中,添加了一個EndpointMiddleware
中介軟體,這個中介軟體是將EndpointRoutingMiddleware
中找到的Endpoint
取出,根據其中的MetaData
資訊,找到對應的Controller
和Action
,並呼叫。
在UseMvc
方法裡,UseEndpointRouting
和UseEndpoint
是連續的兩個中介軟體,而UseEndpoint
是請求的結束,這意味著我們自定義的中介軟體無法取得Endpoint
資訊。
但是透過手動呼叫UseEndpoint
,我們還是可以拿到Endpoint
路由資訊的。
下麵展示一個使用示例。
定義一個LogAttribute
類,並包含一個Message
屬性,在Action
上宣告使用。
定義一個EndpointTestMiddleware
中介軟體,輸出LogAttribute
的Message
屬性。
手動呼叫UseEndpointRouting
,然後呼叫我們定義的EndpointTestMiddleware
中介軟體。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseEndpointRouting();
app.UseMiddleware();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
public class EndpointTestMiddleware
{
private RequestDelegate _next;
public EndpointTestMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var endpoint = httpContext.Features.Get()?.Endpoint;
if (endpoint == null)
{
await _next(httpContext);
return;
}
var attruibutes = endpoint.Metadata.OfType();
foreach (var attribute in attruibutes)
{
Debug.WriteLine("------------------------------------------------------------------------");
Debug.WriteLine(attribute.Message);
Debug.WriteLine("------------------------------------------------------------------------");
}
await _next(httpContext);
}
}
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public sealed class LogAttribute : Attribute
{
public LogAttribute(string message)
{
Message = message;
}
public string Message { get; set; }
}
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的實現原理,並給出了一個使用的示例。
參考連結:
- [https://devblogs.microsoft.com/aspnet/asp-net-core-2-2-0-preview1-endpoint-routing/]
- [https://www.stevejgordon.co.uk/asp-net-core-first-look-at-global-routing-dispatcher]
- [https://rolandguijt.com/endpoint-routing-in-asp-net-core-2-2-explained/]
原文地址:https://www.cnblogs.com/Weilence/p/10616567.html