日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core MVC 源码学习:详解 Action 的匹配

發(fā)布時間:2025/7/14 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core MVC 源码学习:详解 Action 的匹配 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

在 上一篇 文章中,我們已經(jīng)學(xué)習(xí)了 ASP.NET Core MVC 的啟動流程,那么 MVC 在啟動了之后,當(dāng)請求到達過來的時候,它是怎么樣處理的呢? 又是怎么樣把我們的請求準(zhǔn)確的傳達到我們的 Action 上呢? 那么,在這邊文章中,我們一起跟蹤源碼看一下,框架都做了些什么東西。

Getting Started

我們知道,Startup.cs 中的 Configure(IApplicationBuilder app) 中,我們使用 app.UseMvc()

在 UseMVC() 代碼執(zhí)行的過程中,它可以接收一個 Action<IRouteBuilder> 形式的委托,我們使用這個委托可以進行自定義路由的配置,默認情況下,我們一般會如下進行配置:

app.UseMvc(routes => {routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}"); });

或者是你使用默認的 app.UseMvcWithDefaultRoute(),這個擴展方法在內(nèi)部已經(jīng)幫你做了上述代碼的內(nèi)容。

那我們今天就從這個 Route 的配置開始看起吧。

RouteContext 如何初始化?

在 IRouteBuilder 通過配置 IRouteBuilder,IRouteBuilder 在 Build() 之后會得到 Router 會得到 IRouter。

public static IApplicationBuilder UseMvc(this IApplicationBuilder app,Action<IRouteBuilder> configureRoutes) {// ......var routes = new RouteBuilder(app){DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),};configureRoutes(routes);routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices));return app.UseRouter(routes.Build()); }

上面的代碼有兩個地方需要注意的。

第一個地方是 DefaultHandler,可以看到默認配置下,MVC 程序從 DI 中獲取 MvcRouteHandler 路由處理程序來作為路由的默認處理程序。

第二個地方是 AttributeRouting.CreateAttributeMegaRoute(app.ApplicationServices)
,那么這個地方是干嘛的呢?

CreateAttributeMegaRoute 它返回了一個 IRouter ,主要是用來處理帶 RouteAttribute 標(biāo)記的 Action,我們來看一下這個方法:

public static IRouter CreateAttributeMegaRoute(IServiceProvider services) {return new AttributeRoute(services.GetRequiredService<IActionDescriptorCollectionProvider>(),services,actions => {var handler = services.GetRequiredService<MvcAttributeRouteHandler>();handler.Actions = actions;return handler;}); }

在方法內(nèi)部,new 了一個 AttributeRoute 返回了回去,大家可以看到有一個參數(shù) actions,它使用的是 MvcAttributeRouteHandler 這個處理程序,說明在實際調(diào)用過程中使用的是 MvcAttributeRouteHandler 進行的路由處理。

OK,我們總結(jié)一下關(guān)于 MVC 自己的幾個路由處理程序,還是用一個圖比較容易看的清楚,幸運的是,MVC 一共就這3個路由處理程序,我們已經(jīng)全部接觸到了。

MVC 框架針對于 IRouter 接口的實現(xiàn)有以下三個:

提前告訴你,最左邊綠色的那個 AttributeRoute 其實只是一個包裝,在內(nèi)部也是通過 MvcAttributeRouteHandler 或者 MvcRouteHandler 進行的處理。那么,現(xiàn)在關(guān)于路由的處理程序只剩下了兩個,他們分別是:

默認處理程序: MvcRouteHandler,用來處理約定的 Action。

注解處理程序: MvcAttributeRouteHandler ,用來處理注解(Attribute)路由。

細心的同學(xué)可能注意到了, MvcAttributeRouteHandler 比 MvcRouteHandler 多了一個 Actions : ActionDescriptor[]屬性。

我們再看一下這兩個處理程序的 RouteAsync 方法,這個方法是路由組件的入口方法,我們通過一個對比工具來看一下兩者之間的差距。

圖片看不清楚可以新標(biāo)簽打開

可以看到,這兩個 RouteAsync 主要有兩處差距,第一處就是 SelectBestCandidate 這個函數(shù)第二個參數(shù)

ActionDescriptor SelectBestCandidate(RouteContext context, IReadOnlyList<ActionDescriptor> candidates)

MvcRouteHandler:

在這個流程中,顯示調(diào)用了 IActionSelect 接口中的 SelectCandidates() 用來找到所有符合條件的候選 Action,然后調(diào)用了 SelectBestCandidate 找出最佳的一個。

程序走到這里,這里會有兩個重點的地方,或者叫有疑問的地方?

1、 程序集中定義的 Action 是怎么找到的?

要想找到程序定義的所有 Action,那么首先需要找到 Controller,在上一篇文章中我們已經(jīng)知道了有一個 MVC 程序用來管理 AssemblyPart 的東西叫 ApplicationPartManager ,它的里面存儲了所有 MVC 框架在啟動的時候加載的所有程序集,那么我們可以從這個程序集中找到需要的 Controller。下面這個流程圖顯示了查找Controller 的流程:

GetControllerTypes 返回的是一個 IEnumerable<TypeInfo> 的集合,有了 Controller 之后,MVC 框架使用了一個對象來包裝 Controller,因為在后續(xù)的流程中,除了需要 Controller 之外還需要其他的一些東西,比如 Filter, ApiExplorer 等。

ApplicationModel

ApplicationModel 就是MVC框架用來包裝 Controller,Filter , ApiExplorer 等的一個Model 對象,我們來看一下它的定義:

public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel {public ApplicationModel(){ApiExplorer = new ApiExplorerModel();Controllers = new List<ControllerModel>();Filters = new List<IFilterMetadata>();Properties = new Dictionary<object, object>();}public ApiExplorerModel ApiExplorer { get; set; }public IList<ControllerModel> Controllers { get; private set; }public IList<IFilterMetadata> Filters { get; private set; }public IDictionary<object, object> Properties { get; } }

ApplicationModel 里面關(guān)于 Controller 的包裝是一個 IList<ControllerModel>,看一下 ControllerModel 的定義:

public class ControllerModel : ICommonModel, IFilterModel, IApiExplorerModel {//......public IList<ActionModel> Actions { get; }public ApiExplorerModel ApiExplorer { get; set; }public ApplicationModel Application { get; set; }public IReadOnlyList<object> Attributes { get; }MemberInfo ICommonModel.MemberInfo => ControllerType;string ICommonModel.Name => ControllerName;public string ControllerName { get; set; }public TypeInfo ControllerType { get; }public IList<PropertyModel> ControllerProperties { get; }public IList<IFilterMetadata> Filters { get; }public IDictionary<string, string> RouteValues { get; }public IDictionary<object, object> Properties { get; }public IList<SelectorModel> Selectors { get; } }

在 ASP.NET Core MVC 框架中,ApplicationModel 有下面幾個提供者,他們用于初始化整個 ApplicationModel 的各個部分,我們還是分別看一下吧。

AuthorizationApplicationModelProvider: 處理認證相關(guān)業(yè)務(wù)邏輯,在它的Executing方法中會將 AuthorizeFilter,AllowAnonymousFilter 等過濾器添加到 ApplicationModelProviderContext 里面的 ApplicationModel 里。

DefaultApplicationModelProvider:初始化 ControllerModel, 添加 Controller 相關(guān)的各種信息,添加用戶自定義 Filter,遍歷 ControllerTypes : 創(chuàng)建 ControllerModel --> 初始化Properties --> 初始化Parameters。

CorsApplicationModelProvider:跨域資源相關(guān)邏輯,添加CorsAuthorizationFilterFactory,DisableCorsAuthorizationFilter,CorsAuthorizationFilterFactory,DisableCorsAuthorizationFilter等過濾器。

TempDataApplicationModelProvider: 添加 SaveTempDataPropertyFilterFactory 過濾器,存儲Controller中的TempData信息,注意 TempDataAttribute 修飾的屬性只能是基元類型或字符串。

構(gòu)建ApplicationModel

MVC 框架通過 ControllerActionDescriptorProvider 中的 BuildModel() 這個方法進行 ApplicationModel 的構(gòu)建:

internal protected ApplicationModel BuildModel() {var controllerTypes = GetControllerTypes();var context = new ApplicationModelProviderContext(controllerTypes);for (var i = 0; i < _applicationModelProviders.Length; i++){_applicationModelProviders[i].OnProvidersExecuting(context);}for (var i = _applicationModelProviders.Length - 1; i >= 0; i--){_applicationModelProviders[i].OnProvidersExecuted(context);}return context.Result; }

現(xiàn)在,我們已經(jīng)有一個完整的 ApplicationModel 對象了。

有了 ApplicationModel 對象之后,會再進行一次約定的應(yīng)用。比如以下Action重寫路由的情況或者配置多個路由的情況。

2、ActionDescriptorCollection是怎么創(chuàng)建的?

ControllerActionDescriptor構(gòu)建

ControllerActionDescriptor的構(gòu)建是基于ApplicationModel對象的,下面我就畫了一個流程圖用來展示構(gòu)建 ControllerActionDescriptor 的整個過程,就不過多描述了。

截止到目前,我們會得到一個 IEnumerable<ControllerActionDescriptor> 集合對象。

在有了 ControllerActionDescriptor 之后,ActionDescriptorCollectionProvider 會提供一個屬性,

public ActionDescriptorCollection ActionDescriptors {get{if (_collection == null){UpdateCollection();}return _collection;} }

在這個屬性中使用了 UpdateCollection 這個方法來更新 ActionDescriptorCollection。

private void UpdateCollection() {var context = new ActionDescriptorProviderContext();for (var i = 0; i < _actionDescriptorProviders.Length; i++){_actionDescriptorProviders[i].OnProvidersExecuting(context);}for (var i = _actionDescriptorProviders.Length - 1; i >= 0; i--){_actionDescriptorProviders[i].OnProvidersExecuted(context);}_collection = new ActionDescriptorCollection(new ReadOnlyCollection<ActionDescriptor>(context.Results),Interlocked.Increment(ref _version)); }

OK , 現(xiàn)在我們有了 ActionDescriptorCollection , 之后的流程就比較簡單了,但是會涉及到幾個算法。

接下來,輪到 ActionSelectorDecisionTreeProvider 上場了,它主要是把 ActionDescriptorCollection,組裝成為一個 IActionSelectionDecisionTree 對象以便于后續(xù)的查找匹配工作, IActionSelectionDecisionTree 的數(shù)據(jù)結(jié)構(gòu)是一個多叉樹,組裝過程是使用了一個深度優(yōu)先的遞歸算法。

我們回到起點,繼續(xù)看這張圖:

現(xiàn)在 SelectCandidates 你應(yīng)該能夠看懂了:

public IReadOnlyList<ActionDescriptor> SelectCandidates(RouteContext context) {//IActionSelectionDecisionTree 對象var tree = _decisionTreeProvider.DecisionTree;//使用的是一個多叉樹查找算法,關(guān)于算法可以看我這篇博文://http://www.cnblogs.com/savorboard/p/6582399.htmlreturn tree.Select(context.RouteData.Values); }

接下來就是 SelectBestCandidates 這個流程:

1、遍歷 Action 列表,評估 Action 的相關(guān)約束,返回匹配的 ActionDescriptor 列表。

2、從匹配的 ActionDescriptor 列表中返回最佳的 Action 列表,注意這里這個方法 SelectBestActions,它是一個虛方法,默認是沒有實現(xiàn)的會直接返回上一步的結(jié)果,也就是說用戶可以通過重寫這個方法來自定義一些Action匹配規(guī)則。

3、如果SelectBestActions 返回的是一個ActionDescriptor,則直接返回,當(dāng)路由系統(tǒng)匹配到多個 Action 的時候,那么 MVC 需要從這些 Action 候選者中選中最佳的哪一個,當(dāng)兩個動作通過路由匹配時,MVC必須消除歧義以選擇“最佳”候選者,否則拋出 AmbiguousActionException 異常

最終 SelectBestCandidates 會返回一個 ActionDescriptor ,即需要執(zhí)行的 Action。

后續(xù)流程的執(zhí)行,我又畫了一個圖來表示,希望能夠更加清晰一些:

終于講解結(jié)束了,心好累,如果你認為本篇文章對你有幫助的話,順手點個【推薦】吧。

MvcAttributeRouteHandler:

下面是MvcAttributeRouteHandler的 RouteAsync。

可以看到,在 MvcAttributeRouteHandler 中,少了 SelectCandidates() 這個流程,取而代之的是用 Actions 的屬性參數(shù)。 這個Actions 就比較簡單了,就是MVC框架啟動的時候配置的IRouter Action。

然后就是 SelectBestCandidates 這個流程了,參考上文的流程吧,都一樣。

總結(jié)

本文詳細描述了 MVC 在 Request 到達的時候是怎么樣通過自定義的路由處理程序來選擇一個Action 的,并且講解了其中的過程。

如果你對 .NET Core 感興趣可以關(guān)注我,我會定期在博客分享關(guān)于 .NET Core 的學(xué)習(xí)心得,如果你認為本篇文章對你有幫助的話,謝謝你的【推薦】。


本文地址:http://www.cnblogs.com/savorboard/p/aspnetcore-mvc-routing-action.html
作者博客:Savorboard
歡迎轉(zhuǎn)載,請在明顯位置給出出處及鏈接

轉(zhuǎn)載于:https://www.cnblogs.com/savorboard/p/aspnetcore-mvc-routing-action.html

總結(jié)

以上是生活随笔為你收集整理的ASP.NET Core MVC 源码学习:详解 Action 的匹配的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 黄色一级片一级片 | 日韩中文字幕网址 | 蜜芽一区二区 | julia一区二区三区中文字幕 | 免费观看毛片网站 | 久久不射视频 | 欧洲性生活片 | 亚洲v日韩v综合v精品v | 天天看天天摸天天操 | 中国黄色一级片 | 深夜啪啪 | 国产91丝袜在线播放 | 草视频在线观看 | av卡一卡二| 国产黄网在线观看 | 久久久久久久久久久影院 | 久久精品—区二区三区舞蹈 | 疯狂揉花蒂控制高潮h | 久久中文字幕一区二区 | 国产无套粉嫩白浆内谢 | 在线日韩精品视频 | 人人射人人插 | 91网站在线播放 | 人妻久久久一区二区三区 | 国产va在线 | 狠狠插av | 欧美在线黄 | av一区二区三 | 亚洲一线av | 无码人妻一区二区三区精品视频 | 屁屁影院国产第一页 | 在线观看免费国产视频 | 男男h黄动漫啪啪无遮挡软件 | 色婷婷综合久久久久中文一区二区 | 成人深夜免费视频 | 欧美18一20男同69gay | 插入综合网 | 中文字幕一区二区三区日韩精品 | 色www国产亚洲阿娇 自拍一区在线 | 性xxxx欧美老肥妇牲乱 | 精品少妇人妻av一区二区三区 | 欧美亚洲国产一区 | 午夜国产一级 | 欧美伊人影院 | 91国产一区二区 | 风韵丰满熟妇啪啪区老熟熟女 | 国产精品久久久网站 | 日韩成人av一区 | 91av视频免费观看 | 91免费视频网站 | 草久久久久 | 青青草原一区二区 | 亚洲一级二级 | 欧美一本 | 粉嫩欧美一区二区三区 | 欧美做受喷浆在线观看 | 女人扒开腿让男人桶爽 | 国产高清二区 | 欧美色激情 | 91爱爱爱| 国产一区二区三区色淫影院 | 温柔女教师在线观看 | 欧美性色a | 欧美综合亚洲 | 国产在线观看h | 人妻无码久久精品人妻 | 中国免费一级片 | 欧美大片在线免费观看 | 亚洲国产精品视频一区 | 成年人在线免费观看网站 | 日韩久久电影 | 欧美视频免费看欧美视频 | 成年人免费观看视频网站 | 日韩中文字幕免费 | 青青草免费在线观看视频 | 国产真人做爰毛片视频直播 | 欧美综合自拍 | www.久久久久久久久 | 日韩激情一区二区三区 | www.欧美精品 | 99热免费精品 | 成人欧美一区二区三区在线观看 | 在线观看国产小视频 | 日本黄视频在线观看 | 天天爱夜夜操 | 国产色爽 | 男女免费看 | 国产最新在线 | 亚洲午夜精品一区二区三区 | 欧美乱插 | 男插女av| 高清av免费| 中文字幕观看在线 | 18男女无套免费视频 | 国产精品午夜未成人免费观看 | 无码人妻aⅴ一区二区三区69岛 | 国产麻豆乱码精品一区二区三区 | 日本一区二区三区免费电影 | 在线三级av |