一、前言
編程中我們會使用特性(Attribute)標注到程式集、類、方法、屬性上進行描述,在Asp.net MVC或者Asp.net WebApi中使用過濾器(Filter)對Action、Result、Exception、Authorize進行AOP(切面編程),并且過濾器和特性結合,將過濾器優雅的使用在方法上,本文針對特性與過濾器做一個總結,
二、定義
1、特性(Attribute),在微軟官方檔案的定義是使用特性,可以有效地將元資料或宣告性資訊與代碼(程式集、型別、方法、屬性等)相關聯,按個人理解,就是對元資料的描述,類和方法,屬性作為元資料,使用特性在元資料上使用特性,其作用就是對元資料補充說明,使用反射的方式獲取特性內容,使用特性資訊,
主要用途,比如描述類、方法和介面的 COM 屬性、從標題、版本、說明或商標方面描述程式集、描述的方法的安全要求等詳情參考msdn給的官方檔案說明,總結就是基于元資料的描述資訊,然后使用描述資訊,
2、過濾器(Filter),提供了在asp.net MVC與asp.net webApi的請求處理管道程序中注入額外的邏輯,提供了一個簡單而優雅的方式來實作橫切關注點,主要分四類過濾器IAuthorizationFilter(授權過濾器)、IActionFilter(Action方法過濾器)、IResultFilter(ActionResult方法回傳結果)、IExceptionFilter(例外過濾器),類別庫中通過繼承介面提供了AuthorizeAttribute、ActionFilterAttribute、HandleErrorAttribute給開發者進行繼承重寫實作業務邏輯,
主要用途,比如基于AuthorizeAttribute(提供角色、用戶名)方式的授權、日志資訊、安全驗證、圖片防盜鏈、基于ActionFilterAttribute注入業務邏輯,請求和回傳結果的處理等,
3、在過濾器中.NET FrameWork中提供兩類,一類是在命名空間為using System.Web.Mvc下的提供給ASP.NET MVC的過濾器、一類是在命名空間using System.Web.Http.Filters下提供給ASP.NET WebApi的過濾器,兩者不能混用,否則無法攔截生效,
三、使用
1、自定義的特性和過濾器專案

2、使用自定義特性在程式集、方法、屬性等上,對其進行描述,通過反射的方式獲取相應資訊,
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace TQF.CustomFilterAttribute.App_Start.Filter { // _Attribute 介面運行時中 public class TestAttribute: Attribute { public string ActionName { get; set; } public TestAttribute() { } } }
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web; using System.Web.Mvc; using TQF.CustomFilterAttribute.App_Start.Filter; namespace TQF.CustomFilterAttribute.Controllers { /// <summary> /// MVC請求 /// </summary> public class HomeController : Controller { public string Field { get; set; } public HomeController() { } //[TestMvcFilter(ActionName =nameof(Index))] [Test(ActionName =nameof(Index))] public ActionResult Index() { ViewBag.Title = "Home Page"; //獲取類的屬性描述 var classIfno = typeof(HomeController).GetCustomAttribute<TestAttribute>(); //獲取指定屬性的屬性描述 var fieldIfno = typeof(HomeController).GetProperty("Field").GetCustomAttribute<TestAttribute>(); //獲取指定方法的屬性描述 var methodIfno = typeof(HomeController).GetMethod("Index").GetCustomAttribute<TestAttribute>(); return View(); } [HttpPost] public JsonResult Save() { //throw (new Exception("error", new InvalidCastException())); return new JsonResult(); } public ActionResult Error() { return View(); } } }
3、自定義AuthorizeAttribute過濾
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using TQF.CustomFilterAttribute.Models; namespace TQF.CustomFilterAttribute.App_Start.Filter { /// <summary> /// Mvc請求權限授權過濾器 /// </summary> public class TestMvcAuthorizeAttribute: AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { var result = new ResultModel() { Message = "授權中" }; //actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, result); // 獲取特殊設定的角色和用戶,進行權限判斷 if (Users == "admin") { // 回傳,不進行權限驗證或者驗證成功 return; } else { } //base.OnAuthorization(filterContext); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http; using System.Web.Http.Controllers; using TQF.CustomFilterAttribute.Models; namespace TQF.CustomFilterAttribute.App_Start.Filter { /// <summary> /// webApi請求權限授權過濾器 /// </summary> public class TestHttpAuthorizeAttribute: AuthorizeAttribute { public override void OnAuthorization(HttpActionContext actionContext) { var result = new ResultModel() { Message = "授權中" }; //actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, result); // 獲取特殊設定的角色和用戶,進行權限判斷 if (Users == "admin"){ // 回傳,不進行權限驗證或者驗證成功 return; }else{ } base.OnAuthorization(actionContext); } } }
4、自定義ActionFilterAttribute過濾器(其包括實作了IActionFilter和IResultFilter介面)
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace TQF.CustomFilterAttribute.App_Start.Filter { /// <summary> /// Mvc /// </summary> public class TestMvcActionFilterAttribute: ActionFilterAttribute { /// <summary> /// action 執行中 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("OnActionExecuting"); base.OnActionExecuting(filterContext); } /// <summary> /// action 執行結束 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("OnActionExecuted"); base.OnActionExecuted(filterContext); } /// <summary> /// 生成結果中 /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write("OnResultExecuting"); base.OnResultExecuting(filterContext); } /// <summary> /// /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuted(ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write("OnResultExecuting"); base.OnResultExecuted(filterContext); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http.Controllers; using System.Web.Http.Filters; using TQF.CustomFilterAttribute.Models; namespace TQF.CustomFilterAttribute.App_Start.Filter { /// <summary> /// WebApi 請求的Action方法過濾器 /// </summary> public class TestHttpActionFilterAttribute: ActionFilterAttribute { /// <summary> /// 執行前 /// </summary> /// <param name="actionContext"></param> public override void OnActionExecuting(HttpActionContext actionContext) { var result = new ResultModel() { Message = "執行中"}; // 回傳請求結果,不執行后續 actionContext.Response=actionContext.Request.CreateResponse(HttpStatusCode.OK, result); base.OnActionExecuting(actionContext); } /// <summary> /// 執行后 /// </summary> /// <param name="actionExecutedContext"></param> public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { var result = new ResultModel() { Message = "執行后" }; // 更改請求結果 actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, result); base.OnActionExecuted(actionExecutedContext); } } }
5、自定義HandleErrorAttribute過濾器
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using TQF.CustomFilterAttribute.Models; namespace TQF.CustomFilterAttribute.App_Start.Filter { /// <summary> /// 處理中產生的例外,例外過濾器 /// </summary> public class TestHandleErrorAttribute: HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { // 例外的具體資訊 var exceptionType = filterContext.Exception.InnerException.GetType().FullName; var exceptionMessage = filterContext.Exception.InnerException.Message; var exceptionMethod = filterContext.Exception.TargetSite; var exceptionStackTrace = filterContext.Exception.StackTrace; // 寫入日志檔案 filterContext.ExceptionHandled = true; if (filterContext.HttpContext.Request.IsAjaxRequest()) { // 回傳統一的錯誤資訊 var result = new ResultModel(); filterContext.HttpContext.Response.ContentType = "application/json"; filterContext.HttpContext.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(result)); filterContext.HttpContext.Response.End(); } else { // 回傳統一的錯誤頁面 filterContext.HttpContext.Response.Redirect("/Home/Error"); base.OnException(filterContext); filterContext.HttpContext.Response.End(); } } } }
5、過濾器的注冊,通過特性的方式將過濾器標注在Action上,或者在全域中進行注冊,讓所有的Action都使用,比如在Asp.NET MVC中提供的App_Start檔案的FilterConfig類中注冊,
using System.Web; using System.Web.Mvc; using TQF.CustomFilterAttribute.App_Start.Filter; namespace TQF.CustomFilterAttribute { public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // filters.Add(new HandleErrorAttribute()); // filters.Add(new TestHandleErrorAttribute()); // filters.Add(new TestMvcActionFilterAttribute()); // filters.Add(new TestMvcAuthorizeAttribute()); // filters.Add(new TestFilter()); } } }
或者在Global.asax的Application_Start方法中GlobalFilters注冊,
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using TQF.CustomFilterAttribute.App_Start.Filter; namespace TQF.CustomFilterAttribute { public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { //AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); GlobalFilters.Filters.Add(new TestHttpActionFilterAttribute()); } } }
注意ASP.NET WebApi的fliter不能在FilterConfig類中注冊,必須在WebApiConfig類中注冊,
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using TQF.CustomFilterAttribute.App_Start.Filter; namespace TQF.CustomFilterAttribute { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Filters.Add(new TestHttpActionFilterAttribute()); } } }
四、總結
1、過濾器提供AOP的面向切面的關注點,動態注入業務邏輯,將相關的非主業務邏輯進行優雅解耦,并且可以使用特性的方式便利添加在各個Action上,
2、通過自定義過濾器,重寫過濾器的虛方法,使用方法中提供的引數背景關系資訊(包含請求資料的請求體、請求頭、回傳資料的請求結果、例外資訊)來處理業務,
3、各過濾器的執行順序依次是IAuthorizationFilter->IActionFilter->IResultFilter->IExceptionFilter,首先是授權的驗證,其次是Action方法的處理程序和回傳結果、最后是產生的例外資訊,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/415146.html
標籤:ASP.NET
