asp.net攔截器


攔截器又稱過濾器。

asp.net mvc本身是自帶3種攔截器:Action攔截器、Result攔截器、Exception攔截器。 應用中常見的攔截器有日志攔截器(Action攔截器)和異常處理攔截器(Exception攔截器)。

java里spring mvc也常用攔截器來做些非干預業務邏輯的事,諸如實現HandlerInterceptor接口。

 

攔截器是AOP(面向切面編程)的一種應用。

攔截器要解決的問題:

1.代碼復用。攔截器可被復用
2.職責單一。比如廚師只負責炒菜,不管前期的洗菜、后續的送菜工作。菜變質了也是直接喊一聲就有人來處理。
 
asp.net的攔截器怎么實現呢?
舊瓶裝新酒,asp.net的攔截器需要通過IHttpModule接口來實現。
 

這兩天重構支付中心代碼,將設置線程名和IP白名單這2個功能做成攔截器。
 
如下是線程名Filter的代碼:
    /// <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后訪問接口所記錄的日志:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM