在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
知識星球