Asp.Net Filter學習,學習了基本過濾器、ActionFilterAttribute以及異常過濾器 當然最後學習了全局異常過濾器 文中有很多拍不足之處,敬請各位諒解
在上學期間學習的Asp.Net MVC,基本只是大概馬馬虎虎的瞭解,基本處於知其然而不知其所以然。現在到上班,接觸到真實的項目,才發現還不夠用,於是從最簡單的過濾器開始學習。不得不說MVC的過濾器真是簡單,而又不失優雅。
以前我寫異常都是try...catch...配合log4net來記錄日誌,這真是一個重覆造輪子的過程,一不小心還會忘記。後面在開發的過程中,逐漸學習到過濾器(Filter)這一優雅的東東,一下子愛上了它。
在Asp.Net MVC有最基本的過濾器,添加一個Home控制器,然後添加兩個Action,這裡為了演示,添加了兩個同名的Action,為了編譯,設置了參數的區別,實際上並沒有使用參數。
public class HomeController : Controller { [HttpGet] public ActionResult Index(string msg) { return Content("I'm come from Get Method."); } [HttpPost] public ActionResult Index() { return Content("I'm come from Post Method."); } }
點擊調試,使用PostMan分別用get/post方式去訪問Home/Index,如下圖:
對於同一個Action,只是請求方式不一樣,返回的結果也不一樣,這就是Asp.Net最基本的過濾器。
[HttpGet]:該Action只響應get請求
[HttpPost]:該Action只響應post請求
於是我們可以思考,是不是可以考慮將很多重覆的代碼封裝起來,例如判斷用戶是否有許可權訪問該Action,只需要簡單的在Action上做一個特性標註就可以或者註冊一個全局的機制,滿足需要?很好,Asp.Net給我們提高了簡單優雅的過濾器。
下麵來簡單看一下我自己寫的許可權判斷過濾器。
1,在項目中添加Filters文件夾,所有Filters都放置在該文件夾中,方便後期歸檔
2,在Filters文件夾中添加一個類:CheckUserRoleAttribute.cs,在這裡我們按照MVC約定的方式來命名,過濾器以Attribute來結尾。讓其繼承: System.Web.Mvc.ActionFilterAttribute。查看ActionFilterAttribute定義,其成員如下:
// 摘要: // 在執行操作方法後由 ASP.NET MVC 框架調用。 // // 參數: // filterContext: // 篩選器上下文。 public virtual void OnActionExecuted(ActionExecutedContext filterContext); // // 摘要: // 在執行操作方法之前由 ASP.NET MVC 框架調用。 // // 參數: // filterContext: // 篩選器上下文。 public virtual void OnActionExecuting(ActionExecutingContext filterContext); // // 摘要: // 在執行操作結果後由 ASP.NET MVC 框架調用。 // // 參數: // filterContext: // 篩選器上下文。 public virtual void OnResultExecuted(ResultExecutedContext filterContext); // // 摘要: // 在執行操作結果之前由 ASP.NET MVC 框架調用。 // // 參數: // filterContext: // 篩選器上下文。 public virtual void OnResultExecuting(ResultExecutingContext filterContext);
看註解可以知道4個成員:
OnActionExecuted
OnActionExecuting
OnResultExecuted
OnResultExecuted
而我一般都是重寫OnActionExecuting方法:
public class CheckUserRoleAttribute : System.Web.Mvc.ActionFilterAttribute { public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext) { /* * 這裡為了方便演示,直接在請求參數中獲取了userName * 假設某一個Action只有Lucy可以訪問。 */ string userName = filterContext.HttpContext.Request["userName"]; if (userName=="Lucy") { base.OnActionExecuting(filterContext); return; } else { //這裡構造了一個心得ActionResult.如果userName不是Lucy,則返回許可權不足 filterContext.Result = new System.Web.Mvc.ContentResult() { Content = "許可權不足,無法訪問" }; return; } } }
然後在HomeController中添加SayHello(),並且添加特性[CheckUserRole]
public class HomeController : Controller { [HttpGet] public ActionResult Index(string msg) { return Content("I'm come from Get Method."); } [HttpPost] public ActionResult Index() { return Content("I'm come from Post Method."); } //添加特性 [Filters.CheckUserRole] public ActionResult SayHello() { return Content("我是Lucy,這隻能給我訪問"); } }
點擊調試:
這樣子,一個簡單的過濾器就實現了。
我們可以根據實際的邏輯去重寫自己的過濾器。
**********************簡單優雅的分隔符**********************
另外一個比較常用的是異常過濾器
1,同樣新建SystemErrorAttribute.cs
需要註意,這裡繼承的是:System.Web.Mvc.HandleErrorAttribute
public class SystemErrorAttribute : System.Web.Mvc.HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { base.OnException(filterContext); //處理錯誤消息,將其跳轉到一個頁面 string controllerName = (string)filterContext.RouteData.Values["controller"]; string actionName = (string)filterContext.RouteData.Values["action"]; //這裡簡單向C盤的test.log寫入了文件 FileStream fs = new FileStream(@"C:\test.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.BaseStream.Seek(0, SeekOrigin.End); string writeText = string.Format("controllerName:[{0}]actionName:[{1}]{2}", controllerName, actionName, filterContext.Exception.ToString()); sw.WriteLine(writeText); sw.Flush(); sw.Close(); fs.Close(); /*//這裡是使用log4net來記錄 log4net.ILog log = log4net.LogManager.GetLogger("controllerName:[" + controllerName + "]actionName:[" + actionName+"]"); log.Error(filterContext.Exception.ToString()); */ //錯誤友好輸出,這裡重新構造了一個ActionResult filterContext.Result = new System.Web.Mvc.ContentResult() { Content = "系統錯誤,請聯繫管理員" }; return; } }
2,在HomeController中添加MyError()
public class HomeController : Controller { [Filters.SystemError]//添加 public ActionResult MyError() { //人為製造一個錯誤 int a = 1; int b = 0; return Content((a/b).ToString()); } }
3,調試:註意:這裡需要採用Ctrl+F5的方式運行,結果如下:
到這裡,可能會有很大疑問,為什麼沒有產生友好提示呢?在過濾器中不是明明有添加友好提示嗎?
先看一下C盤的日誌:test.log
日誌有成功產生。沒有出現友好提示的原因在於不是正式的環境,VS為了方便調試,不會隱藏錯誤信息。下麵將應用部署到真實的環境中去調試,看結果:
這下友好提示又出來了。。。
當然對於異常處理過濾器來說,我在每個Action都來添加特性,還是很麻煩,這裡我們就要註冊成為全局過濾器:
①,打開App_Start文件夾中的FilterConfig.cs
添加:filters.Add(new Filters.SystemErrorAttribute());
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //添加這個 filters.Add(new Filters.SystemErrorAttribute()); filters.Add(new HandleErrorAttribute()); } }
②,在HomeController去掉[Filters.SystemError]特性,然後發佈,調試結果:結果一樣
就這樣,全局異常處理就完成了。
========================
由於學識有限,文章難免會有錯誤,敬請指教與批評。