1. 程式人生 > >ASP.NET MVC中Filter過濾器的使用

ASP.NET MVC中Filter過濾器的使用

MVC Filter是典型的AOP(面向切面程式設計)應用,在ASP.NET MVC中的4個過濾器型別,如下:

過濾器型別 介面 預設實現 描述
Action IActionFilter ActionFilterAttribute 在動作方法之前及之後執行
Result IResultFilter ActionFilterAttribute 在動作結果被執行之前和之後執行
AuthorizationFilter IAuthorizationFilter AuthorizeAttribute 首先執行,在任何其它過濾器或動作方法之前
Exception IExceptionFilter HandleErrorAttribute 只在另一個過濾器、動作方法、動作結果彈出異常時執行

但是預設實現它們的過濾器只有三種,分別是ActionFilter(方法),Authorize(授權),HandleError(錯誤處理)。

1、Action過濾器

在ASP.NET MVC中建立MvcApp專案,建立資料夾Filter,然後新建類MyActionFilterAttribute(為了遵循預設的約定,名稱以Attribute結尾),繼承自ActionFilterAttribute類。ActionFilterAttribute類有如下4個方法。

using System;

namespace System.Web.Mvc
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
    {

        protected ActionFilterAttribute();

        public virtual void OnActionExecuted(ActionExecutedContext filterContext);

        public virtual void OnActionExecuting(ActionExecutingContext filterContext);

        public virtual void OnResultExecuted(ResultExecutedContext filterContext);

        public virtual void OnResultExecuting(ResultExecutingContext filterContext);
    }
}

實現MyActionFilterAttribute類:

using System;
using System.Web.Mvc;

namespace MvcApp.Filter
{
    public class MyActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //1、獲取請求的類名和方法名
            string strController = filterContext.RouteData.Values["controller"].ToString();
            string strAction = filterContext.RouteData.Values["action"].ToString();

            //2、用另一種方式獲取請求的類名和方法名
            string strController2 = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            string strAction2 = filterContext.ActionDescriptor.ActionName;

            filterContext.HttpContext.Response.Write("控制器:" + strController + "<br/>");
            filterContext.HttpContext.Response.Write("控制器:" + strController2 + "<br/>");
            filterContext.HttpContext.Response.Write("Action:" + strAction + "<br/>");
            filterContext.HttpContext.Response.Write("Action:" + strAction2 + "<br/>");

            filterContext.HttpContext.Response.Write("Action執行前:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");
            base.OnActionExecuting(filterContext);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write("Action執行後:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");
            base.OnActionExecuted(filterContext);
        }
    }
}

對於過濾器,我們可以把它們加在3個地方,一個是控制器上面(控制器下面的所有Action),一個是Action上面(指定標識的Action),另一個就是全域性位置(所有控制器中的Action)。這裡只演示在Action上面和Home控制器中:

[MyActionFilter]
public ActionResult Index()
{
    return View();
}

2、Result過濾器

新建MyResultFilterAttribute類,繼承ActionFilterAttribute:

using System;
using System.Web.Mvc;

namespace MvcApp.Filter
{
    public class MyResultFilterAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 載入“檢視”前執行
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            filterContext.HttpContext.Response.Write("載入檢視前執行 OnResultExecuting" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");
            base.OnResultExecuting(filterContext);
        }

        /// <summary>
        /// 載入“檢視”後執行
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            filterContext.HttpContext.Response.Write("載入檢視後執行 OnResultExecuted" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");
            base.OnResultExecuted(filterContext);
        }
    }
}

這裡把MyResultFilter過濾器加在控制器上面,相當於給Home控制器中的所有的Action方法添加了MyResultFilter過濾器。

using MvcApp.Filter;
using System.Web.Mvc;

namespace MvcApp.Controllers
{
    [MyResultFilter]
    public class HomeController : Controller
    {
        [MyActionFilter]
        public ActionResult Index()
        {
            return View();
        }

    }
}

3、AuthorizeAttribute過濾器

建立MyAuthorizeAttribute類,繼承AuthorizeAttribute類:

using System.Web.Mvc;

namespace MvcApp.Filter
{
    /// <summary>
    /// 授權過濾器
    /// </summary>
    public class MyAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            filterContext.HttpContext.Response.Write("OnAuthorization<br/>");

            //註釋掉父類方法,因為父類裡的OnAuthorization方法會呼叫ASP.NET的授權驗證機制
            //base.OnAuthorization(filterContext);
        }

    }
}

在控制器Home中的Index上新增MyAuthorize過濾器:

[MyAuthorize]
[MyActionFilter]
public ActionResult Index()
{
    return View();
}

通常Authorize過濾器也是在全域性過濾器上面的,主要用來做登入驗證或者許可權驗證,在App_Start目錄下的FilterConfig類的RegisterGlobalFilters方法中新增:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //filters.Add(new HandleErrorAttribute());

        //新增全域性授權過濾器
        filters.Add(new MyAuthorizeAttribute());
    }
}

在全域性中註冊過濾器,則所有控制器的所有行為(Action)都會執行這個過濾器。

執行結果,如下圖:

4、Exception過濾器

建立MyHandleErrorAttribute類,繼承HandleErrorAttribute類:

using System;
using System.Web.Mvc;

namespace MvcApp.Filter
{
    /// <summary>
    /// 異常處理過濾器
    /// </summary>
    public class MyHandleErrorAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        { 
            //1、獲取異常物件
            Exception ex = filterContext.Exception;
            
            //2、記錄異常日誌

            //3、重定向友好頁面
            filterContext.Result = new RedirectResult("~/error.html");

            //4、標記異常已經處理完畢
            filterContext.ExceptionHandled = true;

            base.OnException(filterContext);
        }
    }
}

在Action上面新增MyHandleError過濾器:

[MyHandleError]
public ActionResult GetErr()
{
    int a = 0;
    int b = 1 / a;
    return View();
}

建立異常錯誤友好提示頁面error.html。

<body>
    自定義錯誤頁面
</body>

執行會自動跳轉到error.html頁面。

如果頁面沒有跳轉,就需要去Web.config配置檔案中的<system.web>節點下面新增如下配置節點,開啟自定義錯誤:

<customErrors mode="On"></customErrors>

通常這樣的異常處理是放在全域性過濾器上面的,只要任意Action方法報錯就會執行MyHandleError過濾器中的程式碼。

修改App_Start目錄下面的FilterConfig類:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //filters.Add(new HandleErrorAttribute());

        //新增全域性授權過濾器
        filters.Add(new MyAuthorizeAttribute());

        //新增全域性異常處理過濾器
        filters.Add(new MyHandleErrorAttribute());
    }
}