在.Net Framework MVC 中有四種過濾器,授權過濾器(Authorize)、Action 過濾器、結果過濾器(Result)、異常過濾器(Exception)四種過濾器。在.Net Core MVC中,有五種過濾器,授權過濾器、Action過濾器、異常過濾器、結果過濾器、資源過濾器,新 ...
在.Net Framework MVC 中有四種過濾器,授權過濾器(Authorize)、Action 過濾器、結果過濾器(Result)、異常過濾器(Exception)四種過濾器。在.Net Core MVC中,有五種過濾器,授權過濾器、Action過濾器、異常過濾器、結果過濾器、資源過濾器,新增了資源過濾器。
.Net Core MVC和.Net Framework MVC在基本使用上差別不大,主要的還是框架的差別。其中路由是個很重要的東西,參考文章:https://www.cnblogs.com/durow/p/5992926.html
Action過濾器、結果過濾器、Exception,三個特性,沒有什麼變化。在ExceptionFilter多了個Order參數,就是用來排序的。
結果過濾器,包裝了單個Action Result的執行,當且晉檔Action方法成功執行完畢後才運行。它們是理想的圍繞視圖執行或格式處理的邏輯(所在之處)。繼承Attribute,IResultFilter
/// <summary> /// Result的Filter /// </summary> public class CustomResultFilterAttribute : Attribute, IResultFilter { //private Logger logger = Logger.CreateLogger(typeof(CustomResultFilterAttribute)); public void OnResultExecuted(ResultExecutedContext context) { Console.WriteLine("OnResultExecuted Executed!"); //logger.Info("OnResultExecuted Executed!"); } public void OnResultExecuting(ResultExecutingContext context) { Console.WriteLine("OnResultExecuting Executing!"); //logger.Info("OnResultExecuting Executing!"); } }
異常過濾器,為MVC隱藏程式為處理異常應用全局策略。繼承ExceptionFilterAttribute
/// <summary> /// 異常處理的Filter /// </summary> public class CustomExceptionFilterAttribute : ExceptionFilterAttribute { private readonly IHostingEnvironment _hostingEnvironment; private readonly IModelMetadataProvider _modelMetadataProvider; //private Logger logger = Logger.CreateLogger(typeof(CustomExceptionFilterAttribute)); /// <summary> /// IOC來的 /// </summary> /// <param name="hostingEnvironment"></param> /// <param name="modelMetadataProvider"></param> public CustomExceptionFilterAttribute( IHostingEnvironment hostingEnvironment, IModelMetadataProvider modelMetadataProvider) { _hostingEnvironment = hostingEnvironment; _modelMetadataProvider = modelMetadataProvider; } /// <summary> /// 沒有處理的異常,就會進來 /// </summary> /// <param name="filterContext"></param> public override void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled)//異常有沒有被處理過 { string controllerName = (string)filterContext.RouteData.Values["controller"]; string actionName = (string)filterContext.RouteData.Values["action"]; string msgTemplate = "在執行 controller[{0}] 的 action[{1}] 時產生異常"; //logger.Error(string.Format(msgTemplate, controllerName, actionName), filterContext.Exception); if (this.IsAjaxRequest(filterContext.HttpContext.Request))//檢查請求頭 { filterContext.Result = new JsonResult( new { Result = false, PromptMsg = "系統出現異常,請聯繫管理員", DebugMessage = filterContext.Exception.Message }//這個就是返回的結果 ); } else { var result = new ViewResult { ViewName = "~/Views/Shared/Error.cshtml" }; result.ViewData = new ViewDataDictionary(_modelMetadataProvider, filterContext.ModelState); result.ViewData.Add("Exception", filterContext.Exception); filterContext.Result = result; } filterContext.ExceptionHandled = true; } } private bool IsAjaxRequest(HttpRequest request) { string header = request.Headers["X-Requested-With"]; return "XMLHttpRequest".Equals(header); } }View Code
定義完ExceptionFilter,該怎麼註冊到全局呢?在Stratup.cs中ConfigureServer中,進行註冊
services.AddMvc(o => { o.Filters.Add(typeof(CustomExceptionFilterAttribute));// 這裡就是全局註冊Filter }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Action 過濾器,包裝了對單個Action方法的調用,可以將參數傳遞給Action並從中獲得Action Result。繼承IActionFilter
/// <summary> /// Action的Filter` /// </summary> public class CustomActionFilterAttribute : Attribute, IActionFilter { private ILogger<CustomActionFilterAttribute> _logger = null; public CustomActionFilterAttribute(ILogger<CustomActionFilterAttribute> logger) { this._logger = logger; } public void OnActionExecuted(ActionExecutedContext context) { //context.HttpContext.Response.WriteAsync("ActionFilter Executed!"); Console.WriteLine("ActionFilter Executed!"); //this._logger.LogDebug("ActionFilter Executed!"); } public void OnActionExecuting(ActionExecutingContext context) { //context.HttpContext.Response.WriteAsync("ActionFilter Executing!"); Console.WriteLine("ActionFilter Executing!"); //this._logger.LogDebug("ActionFilter Executing!"); } }
在Startup.cs中ConfigureServices進行註冊
//允許使用ServiceFilter 標記特性 services.AddScoped<CustomActionFilterAttribute>();
標記到Controller的ActionFilter
/// <summary> /// 標記到Controller /// </summary> public class CustomControllerActionFilterAttribute : Attribute, IActionFilter { private ILogger<CustomControllerActionFilterAttribute> _logger = null; public CustomControllerActionFilterAttribute(ILogger<CustomControllerActionFilterAttribute> logger) { this._logger = logger; } public void OnActionExecuted(ActionExecutedContext context) { //context.HttpContext.Response.WriteAsync("ActionFilter Executed!"); Console.WriteLine("ActionFilter Executed!"); //this._logger.LogDebug("ActionFilter Executed!"); } public void OnActionExecuting(ActionExecutingContext context) { //context.HttpContext.Response.WriteAsync("ActionFilter Executing!"); Console.WriteLine("ActionFilter Executing!"); //this._logger.LogDebug("ActionFilter Executing!"); } }
[TypeFilter(typeof(CustomControllerActionFilterAttribute),Order =-1)] public class ThirdController : Controller { }
註冊到全局的ActionFilter
public class CustomGlobalActionFilterAttribute : Attribute, IActionFilter { private ILogger<CustomGlobalActionFilterAttribute> _logger = null; public CustomGlobalActionFilterAttribute(ILogger<CustomGlobalActionFilterAttribute> logger) { this._logger = logger; } public void OnActionExecuted(ActionExecutedContext context) { //context.HttpContext.Response.WriteAsync("ActionFilter Executed!"); Console.WriteLine("ActionFilter Executed!"); //this._logger.LogDebug("ActionFilter Executed!"); } public void OnActionExecuting(ActionExecutingContext context) { //context.HttpContext.Response.WriteAsync("ActionFilter Executing!"); Console.WriteLine("ActionFilter Executing!"); //this._logger.LogDebug("ActionFilter Executing!"); } }
還是要在Startup中進行全局的註冊
services.AddMvc(o => { o.Filters.Add(typeof(CustomGlobalActionFilterAttribute));// 這裡就是全局註冊Filter }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
分別對全局、控制器、Action註冊了ActionFilter預設執行順序:
全局OnActionExecuting===》控制器的OnActionExecuting====》Action的OnActionExecuting====》執行Action ====》Action的OnActionExecuted====》控制器的OnActionExecuted====》全局的OnActionExecuted。類似於一個俄羅斯套娃,也可以說是一個洋蔥模型。
資源過濾器,是授權之後第一個用來處理請求的過濾器,也是最後一個接觸到請求的過濾器(因為之後就會離開過濾器管道)。在性能方面,資源過濾器在實現緩存或短路過濾器管道尤其有用。繼承IResourceFilter
/// <summary> /// 自定義的資源Filter /// </summary> public class CustomResourceFilterAttribute : Attribute, IResourceFilter { private static readonly Dictionary<string, object> _Cache = new Dictionary<string, object>(); private string _cacheKey; /// <summary> /// 控制器實例化之前 /// </summary> /// <param name="context"></param> public void OnResourceExecuting(ResourceExecutingContext context) { _cacheKey = context.HttpContext.Request.Path.ToString(); if (_Cache.ContainsKey(_cacheKey)) { var cachedValue = _Cache[_cacheKey] as ViewResult; if (cachedValue != null) { context.Result = cachedValue; } } } /// <summary> /// 把請求都處理完的 /// </summary> /// <param name="context"></param> public void OnResourceExecuted(ResourceExecutedContext context) { if (!String.IsNullOrEmpty(_cacheKey) && !_Cache.ContainsKey(_cacheKey)) { var result = context.Result as ViewResult; if (result != null) { _Cache.Add(_cacheKey, result); } } } }