Asp.Net MVC過濾器小試牛刀


  在上學期間學習的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]特性,然后發布,調試結果:結果一樣

就這樣,全局異常處理就完成了。

 

========================

由於學識有限,文章難免會有錯誤,敬請指教與批評。

 


免責聲明!

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



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