ASP.NET Core 2.2中的Endpoint路由详解
Endpoint路由
在ASP.NETCore2.2中,新增了一种路由,叫做Endpoint(终结点)路由。本文将以往的路由系统称为传统路由。
本文通过源码的方式介绍传统路由和Endpoint路由部分核心功能和实现方法,具体功能上的差异见官方文档。
在升级到ASP.NETCore2.2后,会自动启用Endpoint路由。如果要恢复以往的实现逻辑,需要加入以下代码:
services.AddMvc(options=>options.EnableEndpointRouting=false) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
本文分析的源代码基于ASP.NETCore2.2.3版本的源代码。
Endpoint作用
Endpoint路由与传统路由的区别在于,传统路由Url与Action对应关系的处理是在UseMvc中做的。我们无法根据Url获取对应的Action然后进行处理。
Endpoint就是将Url与Action的映射关系从Mvc中拆离,作为独立使用的中间件。
由此带来的好处是我们可以在其他的中间件中使用Controller和Action上的一些信息,例如Attruibute。
框架也提供了LinkGenerator类来直接根据Endpoint生成链接,不再需要HttpContext的信息。
另外也提升了一些RPS(RequestsperSecond)。
不过目前Endpoint依然是在UseMvc中调用,更多开放的使用方式会在ASP.NETCore3.0中实现。
启用Endpoint路由
源代码见Github。也可以获取源代码到本地看。
在MvcApplicationBuilderExtensions.cs文件72行的UseMvc方法中我们可以看到以下代码:
varoptions=app.ApplicationServices.GetRequiredService>(); if(options.Value.EnableEndpointRouting) { ... } else { ... }
if之中是Endpoint路由的逻辑,else是传统路由的逻辑。
而MvcOptions的构造方法如下所示,EnableEndpointRouting是通过CompatibilitySwitch来控制默认值的,这就是CompatibilityVersion.Version_2_2启用Endpoint路由的原因。
publicMvcOptions()
{
//...
_enableEndpointRouting=newCompatibilitySwitch(nameof(EnableEndpointRouting));
//...
}
Endpoint路由实现原理
在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中间件。
//Startup.cs
publicvoidConfigure(IApplicationBuilderapp,IHostingEnvironmentenv)
{
app.UseEndpointRouting();
app.UseMiddleware();
app.UseMvc(routes=>
{
routes.MapRoute(
name:"default",
template:"{controller=Home}/{action=Index}/{id?}");
});
}
//EndpointTestMiddleware.cs
publicclassEndpointTestMiddleware
{
privateRequestDelegate_next;
publicEndpointTestMiddleware(RequestDelegatenext)
{
_next=next;
}
publicasyncTaskInvoke(HttpContexthttpContext)
{
varendpoint=httpContext.Features.Get()?.Endpoint;
if(endpoint==null)
{
await_next(httpContext);
return;
}
varattruibutes=endpoint.Metadata.OfType();
foreach(varattributeinattruibutes)
{
Debug.WriteLine("------------------------------------------------------------------------");
Debug.WriteLine(attribute.Message);
Debug.WriteLine("------------------------------------------------------------------------");
}
await_next(httpContext);
}
}
//LogAttribute.cs
[AttributeUsage(AttributeTargets.Method,Inherited=false,AllowMultiple=true)]
publicsealedclassLogAttribute:Attribute
{
publicLogAttribute(stringmessage)
{
Message=message;
}
publicstringMessage{get;set;}
}
//HomeController.cs
publicclassHomeController:Controller
{
[Log("Index")]
publicIActionResultIndex()
{
returnView();
}
[Log("Privacy")]
publicIActionResultPrivacy()
{
returnView();
}
}
这样的话,我们可以在我们自己的中间件中拿到Endpoint信息,然后找到Controller上的LogAttribute,然后输出Message。
总结
Endpoint是ASP.NETCore2.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/]
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。