ASP.NET Core 2.2 : 扒一扒新的Endpoint路由方案
ASP.NET Core 從2.2版本開始,采用了一個(gè)新的名為Endpoint的路由方案,與原來(lái)的方案在使用上差別不大,但從內(nèi)部運(yùn)行方式上來(lái)說,差別還是很大的。上一篇ASP.NET Core;圖解路由(2.1 earler)詳細(xì)介紹了原版路由方案的運(yùn)行機(jī)制,本文仍然通過一幅圖來(lái)了解一下新版的運(yùn)行機(jī)制,最后再總結(jié)一下二者的異同點(diǎn)。
一、概述
? ? ? ?此方案從2.2版本開始,被稱作終結(jié)點(diǎn)路由(下文以“新版”稱呼),它是默認(rèn)開啟的,若想采用原來(lái)的方案(<=2.1,下文以原版稱呼),可以在AddMvc的時(shí)候進(jìn)行設(shè)置
services.AddMvc(option=>option.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);EnableEndpointRouting 默認(rèn)為true,也就是啟用新的Endpoint方案,設(shè)置為false則采用舊版(<=2.1)的路由方案。
? ? ? ? 在配置方法上來(lái)說,系統(tǒng)仍然采用在Startup中的use.Mvc()中配置,而實(shí)際上內(nèi)部的處理中間件已由原來(lái)的RouterMiddleware改為EndpointMiddleware和EndpointRoutingMiddleware兩個(gè)中間件處理,下面依舊通過一幅圖來(lái)詳細(xì)看一下:
?二、流程及解析
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖一
為了方便查看,依然對(duì)幾個(gè)“重點(diǎn)對(duì)象”做了顏色標(biāo)識(shí)(點(diǎn)擊圖片可以看大圖):
? ? ? 1. 路由的初始化配置(圖的前兩個(gè)泳道)?
①? 一切依然是從Startup開始,而且和舊版一樣,是通過UseMvc方法進(jìn)行配置,傳入routes.MapRoute(...)這樣的一個(gè)或多個(gè)配置, 不做贅述。
下面著重說一下后面的流程,看一下MvcApplicationBuilderExtensions中的UseMvc方法:
② 第6行,這里會(huì)獲取并判斷設(shè)置的EnableEndpointRouting的值,若為false,則采用舊版路由,詳見上一篇文章;該值默認(rèn)為true,即采用新版路由。
?③ 對(duì)應(yīng)第9行,MvcEndpointDataSource在新版路由中是個(gè)非常非常重要的角色,在啟動(dòng)初始化階段,它完成了路由表存儲(chǔ)和轉(zhuǎn)換,此處先用顏色重點(diǎn)標(biāo)記一下,大家記住它,在后面的流程中詳細(xì)介紹。
?④ 對(duì)應(yīng)第16行,同舊版的RouteBuilder一樣,這里會(huì)new一個(gè) endpointRouteBuilder,二者都是一個(gè)IRouteBuilder,所以也同樣調(diào)用configureRoutes(endpointRouteBuilder)方法(也就是startup中的配置)獲取了一個(gè)Route的集合(IList<IRouter>)賦值給endpointRouteBuilder.Routes,這里有個(gè)特別該注意的地方if (router is Route route && router.GetType() == typeof(Route)) ,也就是這里只接受route類型,終結(jié)點(diǎn)路由系統(tǒng)不支持基于 IRouter的可擴(kuò)展性,包括從 Route繼承。
⑤ 對(duì)應(yīng)第20行,這里對(duì)剛獲取到的endpointRouteBuilder.Routes進(jìn)行遍歷,轉(zhuǎn)換成了一個(gè)MvcEndpointInfo的集和,賦值給mvcEndpointDataSource.ConventionalEndpointInfos。
⑥ 之后就是向管道塞中間件了,這里的處理中間件由原來(lái)的RouterMiddleware改為EndpointMiddleware和EndpointRoutingMiddleware。
??2.請(qǐng)求的處理(圖的后兩個(gè)泳道)
? ? ? ?請(qǐng)求的處理大部分功能在中間件EndpointRoutingMiddleware,他有個(gè)重要的屬性_endpointDataSource保存了上文中初始化階段生成的MvcEndpointDataSource,而中間件EndpointMiddleware的功能比較簡(jiǎn)單,主要是在EndpointRoutingMiddleware篩選出endpoint之后,調(diào)用該endpoint的endpoint.RequestDelegate(httpContext)進(jìn)行請(qǐng)求處理。
?⑦ InitializeAsync()方法主要是用于調(diào)用InitializeCoreAsync()創(chuàng)建一個(gè)matcher,而通過這個(gè)方法的代碼可以看出它只是在第一次請(qǐng)求的時(shí)候執(zhí)行一次。
?? ⑧ MvcEndpointDataSource一個(gè)重要的方法UpdateEndpoints(),作用是讀取所有action,并將這個(gè)action列表與它的ConventionalEndpointInfos列表(見⑤)進(jìn)行匹配,最終生成一個(gè)新的列表。如下圖,我們默認(rèn)情況下只配置了一個(gè)"{controller=Home}/{action=Index}/{id?}"這樣的路由,默認(rèn)的HomeController有三個(gè)action,添加了一個(gè)名為FlyLoloController的controller并添加了一個(gè)帶屬性路由的action,最終生成了7個(gè)Endpoint,這有點(diǎn)像路由與action的“乘積”。當(dāng)然,這里只是用默認(rèn)程序舉了個(gè)簡(jiǎn)單的例子,實(shí)際項(xiàng)目中可能會(huì)有更多的路由模板注冊(cè)、會(huì)有更多的Controller和Action以及屬性路由等。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖二
具體代碼如下:
本質(zhì)就是計(jì)算出一個(gè)個(gè)可能被請(qǐng)求的請(qǐng)求終結(jié)點(diǎn),也就是Endpoint。由此可見,如上一篇文章那樣想自定義一個(gè)handler來(lái)處理特殊模板的方式(如 routes.MapRoute("flylolo/{code}/{name}", MyRouteHandler.Handler);)將被忽略掉,因其無(wú)法生成 Endpoint,且此種方式完全可以自定義一個(gè)中間件來(lái)實(shí)現(xiàn),沒必要混在路由中。
? ? ? ? ? ? ⑨ 就是用上面生成的Matcher,攜帶Endpoint列表與請(qǐng)求URL做匹配,并將匹配到的Endpoint賦值給feature.Endpoint。
? ? ? ? ? ? ⑩ 獲取feature.Endpoint,若存在則調(diào)用其RequestDelegate處理請(qǐng)求httpContext。
?三、新版與舊版的異同點(diǎn)總結(jié)
簡(jiǎn)要從應(yīng)用系統(tǒng)啟動(dòng)和請(qǐng)求處理兩個(gè)階段對(duì)比說一下兩個(gè)版本的區(qū)別:
1.啟動(dòng)階段:
這個(gè)階段大部分都差不多,都是通過Startup的app.UseMvc()方法配置一個(gè)路由表,一個(gè)Route的集合Routes(IList<IRouter>),然后將其簡(jiǎn)單轉(zhuǎn)換一下
<=2.1:? 將Routes轉(zhuǎn)換為RouteCollection
2.2+ : ? 將Routes轉(zhuǎn)換為L(zhǎng)ist<MvcEndpointInfo>
二者區(qū)別不大,雖然名字不同,但本質(zhì)上還是差不多,都仍可理解為Route的集合的包裝。
2.請(qǐng)求處理階段:
<=2.1: ? 1. 將請(qǐng)求的URL與RouteCollection中記錄的路由模板進(jìn)行匹配。
? ? ? ? ? ?2. 找到匹配的Route之后,再根據(jù)這個(gè)請(qǐng)求的URL判斷是否存在對(duì)應(yīng)的Controlled和Action。
? ? ? ? ? ?3. 若以上均通過,則調(diào)用Route的Handler對(duì)HttpContext進(jìn)行處理。
2.2+ : ? 1. 第一次處理請(qǐng)求時(shí),首先根據(jù)啟動(dòng)階段所配置的路由集合List<MvcEndpointInfo>和_actions.ActionDescriptors.Items(所有的action的信息)做匹配,生成一個(gè)列表,這個(gè)列表存儲(chǔ)了所有可能被匹配的URL模板,如圖二,這個(gè)列表同樣是List<MvcEndpointInfo>,記錄了所有可能的URL模式,實(shí)際上是列出了一個(gè)個(gè)可以被訪問的詳細(xì)地址,已經(jīng)算是最終地址了,即終結(jié)點(diǎn),或許就是為什么叫Endpoint路由的原因。
? ? ? ? ? ? 2.請(qǐng)求的Url和這個(gè)生成的表做匹配,找到對(duì)應(yīng)的MvcEndpointInfo。
? ? ? ? ? ? 3. 調(diào)用被匹配的MvcEndpointInfo的RequestDelegate方法對(duì)請(qǐng)求進(jìn)行處理。
二者區(qū)別就是對(duì)于_actions.ActionDescriptors.Items(所有的action的信息)的匹配上,原版是先根據(jù)路由模板匹配后,再根據(jù)ActionDescriptors判斷是否存在對(duì)應(yīng)的Controller和action,而新版是先利用了action信息與路由模板匹配,然后再用請(qǐng)求的URL進(jìn)行匹配,由于這樣的工作只在第一次請(qǐng)求的時(shí)候執(zhí)行,所以雖然沒有做執(zhí)行效率上的測(cè)試,但感覺應(yīng)該是比之前快的。?
原文鏈接:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_16.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Core 2.2 : 扒一扒新的Endpoint路由方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为云提供针对Nuget包管理器的缓存加
- 下一篇: asp.net ajax控件工具集 Au