MVC過濾器特性


1、概括

  MVC提供的幾種過濾器其實也是一種特性(Attribute),MVC支持的過濾器類型有四種,分別是:AuthorizationFilter(授權),ActionFilter(行為),ResultFilter(結果)和ExceptionFilter(異常),他們分別對應了四個篩選器接口IAuthorizationFilter、IActionFilter、IResultFilter和IExceptionFilter。這四種篩選器都有派生於一個公共的類FilterAttribute,該類指定了篩選器的執行順序和是否允許多個應用AllowedMultiple。這四種篩選器默認的執行順序為最先進行授權篩選,最后進行異常處理,中間則是ActionFilter和ResultedFilter。官網對FilterAttribute層次結構的介紹圖如下

 

 

2、MVC四大過濾器介紹

  2.1、AuthorizeFilter篩選器

  AuthorizeAttribute為最終授權過濾器的實現者,它實現了IAuthorizationFilter接口和FilterAttribute抽象類,接口中的OnAuthorization(AuthorizationContext filterContext)方法是最終驗證授權的邏輯(其中AuthorizationContext是繼承了ControllerContext類),AuthorizeCore方法是最終OnAuthorization()方法調用的最終邏輯。

  • bool AuthorizeCore(HttpContextBase httpContext):授權驗證的邏輯處理,返回true則是通過授權,返回false則不是。若驗證不通過時,OnAuthorization方法內部會調用HandleUnauthorizedRequest
  • void HandleUnauthorizedRequest(AuthorizationContext filterContext):這個方法是處理授權失敗的事情。

AuthorizeCore代碼如下:

protected virtual bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
 
            IPrincipal user = httpContext.User;
            if (!user.Identity.IsAuthenticated)
            {
                return false;
            }
 
            if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
            {
                return false;
            }
 
            if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
            {
                return false;
            }
 
            return true;
        }

我們不一定要用MVC默認的Authorize授權驗證規則,規則可以自己來定,自定義授權過濾器繼承IAuthorizeAttribute和FilterAttribute,由於OnAthurization()、AuthorizeCore()和HandleUnauthorizedRequest()方法都是虛方法,這些方法是可以重寫的,這樣就可以自定義自己的驗證規則和驗證失敗時的處理邏輯了。示例代碼如下

public class PermissionFilterAttribute: AuthorizationFilter
    {
         
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            return true;
        }
 
         
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result="";     
           
        }
    }

授權過濾器的使用方式一如下:

[PermissionFilterAttribute] 
public ActionResult index()
{
  return View();
}

  2.2、ActionFilter過濾器

  ActionFilter過濾器是在Action方法執行前后會觸發,主要用於在Action執行前后處理一些相應的邏輯。ActionFilter的過濾器都繼承於ActionFilterAttribute抽象類,而它實現了IActionFilter、IResultFilter和FilterAttribute類,結構如下

因此自定義ActionFilter過濾器只要繼承ActionFilterAttribute,實現其中的方法即可。我們來舉一個簡單的例子,獲取Action方法的執行時長,代碼如下

 

public class DefaultController : Controller
    {
        [ActionExecTimeSpan]
        public ActionResult DoWork()
        {
            return View();
        }
    }
 
public class ActionExecTimeSpanAttribute : ActionFilterAttribute
    {
        private const string executeActionTimeKey = "ActionExecBegin";
 
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            //記錄開始執行時間
            filterContext.HttpContext.Items[executeActionTimeKey] = DateTime.Now;
        }
 
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            //計算執行時間,並記錄日志
            if (filterContext.HttpContext.Items.Contains(executeActionTimeKey))
            {
                DateTime endTime = DateTime.Now;
                DateTime beginTime = Convert.ToDateTime(filterContext.HttpContext.Items[executeActionTimeKey]);
                TimeSpan span = endTime - beginTime;
                double execTimeSpan = span.TotalMilliseconds;
                log.Info(execTimeSpan + "毫秒");
            }
            //
            base.OnActionExecuted(filterContext);
        }
    }

  2.3、ResultFilter過濾器

  ResultFilter過濾器是對Action方法返回的Result結果進行執行時觸發的。它也分執行前和執行后兩個段執行,所有的ResultFilter都實現了IResultFilter接口和FilterAttribute類,看一下接口定義

 public interface IResultFilter
    {
        void OnResultExecuting(ResultExecutingContext filterContext);
 
        void OnResultExecuted(ResultExecutedContext filterContext);
    }
其中OnResultExecuting和OnResultExecuted方法分別是在Result執行前、后(頁面展示內容生成前、后)觸發。使用ResultFilter篩選器最典型的應用就是頁面靜態化。
  

2.4、ExceptionFilter過濾器
  
該過濾器是在系統出現異常時觸發,可以對拋出的異常進行處理。所有的ExceptionFilter篩選器都是實現自IExceptionFilter接口 
public interface IExceptionFilter
    {
        void OnException(ExceptionContext filterContext);
    }

實現OnException方法來實現對異常的自定義處理,MVC4中實現了默認的異常處理機制,源碼如下 

public virtual void OnException(ExceptionContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            if (filterContext.IsChildAction)
            {
                return;
            }
 
            // If custom errors are disabled, we need to let the normal ASP.NET exception handler
            // execute so that the user can see useful debugging information.
            if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
            {
                return;
            }
 
            Exception exception = filterContext.Exception;
 
            // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
            // ignore it.
            if (new HttpException(null, exception).GetHttpCode() != 500)
            {
                return;
            }
 
            if (!ExceptionType.IsInstanceOfType(exception))
            {
                return;
            }
 
            string controllerName = (string)filterContext.RouteData.Values["controller"];
            string actionName = (string)filterContext.RouteData.Values["action"];
            HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
            filterContext.Result = new ViewResult
            {
                ViewName = View,
                MasterName = Master,
                ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                TempData = filterContext.Controller.TempData
            };
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500;
 
            // Certain versions of IIS will sometimes use their own error page when
            // they detect a server error. Setting this property indicates that we
            // want it to try to render ASP.NET MVC's error page instead.
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }

 

  Application_Start中將HandleErrorAttribute添加到全局過濾器GlobalFilterCollection中,系統即會對異常進行對應的處理。

3、其他的過濾器
  
3.1、OutputCache過濾器
  表示一個特性,該特性用於標記將緩存其輸出的操作方法。當用戶訪問頁面時,整個頁面將會被服務器保存在內存中,這樣就對頁面進行了緩存。當用戶再次訪問該頁,
頁面不會再次執行數據操作,頁面首先會檢查服務器中是否存在緩存,如果緩存存在,則直接從緩存中獲取頁面信息,如果頁面不存在,則創建緩存。OutputCache的代碼定義片段如下:
[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Method, Inherited = true, 
    AllowMultiple = false)]
public class OutputCacheAttribute : ActionFilterAttribute, 
    IExceptionFilter

從上面的代碼中可以看到該特性可以應用在類,方法上面。在mvc中,就可以直接在控制器上面或者控制器中的Action上面直接使用,做到細粒度的對緩存的控制。

 
        
namespace OutputCacheDemo.Controllers
{
    [OutputCache(Duration = 10)]
    public class HomeController : Controller
    {
        // GET: Home
        public string Index()
        {
            return DateTime.Now.ToString();
        }
    }
}
 
        

上面的代碼是將OutputCache特性標記在了控制器類上,以達到該控制器上所有的Action都將應用該特性,過期時間設置為10s。10s后緩存過期,再訪問就會更新時間。OutputCache特性也可以設置在Action方法上面,以達到更細粒度的控制緩存,代碼如下:

public class HomeController : Controller
    {
        [OutputCache(Duration = 10)]
        // GET: Home
        public string Index()
        {
            return DateTime.Now.ToString();
        }
    }

此時,只有Index的頁面進行了緩存。如果多個控制器或者Action使用相同的緩存配置,可以在配置文件中進行統一配置。

<system.web>
    <caching>
      <outputCacheSettings>
        <outputCacheProfiles >
          <add name='myoutputcache' duration='10'/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5"/>
  </system.web>

應用名稱為myoutputcache的緩存代碼如下:

public class HomeController : Controller
    {
        [OutputCache(CacheProfile = "myoutputcache")]
        // GET: Home
        public string Index()
        {
            return DateTime.Now.ToString();
        }
    }

 

注意:當控制器和Action同時使用了OutputCache特性時,以Action為主。 

 


免責聲明!

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



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