一
攔截器又稱過濾器。
asp.net mvc本身是自帶3種攔截器:Action攔截器、Result攔截器、Exception攔截器。 應用中常見的攔截器有日志攔截器(Action攔截器)和異常處理攔截器(Exception攔截器)。
java里spring mvc也常用攔截器來做些非干預業務邏輯的事,諸如實現HandlerInterceptor接口。
攔截器是AOP(面向切面編程)的一種應用。
攔截器要解決的問題:
二
/// <summary> /// 設置當前工作線程的名稱。供用來統一標識記錄的日志 /// </summary> public class ThreadNameFilter : IHttpModule { LogHelperUtil logHelper = new LogHelperUtil(typeof(ThreadNameFilter).Name); public void Dispose() { //throw new NotImplementedException(); } public void Init(HttpApplication context) { //NewMethod(context);請求在此上下文中不可用 context.BeginRequest += context_BeginRequest; } /// <summary> /// 設置當前工作線程的name /// </summary> /// <param name="sender"></param> private void SetThreadName(object sender) { if (null != Thread.CurrentThread.Name) { return; } HttpApplication application = (HttpApplication)sender; HttpRequest request2 = application.Context.Request; HttpResponse response = application.Context.Response; string url = request2.Url.LocalPath; url = url.Trim('/'); // * 根據請求url得到一個nameFlag string nameFlag; if (url.IndexOf(".ashx", StringComparison.OrdinalIgnoreCase) > 0) { var arr = url.Split('/'); string ashxName = arr.FirstOrDefault(str => str.IndexOf(".ashx", StringComparison.OrdinalIgnoreCase) > 0); nameFlag = ashxName.Substring(0, ashxName.IndexOf('.')); if (nameFlag == "AgentPayQuery") { nameFlag = "QueryAgentPay"; } } else { nameFlag = url.Replace('/', '_').Replace('.', '_'); } // * 設置當前工作線程的name Thread.CurrentThread.Name = string.Format("[{0}_T{1:HHmmssfff}_{2}]", nameFlag, DateTime.Now, Guid.NewGuid().ToString().Replace("-", "").Substring(0, 5).ToUpper()); logHelper.Write("線程名已設置為:{0} url:{1}", Thread.CurrentThread.Name, url); } void context_BeginRequest(object sender, EventArgs e) { SetThreadName(sender); } }
接下來,web.config配置此module:
可在<system.web>節點下的<httpModules>里配置,也可在<system.webServer>節點下的<modules>里配置。 這取決於應用程序池的托管管道模式。經典模式用前者,集成模式用后者。
本地vs2013里的iisexpress默認是集成模式。所以,本地vs2013調試程序要在<system.webServer>里配置module。
<system.webServer> <modules> <!--runAllManagedModulesForAllRequests="true"--> <add name="threadNameFilter" type="PaymentPlatform.Filters.ThreadNameFilter" preCondition="managedHandler" /> <add name="ipValidationInterceptor" type="PaymentPlatform.Filters.IPValidationInterceptor" preCondition="managedHandler"/> <!--只對托管資源起作用--> </modules> <handlers> 。。。。。。 </handlers> </system.webServer>
這樣,一個攔截器的開發就完成了。
在后續的測試時,出現了一些波折。
本地在啟動vs2013執行iisexpress站點應用程序時,發現明明在ThreadNameFilter 里設置了線程名,但觀察在后續ashx里記錄的日志里,並沒有獲取到那個線程名,whatever in Debug or in Release。這讓我想到之前寫的一篇博客《巧用CurrentThread.Name來統一標識日志記錄(續)》,在ashx文件的默認構造器里設置的線程名,在其ProcessRequest方法的處理邏輯里也是獲取不到的。
經多次鼓搗,才發現,把站點程序發布到IIS7上之后,無論apppool的托管模式是集成(目前,集成模式是主流)還是經典,在ThreadNameFilter 里設置的線程名可以被后續ashx里獲取到!
同樣,細心的觀察了一下,《巧用CurrentThread.Name來統一標識日志記錄(續)》里提到的問題,發布到IIS7后也不存在,即在ashx文件的默認構造器里設置的線程名,在其ProcessRequest方法的處理邏輯里可以獲取到!
下圖是本地vs2013里訪問接口所記錄的日志:
下圖是發布到iis7后訪問接口所記錄的日志: