ASP.NET MVC5基礎-過濾器(Filters)詳解

来源:https://www.cnblogs.com/aoede-jacqueline/archive/2019/12/05/mvc-filters.html
-Advertisement-
Play Games

什麼是過濾器? 過濾器的類型與作用 定義過濾器 授權過濾器 動作過濾器 結果過濾器 異常處理過濾器 過濾器的使用方法 總結 什麼是過濾器? 通過上一篇關於Controller控制器的文章我們知道,MVC中的每一個請求,都會分配給相應的控制器(Controller)和對應的行為方法(Action)去處 ...


什麼是過濾器?

通過上一篇關於Controller控制器的文章我們知道,MVC中的每一個請求,都會分配給相應的控制器(Controller)和對應的行為方法(Action)去處理,那麼如果我們想要在Action處理的前後加上一些額外的處理邏輯怎麼辦呢?這時候就用到了過濾器(Filters)。

在ASP.NET MVC的請求處理過程中有19個管道事件,這些事件分佈在請求處理的各個節點中,比如BeginRequest(開始處理請求時觸發)、AuthenticateRequest(對請求進行身份驗證時觸發)、AuthorizeRequest(對請求進程授權時觸發)…等等等等。而過濾器的主要作用就是將我們的附加邏輯註入到這些請求處理管道中。

在實際業務中,在Action方法前後添加額外附加邏輯的情況有很多,過濾器就是用來完成此功能。通過過濾器可以將與業務邏輯無關但經常需要執行的代碼分離開,使我們的代碼邏輯性更加清晰,代碼更加簡潔。

過濾器的類型與作用

MVC給我們提供了四種過濾器,基本滿足了我們實際業務中常用的需求,包括以下:

過濾器類型名稱

實現的介面

預設的實現類

作用

執行的順序與節點

授權過濾器

IAuthorizationFilter

AuthorizeAttribute

用於限制進入控制器或控制器的某個行為方法

在控制器方法調用前執行,所有過濾器中最先執行的

動作過濾器

IActionFilter

ActionFilterAttribute

用於進入動作方法之前或之後的處理

在控制器方法調用前/後執行

結果過濾器

IResultFilter

ActionFilterAttribute

用於動作方法返回結果之前或之後的處理

在控制器方法調用完,跳轉至view頁面前/後執行

異常處理過濾器

IExceptionFilter

HandleErrorAttribute

用於處理某個動作方法或某個控制器裡面拋出的異常

在控制器方法拋出異常時執行

這四種類型的介面是MVC對過濾器的一個介面規範,同時MVC預設通過AuthorizeAttribute(授權)、HandleErrorAttribute(異常處理)、ActionFilterAttribute(動作和結果)三個類實現了這四個介面。

需要註意的是ActionFilterAttribute類既實現了IActionFilter介面,也實現了IResultFilter介面。這是個抽象類,要求必須提供一個實現,AuthorizeAttribute和HandleErrorAttribute類則包含了一些有用的特性,可以不必創建派生類進行使用。所以我們一般都會通過繼承ActionFilterAttribute類,實現自定義的過濾器。

除以上介面之外,我們還要用到FilterAttribute類,這個類將我們的過濾器包裝成了特性,使我們的過濾器可以方便的在Action方法上方使用。

定義過濾器

過濾器有以下幾個特點:

  • 可用於動作方法(Action)

  • 可用於控制器(Controller)

  • 可多個Filter同時使用

  • 不同級別可以混搭

  • 可運用於基類的過濾器,會影響該基類的所有派生類

下麵我們逐一介紹下基本過濾器的使用方法。

授權過濾器

所有實現了IAuthorizationFilter介面的都可以稱之為授權過濾器。它的介面定義如下:

namespace System.Web.Mvc
{
    //
    // 摘要:
    //     定義授權篩選器所需的方法。
    public interface IAuthorizationFilter
    {
        //
        // 摘要:
        //     在需要授權時調用。
        //
        // 參數:
        //   filterContext:
        //     篩選器上下文。
        void OnAuthorization(AuthorizationContext filterContext);
    }
}

授權過濾器是最先運行的過濾器,它運行在其它過濾器和Action方法之前。客戶端請求在調用Action之前,MVC框架會檢測Action上是否有授權過濾器,如果有會調用OnAuthorization方法,如果此方法批准了請求,才會調用相應的Action。流程如圖:

MVC預設使用AuthorizeAttribute實現了IAuthorizationFilter介面,所以我們可以在Action方法上直接添加Authorize特性標簽來驗證授權:

打開Index頁面,會顯示無許可權:

由於使用的是MVC自帶的授權驗證方法,未能符合它的驗證機制,所以無許可權查看。通常我們需要添加一個新的派生自AuthorizeAttribute類的授權過濾器來完成我們自己業務邏輯。

下麵我們自定義一個授權過濾器。我們在MVC項目中添加一個Filters文件夾,我們所有自定義的過濾器都可以放到這個文件夾下,便於管理。

在Filters下創建一個類,類名為MyAuthorizeAttribute。需要註意,過濾器要以Attribute結尾,這是MVC的約定。代碼如下:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    //重寫授權檢查方法,返回值為true,允許訪問,false,禁止訪問。
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        //請求參數user為空,禁止訪問
        if (string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["user"]))
        {
            return false;
        }
        return true;
    }
}

可以看到,我們只要重寫AuthorizeCore方法就可以根據我們的業務需求判斷是否有許可權訪問,返回值為true允許訪問,返回值為false禁止訪問。

回到HomeController,我們給About方法加上我們自定義的特性:

我們看看效果:

可以看到,當About頁面沒有user參數時,會提示無許可權,有user參數則可以訪問通過。

在實際業務中我們可以使用授權過濾器來管理用戶登錄狀態的授權驗證。當然,我的這個例子只是基礎的用法,實際業務比這複雜的多,那麼就需要我們自己去思考設計授權過濾器方法了。

動作過濾器

動作過濾器需要實現IActionFilter介面,介面定義如下:

//
// 摘要:
//     定義操作篩選器中使用的方法。
public interface IActionFilter
{
    //
        // 摘要:
        //     在執行操作方法後調用。
        //
        // 參數:
        //   filterContext:
        //     篩選器上下文。
        void OnActionExecuted(ActionExecutedContext filterContext);
    //
        // 摘要:
        //     在執行操作方法之前調用。
        //
        // 參數:
        //   filterContext:
        //     篩選器上下文。
        void OnActionExecuting(ActionExecutingContext filterContext);
}

我們看到該介面里有兩個方法OnActionExecuting和OnActionExecuted,前者在動作方法執行前調用,後者在動作方法執行後調用。

OnActionExecuting方法是在Action方法執行前調用的,那麼我們可以利用這個方法來檢測請求,並且可以在這裡修改請求,取消請求等等操作。

OnActionExecuting方法的參數是一個ActionExecutingContext對象,它繼承自ControllerContext類,屬性如下:

名稱

類型

說明

ActionDescriptor

ActionDescriptor

獲取或設置操作描述符。

ActionParameters

IDictionary<string, object>

獲取或設置操作方法參數。

Result

ActionResult

獲取或設置由操作方法返回的結果。

我們添加一個自定義的Action過濾器。由於ActionFilterAttribute類實現了IActionFilter介面,所以我們直接繼承ActionFilterAttribute類即可,並且重寫OnActionExecuting和OnActionExecuted方法。如下:

public class MyActionAttribute : ActionFilterAttribute
{
    /// <summary>
    /// Action調用之前運行
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (string.Equals(filterContext.HttpContext.Request.HttpMethod, "get", StringComparison.CurrentCultureIgnoreCase))
        {
            filterContext.Result = new HttpNotFoundResult("只允許POST請求!");
        }
    }
    /// <summary>
    /// Action調用之後運行
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {

    }
}

我們給Index方法添加上MyAction特性標簽:

打開Index頁,顯示如下:

可以看到,頁面返回了404錯誤,提示信息為我們設置的Message。

OnActionExecuted方法在Action操作方法調用之後執行,傳遞給OnActionExecuted方法的參數是ActionExecutedContext對象。這個類比ActionExecutingContext對象多了些屬性,如下:

名稱

類型

說明

ActionDescriptor

ActionDescriptor

獲取或設置操作描述符。

Canceled

bool

獲取或設置一個值,該值指示此ActionExecutedContext 對象已被取消。

Exception

Exception

獲取或設置在操作方法的執行過程中發生的異常(如果有)。

ExceptionHandled

bool

獲取或設置一個值,該值指示是否處理異常。

Result

ActionResult

獲取或設置由操作方法返回的結果。

我們可以通過OnActionExecuted方法來執行一些跨越動作方法的任務,比如我們可以用它來獲取動作方法執行的時間。我們修改 MyActionAttribute 過濾器代碼如下:

public class MyActionAttribute : ActionFilterAttribute
{
    private Stopwatch timer;

    /// <summary>
    /// Action調用之前運行
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        timer = Stopwatch.StartNew();
    }
    /// <summary>
    /// Action調用之後運行
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        timer.Stop();
        filterContext.HttpContext.Response.Write($"<div>方法執行時間:{timer.Elapsed.TotalSeconds:F6}s</div>");
    }
}

我們在方法啟動之前啟動了一個計時器,在方法執行後停止了它,並且將這個時間間隔輸出到我們的頁面上。重新編譯打開Index頁面,顯示如下:

結果過濾器

結果過濾器,顧名思義針對的是動作方法返回的結果,它在我們的動作方法結果返回前後執行。

創建結果過濾器需要實現IResultFilter介面。ActionFilterAttribute類幫我們實現了IResultFilter介面,我們可以直接繼承ActionFilterAttribute創建我們的過濾器,然後通過重寫OnResultExecutin和OnResultExecuting(在執行操作結果後調用)方法來實現過濾器規則。

OnResultExecuting方法會在執行操作結果前調用,這個方法的參數是一個ResultExecutingContext對象,屬性如下:

名稱

類型

說明

Cancel

bool

獲取或設置一個值,該值指示此 ResultExecutingContext 值是否為“cancel”。

Result

ActionResult

獲取或設置操作結果。

OnResultExecuted方法在執行操作結果後調用,這個方法的參數是一個ResultExecutingContext對象,屬性如下:

名稱

類型

說明

Canceled

bool

獲取或設置一個值,該值指示此 ResultExecutingContext 值是否為“cancel”。

Exception

Exception

獲取或設置在操作方法的執行過程中發生的異常(如果有)。

ExceptionHandled

bool

獲取或設置一個值,該值指示是否處理異常。

Result

ActionResult

獲取或設置操作結果。

我們可以使用這兩個方法在Action方法返回結果前後進行操作,具體操作的代碼我就不贅述了。

異常處理過濾器

異常處理過濾器需要實現的介面為IExceptionFilter。我們看下介面的定義:

//
// 摘要:
//     定義異常篩選器所需的方法。
public interface IExceptionFilter
{
    //
    // 摘要:
    //     在發生異常時調用。
    //
    // 參數:
    //   filterContext:
    //     篩選器上下文。
    void OnException(ExceptionContext filterContext);
}

介面方法OnException可以看到它在我們的方法中出現異常時觸發,MVC預設用HandleErrorAttribute類來實現了此介面,我們自己定義的異常過濾器可以繼承此類進行擴展。

OnException方法中傳遞的參數是一個ExceptionContext對象,它的屬性如下:

名稱

類型

說明

Exception

Exception

獲取或設置異常對象。

ExceptionHandled

bool

獲取或設置一個值,該值指示是否已處理異常。

Result

ActionResult

獲取或設置操作結果。

我們來定義一個異常過濾器,代碼如下:

public class MyExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        //如果有異常,跳轉到異常頁面。
        if (filterContext.Exception != null)
        {
            //跳轉到自定義的錯誤頁
            ActionResult view = new ViewResult() { ViewName = "Error" };
            filterContext.Result = view;
            //異常處理結束後,一定要將ExceptionHandled設置為true,否則仍然會繼續拋出錯誤。
            filterContext.ExceptionHandled = true;
        }
    }
}

當我們的方法中出現異常時,會將Views文件夾下Shared中的Error.cshtml頁面返回到客戶端,客戶端頁面不再顯示成黃頁,給用戶一個良好的體驗。

我們給Index方法添加上我們的異常處理器,再加一段引發異常的代碼看下效果。

打開Index視圖:

視圖中顯示的是Error頁面中的內容。

通常我們用異常處理器來記錄我們的程式異常日誌,或者在產生異常時給客戶端返回一個友好的提示內容。

過濾器的使用方法

在上文的一些例子中,我們把過濾器的特性都定義在了Action方法上,其實過濾器不僅可以應用在Action方法中,還可在應用在Controller和全局配置中。

應用在Controller中的使用方法和Action一直,在Controller類名上方添加特性標簽即可。如圖:

全局環境下的過濾器,則需要註冊到FilterConfig文件中,例如MVC預設給我們註冊的HandleErrorAttribute異常處理器:

並且我們可以註冊很多個過濾器在全局環境下,那麼在此註冊的過濾器會應用到整個應用程式當中。

總結

本章對過濾器的類型,作用,定義以及使用方法做了一些說明,當然這些都是比較基礎的內容,真正深入的理解還得多多使用,如果文章中有錯誤或者不足的地方,請大家在評論中指正出來。

更多內容可訪問我的博客:http://www.yunc.top/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用本地Windows鏈接 VMware虛擬機 redis服務 我用的虛擬機系統是:windows Server 2012 先把Redis伺服器拷貝到伺服器並解壓,目錄如下 這裡僅僅作為演示,所以就不安裝成window服務了,直接用非系統服務方式啟動服務,啟動之前需要做以下配置: 1,關掉虛擬機上w ...
  • 添加源 sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm 安裝Nginx sudo yum install -y nginx 直到出現 Co ...
  • 摘要:HALCON數據類型:Iconic Variables(圖形變數)、Control Variables(控制變數)。在C#中,圖形變數用HObject聲明,控制變數用HTuple聲明。(halcon數據類型被封裝成類)。 一,HALCON中變數導成C#變數 1,圖形變數 圖像變數 HObjec ...
  • 由於之前在網上查閱一些資料發現總是不能編譯通過,不能正常使用,現把能正常使用的代碼貼出: /// <summary> /// Excel導入幫助類 /// </summary> public class ImportExcelUtil<T> where T : new() { //合法文件擴展名 p ...
  • [toc] C (讀作 “See Sharp”)是一種簡單易用的新式編程語言,不僅面向對象,還類型安全。 C 源於 C 語言系列,可用 C 構建在多種操作系統(平臺)上運行的軟體組件和應用程式。 因為本系列文章會廣泛地使用 C 代碼示例,所以我們先來看看 C 程式的樣子,還有它的不同部分代表什麼意思 ...
  • 因為之前沒有接觸NPOI過這個插件,所以幾乎都是自己一邊百度摸索一邊學習。 這個插件對於Excel的數據導入和導出,可以說是很方便了, 但是對於導出word文檔,可以說是很少的,百度了很多....也不停止地去試代碼,於是整理出自己的一些看法,方便記錄代碼。 話不多說,上代碼... 用這個插件你需要準 ...
  • AMP(加速的移動頁面)是Google的開發人員軟體包,它允許開發負載更快的輕量級系統。AMP是由HTML,JavaScript和CSS組成的框架,它們是為用戶提供Web內容優先格式的標準。 Aspose.Email for .NET是一套全面的電子郵件處理API,可用於構建跨平臺應用程式。近期的更 ...
  • 1、先創建 .net core Web 應用程式,選擇API 2、安裝 Nuget 包:Nlog.Web.AspNetCore install-package Nlog install-package Nlog.Web.AspNetCore 或者打開Nuget管理界面搜索Nlog.Web.AspNe ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...