欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > ASP.NET MVC:Filter和Action的執行介紹

ASP.NET MVC:Filter和Action的執行介紹

熱門標簽:蘇州銷售外呼系統預算 太原外呼電銷機器人費用 東莞語音電銷機器人排名 外呼系統用員工身份證 使用智能電話機器人違法嗎 電話機器人廣告話術 保山電話外呼管理系統怎么用 淘寶地圖標注如何做 朝陽市地圖標注

根據controller的名字正確的實例化了一個controller對象。回到MVCHandler的BeginProcessRequest方法,可以看到,當得到controller對象之后,首先判斷它是不是IAsyncController,如果是則會創建委托用來異步執行。通常情況下,我們都是繼承自Controller類,這不是一個IAsyncController,于是會直接執行Controller的Execute方法。Execute方法是在Controller的基類ControllerBase中定義的,這個方法除去一些安全檢查,初始化了ControllerContext(包含了ControllerBase和Request的信息),核心是調用了ExecuteCore方法,這在ControllerBase是個抽象方法,在Controller類中有實現:

復制代碼 代碼如下:

protected override void ExecuteCore() {
PossiblyLoadTempData();
try {
string actionName = RouteData.GetRequiredString("action");
if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
HandleUnknownAction(actionName);
}
}
finally {
PossiblySaveTempData();
}}

這個方法比較簡單,首先是加載臨時數據,這僅在是child action的時候會出現,暫不討論。接下來就是獲取action的名字,然后InvokeAction, 這里的ActionInvoker是一個ControllerActionInvoker類型的對象,我們來看它的InvokeAction方法,
復制代碼 代碼如下:

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName) {
if (controllerContext == null) {
throw new ArgumentNullException("controllerContext");
}
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);
if (actionDescriptor != null) {
FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
try {
AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
if (authContext.Result != null) {
// the auth filter signaled that we should let it short-circuit the request
InvokeActionResult(controllerContext, authContext.Result);
}
else {
if (controllerContext.Controller.ValidateRequest) {
ValidateRequest(controllerContext);
}
IDictionarystring, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);
InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);
}
}
catch (ThreadAbortException) {
// This type of exception occurs as a result of Response.Redirect(), but we special-case so that
// the filters don't see this as an error.
throw;
}
catch (Exception ex) {
// something blew up, so execute the exception filters
ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled) {
throw;
}
InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}
// notify controller that no method matched
return false;}

這是一個非常核心的方法,有很多工作在這里面完成。ASP.NET MVC中有幾個以Descriptor結尾的類型,首先獲得ControllerDescriptor,這個比較簡單,實際返回的是ReflectedControllerDescriptor對象。第二步實際上是調用了ReflectedControllerDescriptor的FindAction方法,獲得ActionDescriptor,ActionDescriptor最重要的屬性是一個MethodInfo,這就是當前action name對應的Action的方法。FindAction方法內部實際上是調用了ActionMethodSelector的FindActionMethod來獲得MethodInfo,可以想象,這個方法將會反射controller的所有方法的名字,然后和action name匹配,實際上,ASP.NET還支持一些額外的功能,主要是: 1.通過ActionNameAttribute屬性重命名action的名字;2.支持ActionMethodSelectorAttribute對action方法進行篩選,比如[HttpPost]之類的。下面簡單看下ActionMethodSelector的實現,大致分為4步,首先是在構造函數中調用了如下方法反射controller中的所有action方法:
復制代碼 代碼如下:

private void PopulateLookupTables() {
MethodInfo[] allMethods = ControllerType.GetMethods(BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);
MethodInfo[] actionMethods = Array.FindAll(allMethods, IsValidActionMethod);
AliasedMethods = Array.FindAll(actionMethods, IsMethodDecoratedWithAliasingAttribute);
NonAliasedMethods = actionMethods.Except(AliasedMethods).ToLookup(method => method.Name, StringComparer.OrdinalIgnoreCase);
}FindActionMethod方法如下:
public MethodInfo FindActionMethod(ControllerContext controllerContext, string actionName) {
ListMethodInfo> methodsMatchingName = GetMatchingAliasedMethods(controllerContext, actionName);
methodsMatchingName.AddRange(NonAliasedMethods[actionName]);
ListMethodInfo> finalMethods = RunSelectionFilters(controllerContext, methodsMatchingName);
switch (finalMethods.Count) {
case 0:
return null;
case 1:
return finalMethods[0];
default:
throw CreateAmbiguousMatchException(finalMethods, actionName);
} }

這個方法是很清晰的,找到重命名之后符合的,本身名字符合的,然后所有的方法判斷是否滿足ActionMethodSelectorAttribute的條件,最后或者返回匹配的MethodInfo,或者拋出異常,或者返回null。三個步驟的實現并不困難,不再分析下去。
第三步是得到Filter。 FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);實際調用的是:
FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor);這里的代碼風格和之前的不太一樣,特別喜歡用各種委托,讀代碼有點困難,估計不是同一個人寫的。下面的分析都直接給出實際執行的代碼。首先看下FilterProvider的構造函數:
復制代碼 代碼如下:

static FilterProviders() {
Providers = new FilterProviderCollection();
Providers.Add(GlobalFilters.Filters);
Providers.Add(new FilterAttributeFilterProvider());
Providers.Add(new ControllerInstanceFilterProvider());
}

回憶下ASP.NET給Action加上filter的方法一共有如下幾種:
1. 在Application_Start注冊全局filter
2. 通過屬性給Action方法或者Controller加上filter
3. Controller類本身也實現了IActionFilter等幾個接口。通過重寫Controller類幾個相關方法加上filter。
這三種方式就對應了三個FilterProvider,這三個Provider的實現都不是很困難,不分析了。到此為止,準備工作都好了,接下來就會執行Filter和Action,ASP.NET的Filter一共有4類:


Filter Type Interface Description
Authorization IAuthorizationFilter Runs first
Action IActionFilter Runs before and after the action method
Result IResultFilter Runs before and after the result is executed
Exception IExceptionFilter Runs if another filter or action method throws an exception
下面看其源代碼的實現,首先就是InvokeAuthorizationFilters:
復制代碼 代碼如下:

protected virtual AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IListIAuthorizationFilter> filters, ActionDescriptor actionDescriptor) {
AuthorizationContext context = new AuthorizationContext(controllerContext, actionDescriptor);
foreach (IAuthorizationFilter filter in filters) {
filter.OnAuthorization(context);
if (context.Result != null) {
break;
}
}
return context;}

注意到在實現IAuthorizationFilter接口的時候,要表示驗證失敗,需要在OnAuthorization方法中將參數context的Result設置為ActionResult,表示驗證失敗后需要顯示的頁面。接下來如果驗證失敗就會執行context的Result,如果成功就要執行GetParameterValues獲得Action的參數,在這個方法內部會進行Model Binding,這也是ASP.NET的一個重要特性,另文介紹。再接下來會分別執行InvokeActionMethodWithFilters和InvokeActionResultWithFilters,這兩個方法的結構是類似的,只是一個是執行Action方法和IActionFilter,一個是執行ActionResult和IResultFilter。以InvokeActionMethodWithFilters為例分析下:
復制代碼 代碼如下:

protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IListIActionFilter> filters, ActionDescriptor actionDescriptor, IDictionarystring, object> parameters) {
ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
FuncActionExecutedContext> continuation = () =>
new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {
Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
// need to reverse the filter list because the continuations are built up backward
FuncActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
(next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
return thunk();
}

這段代碼有點函數式的風格,不熟悉這種風格的人看起來有點難以理解。 用函數式編程語言的話來說,這里的Aggregate其實就是foldr,
foldr::(a->b->b)->b->[a]->b
foldr 接受一個函數作為第一個參數,這個函數的參數有兩個,類型為a,b,返回類型為b,第二個參數是類型b,作為起始值,第三個參數是一個類型為a的數組,foldr的功能是依次將數組中的a 和上次調用第一個參數函數(f )的返回值作為f的兩個參數進行調用,第一次調用f的時候用起始值。對于C#來說,用面向對象的方式表示,是作為IEnummerable的一個擴展方法實現的,由于C# 不能直接將函數作為函數的參數傳入,所以傳入的是委托。說起來比較拗口,看一個例子:
復制代碼 代碼如下:

static void AggTest()
{
int[] data = { 1, 2, 3, 4 };
var res = data.Aggregate("String", (str, val) => str + val.ToString());
Console.WriteLine(res);
}

最后輸出的結果是String1234. 回到InvokeActionMethodWithFilters的實現上來,這里對應的類型a是IActionFilter,類型b是FuncActionExecutedContext>,初始值是continuation。假設我們有3個filter,[f1,f2,f3],我們來看下thunk最終是什么,
第一次: next=continue, filter=f1, 返回值 ()=>InvokeActionMethodFilter(f1, preContext, continue)
第二次:next=()=>InvokeActionMethodFilter(f1, preContext, continue), filter=f2
返回值:()=>InvokeActionMethodFilter(f2, preContext,()=> InvokeActionMethodFilter(f1, preContext, continue)),
最終: thunk= ()=>InvokeActionMethodFilter(f3,preContext,()=>InvokeActionMethodFilter(f2, preContext, ()=>InvokeActionMethodFilter(f1, preContext, continue)));
直到 return thunk()之前,所有真正的代碼都沒有執行,關鍵是構建好了thunk這個委托,把thunk展開成上面的樣子,應該比較清楚真正的調用順序什么樣的了。這里花了比較多的筆墨介紹了如何通過Aggregate方法構造調用鏈,這里有一篇文章專門介紹了這個,也可以參考下。想象下,如果filter的功能就是先遍歷調用f的Executing方法,然后調用Action方法,最后再依次調用f的Executed方法,那么完全可以用迭代來實現,大可不必如此抽象復雜,關鍵是ASP.NET MVC對于filter中異常的處理還有一些特殊之處,看下InvokeActionMethodFilter的實現:
復制代碼 代碼如下:

internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, FuncActionExecutedContext> continuation) {
filter.OnActionExecuting(preContext);
if (preContext.Result != null) {
return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true /* canceled */, null /* exception */) {
Result = preContext.Result
};
}
bool wasError = false;
ActionExecutedContext postContext = null;
try {
postContext = continuation();
}
catch (ThreadAbortException) {
// This type of exception occurs as a result of Response.Redirect(), but we special-case so that
// the filters don't see this as an error.
postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, null /* exception */);
filter.OnActionExecuted(postContext);
throw;
}
catch (Exception ex) {
wasError = true;
postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, ex);
filter.OnActionExecuted(postContext);
if (!postContext.ExceptionHandled) {
throw;
}
}
if (!wasError) {
filter.OnActionExecuted(postContext);
}
return postContext;
}

代碼有點長,首先就是觸發了filter的OnActionExecuting方法,這是方法的核心。接下來的重點是 postContext = continuation(); 最后是OnActionExecuted方法,結合上面的展開式,我們可以知道真正的調用順序將是:
復制代碼 代碼如下:

f3.Executing->f2.Executing->f1.Exectuing->InvokeActionMethod->f1.Executed->f2->Executed->f3.Executed.

那么,源代碼中的注釋 // need to reverse the filter list because the continuations are built up backward 的意思也很明了了。需要將filter倒序排一下之后才是正確的執行順序。
還有一類filter是當異常發生的時候觸發的。在InvokeAction方法中可以看到觸發它的代碼放在一個catch塊中。IExceptionFilter的觸發流程比較簡單,不多做解釋了。唯一需要注意的是ExceptionHandled屬性設置為true的時候就不會拋出異常了,這個屬性在各種context下面都有,他們是的效果是一樣的。比如在OnActionExecuted方法中也可以將他設置為true,同樣不會拋出異常。這些都比較簡單,不再分析其源代碼,這篇文章比較詳細的介紹了filter流程中出現異常之后的執行順序。
最后說下Action Method的執行,前面我們已經得到了methodInfo,和通過data binding獲得了參數,調用Action Method應該是萬事俱備了。asp.net mvc這邊的處理還是比較復雜的,ReflectedActionDescriptor會去調用ActionMethodDispatcher的Execute方法,這個方法如下:
復制代碼 代碼如下:

public object Execute(ControllerBase controller, object[] parameters) {
return _executor(controller, parameters);
}

此處的_executor是
delegate object ActionExecutor(ControllerBase controller, object[] parameters);_exectuor被賦值是通過一個方法,利用Expression拼出方法體、參數,代碼在(ActionMethodDispatcher.cs):
static ActionExecutor GetExecutor(MethodInfo methodInfo)此處就不貼出了,比較復雜。這里讓我比較費解的是,既然MethodInfo和parameters都有了,直接用反射就可以了,為什么還要如此復雜,我將上面的Execute方法改為:
復制代碼 代碼如下:

public object Execute(ControllerBase controller, object[] parameters) {
return MethodInfo.Invoke(controller, parameters);
//return _executor(controller, parameters);
}

運行結果是完全一樣的。我相信mvc源代碼如此實現一定有其考慮,這個需要繼續研究。
最后附上一張函數調用圖,以便理解,僅供參考。圖片較大,點擊可看原圖。


您可能感興趣的文章:
  • ASP.NET MVC中URL地址傳參的兩種寫法
  • 解讀ASP.NET 5 & MVC6系列教程(10):Controller與Action
  • asp.net mvc-Controllerl篇 ControllerDescriptor
  • 詳解ASP.NET MVC下的異步Action的定義和執行原理
  • ASP.NET MVC使用ActionFilterAttribute實現權限限制的方法(附demo源碼下載)
  • asp.net MVC利用ActionFilterAttribute過濾關鍵字的方法
  • 使用ASP.NET MVC 4 Async Action+jQuery實現消息通知機制的實現代碼
  • asp.net MVC實現無組件上傳圖片實例介紹
  • ASP.NET MVC DropDownList數據綁定及使用詳解
  • ASP.NET MVC 控制器與視圖
  • ASP.NET實現MVC中獲取當前URL、controller及action的方法

標簽:運城 呼倫貝爾 潛江 阿里 洛陽 克拉瑪依 綏化 西藏

巨人網絡通訊聲明:本文標題《ASP.NET MVC:Filter和Action的執行介紹》,本文關鍵詞  ASP.NET,MVC,Filter,和,Action,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《ASP.NET MVC:Filter和Action的執行介紹》相關的同類信息!
  • 本頁收集關于ASP.NET MVC:Filter和Action的執行介紹的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    国产精品网站在线播放| 午夜精品福利在线| 国产传媒日韩欧美成人| 91精品人妻一区二区三区蜜桃欧美| 欧美日韩中文字幕一区二区| 国产精品对白交换视频| 国产精品 日产精品 欧美精品| 免费网站在线高清观看| 26uuu国产在线精品一区二区| 日韩电影在线免费看| 制服丝袜第一页在线观看| 欧美日韩成人综合在线一区二区| 亚洲制服欧美中文字幕中文字幕| 91丨porny丨在线| 欧洲激情一区二区| 一区二区三区在线播放| 女人扒开腿免费视频app| 欧美性猛交xxxx黑人交| 亚洲精品成人少妇| 少妇极品熟妇人妻无码| 欧美卡1卡2卡| 日本一区中文字幕| 亚洲成人网在线播放| 久久中文字幕电影| 国产精品正在播放| 四虎永久免费在线| 亚洲色图视频网| 潘金莲一级淫片aaaaa| 欧美日韩aaaaaa| 日韩va欧美va亚洲va久久| 黄色在线观看av| 久久麻豆一区二区| 国产精品一品二品| 色吧成人激情小说| 亚洲电影第三页| 国产吞精囗交久久久| 欧美精品一区二区高清在线观看| 国产乱子伦视频一区二区三区| 欧美一级片在线视频| 亚洲欧美一区二区三区孕妇| 中文写幕一区二区三区免费观成熟| 在线成人小视频| 久久国产综合精品| 国产成人av免费在线观看| 亚洲黄色免费网站| 在线黄色免费网站| 久久综合九色综合97婷婷| 丁香另类激情小说| 欧美日韩aaa| 狠狠色丁香久久婷婷综合丁香| 国产美女久久久久久| 一区二区三区四区激情| 欧美精品欧美极品欧美激情| 久久久国产精品麻豆| 99视频一区二区三区| 69久久99精品久久久久婷婷| 国模套图日韩精品一区二区 | 色成人在线视频| 日韩国产高清在线| 中文乱码字幕高清一区二区| 亚洲精品视频在线| 国产高清一区二区三区四区| 国产精品成人一区二区三区夜夜夜| 性折磨bdsm欧美激情另类| 精品国产一区二区三区av性色 | 日韩精品一区二区三区中文不卡 | 蜜桃视频免费观看一区| 日韩三级久久久| 亚洲一区二区三区四区在线免费观看 | 成人精品视频网站| 91精品啪在线观看国产60岁| 国产激情视频一区二区在线观看| 欧美三电影在线| 精品夜夜嗨av一区二区三区| 在线精品视频免费观看| 久久精品久久99精品久久| 一本大道久久a久久综合| 美国av一区二区| 欧美在线制服丝袜| 国产一区二区久久| 91精品国产美女浴室洗澡无遮挡| 成人做爰69片免费看网站| 欧美一区二区私人影院日本| 国产99久久久国产精品潘金网站| 欧美一区二区成人6969| 波多野结衣的一区二区三区| 欧美本精品男人aⅴ天堂| 91麻豆视频网站| 国产欧美日韩综合精品一区二区| 蜜臀视频在线观看| 亚洲图片激情小说| 欧美aaa级片| 秋霞午夜鲁丝一区二区老狼| 欧美在线三级电影| 风间由美中文字幕在线看视频国产欧美| 欧美一区三区四区| 99re热这里只有精品视频| 337p日本欧洲亚洲大胆精品| 国产精品手机在线观看| 亚洲精品免费一二三区| 中文字幕第69页| 免费的成人av| 91精品国产综合久久久久久久久久 | 国产精品综合网| 日韩视频一区二区三区| av地址在线观看| 综合自拍亚洲综合图不卡区| 欧美老女人性生活视频| 免费av成人在线| 欧美美女网站色| 91免费看`日韩一区二区| 国产精品欧美一区二区三区| 国产真人做爰视频免费| 蜜臀99久久精品久久久久久软件| 欧美日韩免费电影| 免费人成视频在线播放| 亚洲欧美一区二区三区极速播放 | 久久99精品国产麻豆不卡| 欧美一二三在线| av av在线| 亚洲成a人片在线不卡一二三区 | 91国偷自产一区二区开放时间| 国产成人精品综合在线观看| 国产亚洲精品aa午夜观看| 国产熟女一区二区| 精品一区二区在线看| 精品国产伦一区二区三区免费| 国产ts丝袜人妖系列视频 | 亚洲综合激情网| 91成人在线观看喷潮| av不卡免费在线观看| 国产精品视频线看| h色网站在线观看| 暴力调教一区二区三区| 日韩伦理电影网| 欧美伊人精品成人久久综合97| 91蜜桃在线观看| 亚洲午夜激情网页| 欧美精品一级二级三级| 在线免费播放av| 免费xxxx性欧美18vr| 精品国产乱码91久久久久久网站| 免费一级做a爰片久久毛片潮| 捆绑紧缚一区二区三区视频| 欧美精品一区二区高清在线观看| 欧美aaa级片| 成人网页在线观看| 亚洲精品国产a久久久久久| 欧美另类videos死尸| 亚洲第一黄色网址| 免费在线看成人av| 欧美精品一区二区三区四区 | www.综合网.com| 一区二区三区在线高清| 欧美猛男超大videosgay| 久久中文字幕人妻| 国产麻豆一精品一av一免费| 中文字幕不卡在线观看| 色婷婷久久久亚洲一区二区三区| 国产chinesehd精品露脸| 视频一区视频二区在线观看| 欧美mv日韩mv国产网站| 国产农村妇女精品一区| 不卡高清视频专区| 午夜成人在线视频| 久久婷婷久久一区二区三区| 久久精品一区二区三区四区五区| 99精品视频在线免费观看| 97久久超碰国产精品| 欧美精品一区二区三区四区| 黄色录像二级片| 成人啪啪18免费游戏链接| 人禽交欧美网站| 国产精品欧美精品| 欧美日韩国产综合一区二区 | 麻豆专区一区二区三区四区五区| 国产无一区二区| 91国产免费看| 国产免费看av| caoporn国产一区二区| 日韩综合小视频| 日本一区二区不卡视频| 欧美日韩成人综合在线一区二区| 人妻少妇无码精品视频区| 99久久精品免费看国产| 强制捆绑调教一区二区| 亚洲欧洲在线观看av| 欧美一二区视频| 久久精品黄色片| 国产精品九九九九九| 99久久久精品免费观看国产蜜| 奇米影视7777精品一区二区| 亚洲啪啪综合av一区二区三区| 精品日韩一区二区三区免费视频| 午夜国产福利一区二区| 国产中文字幕一区二区| 成熟亚洲日本毛茸茸凸凹| 琪琪一区二区三区| 一区二区三区四区乱视频| 国产女同互慰高潮91漫画|