asp.net MVC之 自定義過濾器(Filter)

1、系統過濾器使用說明

  一、OutputCache過濾器html

OutputCache過濾器用於緩存你查詢結果,這樣能夠提升用戶體驗,也能夠減小查詢次數。它有如下屬性:git

  Duration:緩存的時間,以秒爲單位,理論上緩存時間能夠很長,但實際上當系統資源緊張時,緩存空間仍是會被系統收回。web

  VaryByParam:以哪一個字段爲標識來緩存數據,好比當「ID」字段變化時,須要改變緩存(仍可保留原來的緩存),那麼應該設VaryByParam爲"ID"。這裏你能夠設置如下幾個值:瀏覽器

  • * = 任何參數變化時,都改變緩存。
  • none = 不改變緩存。

  以分號「;」爲間隔的字段名列表 = 列表中的字段發生變化,則改變緩存。緩存

  Location:緩存數據放在何處。緩存位置很重要,若是存在服務器上,那麼全部用戶看到的緩存視圖都會同樣,若是存在客戶端,那麼用戶只會看到本身的緩存。好比:若是是一些私人信息,那就不能存在服務器上。你能夠設置如下值:安全

  • · Any :默認值,輸出緩存可位於產生請求的瀏覽器客戶端、參與請求的代理服務器(或任何其餘服務器)或處理請求的服務器上。
  • · Client:輸出緩存位於產生請求的瀏覽器客戶端上。
  • · Downstream 輸出緩存可存儲在任何 HTTP 1.1 可緩存設備中,源服務器除外。這包括代理服務器和發出請求的客戶端。 
  • · Server:輸出緩存位於處理請求的 Web 服務器上。
  • · None:對於請求的頁,禁用輸出緩存。
  • · ServerAndClient:輸出緩存只能存儲在源服務器或發出請求的客戶端中。代理服務器不能緩存響應。
  •   NoStore:該屬性定義一個布爾值,用於決定是否阻止敏感信息的二級存儲。

  如下給出一個簡單的例子,在頁面上顯示一個時間,設置緩存爲10秒,在10秒刷新,輸出的值都不會改變。服務器

    [OutputCache(Duration=5)]
    public ActionResult Index(string name)
    {
        return Content(DateTime.Now.ToString());
    }

  除了直接在Action或者類的定義前加上屬性,也可使用配置文件,這樣就能夠動態配置你的緩存模式了。
  在<system.web>節中,添加以下配置:cookie

<outputCacheSettings>
    <outputCacheProfiles>
        <add name="Cache1Hour" duration="3600" varyByParam="none"/>
    </outputCacheProfiles>
</outputCacheSettings>
</caching>

  那麼在Controller中能夠這樣使用:app

[OutputCache(CacheProfile="Cache1Hour")]
public string Index()
{
   return DateTime.Now.ToString("T");
}

  [擴展]在已經緩存的頁面上添加動態內容框架

  爲了提升用戶體驗,咱們會使用緩存技術,可是有時咱們會須要在頁面上改變內容,如:提供一些動態信息、廣告的變化等。
  此時咱們能夠調用 HttpResponse.WriteSubstitution() 方法。

@Response.WriteSubstitution(News.RenderNews);

  其中News.RenderNews是一個靜態方法,它的定義以下,這個方法用來隨機顯示三條廣告詞。

複製代碼
public class News
{
    public static string RenderNews(HttpContext context)
    {
        var news = new List<string> 
        { 
           "Gas prices go up!", 
            "Life discovered on Mars!", 
             "Moon disappears!" 
        };
            
        var rnd = new Random();
        return news[rnd.Next(news.Count)];
    }
}
複製代碼

  將Response.WriteSubstitution()寫成擴展方法的示例:

複製代碼
public static class AdHelper
    {
        public static void RenderBanner(this HtmlHelper helper)
        {
            var context = helper.ViewContext.HttpContext;
            context.Response.WriteSubstitution(RenderBannerInternal);
        }

     private static string RenderBannerInternal(HttpContext context)
        {
            var ads = new List<string> 
                { 
                    "/ads/banner1.gif", 
                    "/ads/banner2.gif", 
                    "/ads/banner3.gif" 
                };

            var rnd = new Random();
            var ad = ads[rnd.Next(ads.Count)];
            return String.Format("<img src='{0}' />", ad);
        }

    }
複製代碼

  調用方法以下:

<% Html.RenderBanner(); %>

  二、ActionName

  ActionName用於規定Action的名稱,當使用此過濾器後,MVC將再也不理會路徑中的Action名稱,而是用標記中的ActionName代替方法名中的ActionName。例如:

[ActionName("關於")]
public ActionResult About()
{
    return View();
}

  此時,當訪問/Home/About時匹配不到Action,須要訪問/Home/關於才能訪問該Action,而且使用的是名爲"關於"的視圖。

  三、NonAction

  NonAction標記一個Action只是一個普通的方法,不做爲MVC的Action。如:

複製代碼
    public class HomeController : Controller
    {
        [NonAction]
        public ActionResult Index(string name)
        {
            return Content(DateTime.Now.ToString());
        }
    }
複製代碼

  此時訪問/Home/Index將找不到Action。

  四、RequireHttps

  強制使用Https從新發送請求;如:

複製代碼
    public class HomeController : Controller
    {
        [RequireHttps]
        public ActionResult Index(string name)
        {
            return Content(DateTime.Now.ToString());
        }
    }
複製代碼

  若是請求:http://localhost/Home/Index 將跳轉到 https://localhost/Home/Index。

  五、ValidateInput

  該Action是否過濾Html等危險代碼(ASP.NET MVC在aspx中設置<%@ Page 的屬性沒法完成等同任務。)

  如如下代碼:

複製代碼
    public class HomeController : Controller
    {
        [ValidateInput(true)]
        public ActionResult Index(string name)
        {
            return Content(DateTime.Now.ToString());
        }
    }
複製代碼

  上述代碼表示開啓安全驗證,當輸入如下路徑時:

  http://localhost:3833/home/index?name=%3Ca%3E123%3C/a%3E    //http://localhost:3833/home/index?name=<a>123</a>

  程序報以下錯誤:

「/」應用程序中的服務器錯誤。


從客戶端(name="<a>123</a>")中檢測到有潛在危險的 Request.QueryString 值。

  六、AllowHtml

  AllowHtml用於禁用某個字段、屬性的驗證,則可使用MVC3中的AllowHtml屬性實現。如:

複製代碼
namespace Mvc權限控制.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index(Content c)
        {
            return View(); ;
        }
    }

    public class Content
    {
        public int Id { get; set; }

        [AllowHtml]
        public string Body { get; set; }
    }
}
複製代碼

  頁面代碼:

複製代碼
<body>
    <div>
        <form action="/Home/Index" method="post">
            請輸入Id:<input type="text" name="Id" />
            請輸入姓名:<input type="text" name="Body" />
            <input type="submit" value="提交" />
        </form>
    </div>
</body>
複製代碼

  注意,若是將上面Body的屬性AllowHtml標記去掉,將報以下錯誤:

「/」應用程序中的服務器錯誤。


從客戶端(Body="<a>123</a>")中檢測到有潛在危險的 Request.Form 值。

  七、SessionState自定義Session控制

  SessionState只能應用於Controller,不能做用於某一個Action。可選值以下:

  1. Default = 0,使用默認 ASP.NET 邏輯來肯定請求的會話狀態行爲。默認邏輯是尋找 System.Web.IHttpHandler 中是否存在標記會話狀態接口。
  2. Required = 1,爲請求啓用徹底的讀寫會話狀態行爲。此設置將覆蓋已經過檢查請求的處理程序肯定的任何會話行爲。
  3. ReadOnly = 2,爲請求啓用只讀會話狀態。這意味着會話狀態沒法更新。此設置將覆蓋已經過檢查請求的處理程序肯定的任何會話狀態行爲。
  4. Disabled = 3,未啓用會話狀態來處理請求。此設置將覆蓋已經過檢查請求的處理程序肯定的任何會話行爲。
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
 
  

  八、Http動做過濾器

  [HttpGet] [HttpSet] [HttpDelete] [HttpPut]  此4個過濾器用於篩選Http請求,[HttpGet]只處理Get請求,[HttpPost]只處理Post請求,[HttpDelete]只處理Delete請求,[HttpPut]只處理put請求。

   九、ValidateAntiForgeryToken

  防止跨站請求攻擊時會在cookie添加一個隨機項,而後添加一個隨機數到表單裏的<input type="hidden" />而ValidateAntiForgeryToken就是用於檢測兩項是否相等。主要包括:
  (1)請求的是否包含一個約定的AntiForgery名的cookie

  (2)請求是否有一個Request.Form["約定的AntiForgery名"],約定的AntiForgery名的cookie和Request.Form值是否匹配。

  10.AsyncTimeout 

  異步訪問過時設置

  11.HandleError 錯誤過濾器

  HandleErrorAttribute中,提供了4種基本屬性:

  1. ExceptionType:指定處理的異常類型
  2. View:指定顯示的View
  3. Master:指定要套用的Master頁面
  4. Order:設置執行的順序

  12.AllowAnonymous 

  身份驗證過濾器,容許匿名用戶訪問

  13.ChildActionOnly 

   聲明該Action不能直接經過Url 訪問但能夠做爲某一個Action的子Action訪問。

 

 

2、過濾器的類別以及執行順序:

  在Asp.net MVC中一共有4種過濾器,而且按照以下順序依次執行。

  1. 受權篩選器:AuthorizationFilters
  2. 動做篩選器:ActionFilters
  3. 響應篩選器:ResultFilters
  4. 異常篩選器:ExceptionFilters

  Controller最終是經過Controller的ExecuteCore完成的,這個方法經過調用ControllerActionInvoker的InvodeAction方法完成最終對於Action的調用。

  其時序圖以下:

  

3、自定義過濾器接口

  ActionFilterAttribute的定義以下,容許咱們在Action執行以前或者以後,在Action的返回結果被處理以前或者以後進行自定義處理。

複製代碼
using System;
namespace System.Web.Mvc
{
  [AttrubiteUsage(ArrtibuteTargets.Class | AttributeTargets.Method,Inherited = true,AllowMultiple = false)]
  public abstract class ActionFilterAttribute : FilterAttribute,IActionFilter,IResultFilter
  {     
public virtual void OnActionExecuting(ActionExecutingContext filterContext){}     public virtual void OnActionExecuted(ActionExecutedContext filterContext){}     public virtual void OnResultExecuting(ResultExecutingContext filterContext){}     public virtual void OnResultExecuted(ResultExecutedContext filterContext){}   } }
複製代碼

  咱們須要實現IActionFilter接口:

public interface IActionFilter
{
  void OnActionExecuting(ActionExecutingContext filterContext);
  void OnActionExecuted(ActionExecutedContext filterContext);
}

  對於ResultFilter來講,咱們須要實現接口IResultFilter

public interface IResultFilter
{
  void OnResultExecuting(ResultExecutingContext filterContext);
  void OnResultExecuted(ResultExecutedContext filterContext);
}

AuthorizationFilter和ExceptionFilter都比較簡單,只有一個方法。

複製代碼
public interface IAuthorizationFilter
{
  void OnAuthorization(AuthorizationContext filterContext);
}
public interface IExceptionFilter
{
  void OnException(ExceptionContext filterContext);
}
複製代碼

  一、自定義Filter

  自定義Filter須要繼承ActionFilterAttribute抽象類,重寫其中須要的方法,來看下ActionFilterAttribute類的方法簽名。

複製代碼
    //表示全部操做-篩選器特性的基類。
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
    {
        protected ActionFilterAttribute();
        //    在Action執行以後由 MVC 框架調用。
        public virtual void OnActionExecuted(ActionExecutedContext filterContext);
        //     在Action執行以前由 MVC 框架調用。
        public virtual void OnActionExecuting(ActionExecutingContext filterContext);
        //     在執行Result後由 MVC 框架調用。
        public virtual void OnResultExecuted(ResultExecutedContext filterContext);
        //     在執行Result以前由 MVC 框架調用。
        public virtual void OnResultExecuting(ResultExecutingContext filterContext);
    }
複製代碼

  所以自定義過濾器能夠選擇適當的方法來重寫方可。下面來舉個簡單的例子:檢查登陸狀態的過濾器,沒有登陸則跳轉到登陸頁

  控制器代碼:

複製代碼
[CheckLogin]  //此處爲自定義屬性,要引用相應的命名空間
public ActionResult Index()
{
    return View();
}

public ActionResult Login()   //此Action自動往cookie裏寫入登陸信息
{
    HttpCookie hcUserName = new HttpCookie("username","admin");
    HttpCookie hcPassWord = new HttpCookie("password","123456");
    System.Web.HttpContext.Current.Response.SetCookie(hcUserName);
    System.Web.HttpContext.Current.Response.SetCookie(hcPassWord);
    return View();
}
複製代碼

  過濾器代碼:

複製代碼
    public class CheckLogin : ActionFilterAttribute
    {
        //在Action執行以前 亂了點,其實只是判斷Cookie用戶名密碼正不正確而已而已。
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            HttpCookieCollection CookieCollect = System.Web.HttpContext.Current.Request.Cookies;if (CookieCollect["username"] == null || CookieCollect["password"] == null)
            {
                filterContext.Result = new RedirectResult("/Home/Login");
            }
            else
            {
                if (CookieCollect["username"].Value != "admin" && CookieCollect["password"].Value != "123456")
                {
                    filterContext.Result = new RedirectResult("/Home/Login");
                }
            }
        }
    }//本示例貪圖方便,將要跳轉到的Action放在同一個Controller下了,若是將過濾器放到Controller類頂部,則永遠也跳不到這個LoginAction。
複製代碼

  此過濾器實現的效果是,當用戶Cookie中用戶名和密碼不正確則跳轉到登陸頁,注意濾器也能夠放在整個Controller類的頂部,表示該Controller下的全部Action都執行該項檢查。這樣一來,控制器裏的代碼很是漂亮,不再用全部的Action裏都充斥着判斷登陸的代碼了。

  二、帶參數的自定義Filter

  首先,仍是按照以前添加自定義過濾器的方法,添加一個自定義過濾器,只是裏面多了一個屬性,代碼以下:

複製代碼
    public class FilterAttribute : ActionFilterAttribute
    {
        public string Message { get; set; }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            filterContext.HttpContext.Response.Write("Action執行以前" + Message + "<br />");
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
            filterContext.HttpContext.Response.Write("Action執行以後" + Message + "<br />");
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            base.OnResultExecuting(filterContext);
            filterContext.HttpContext.Response.Write("返回Result以前" + Message + "<br />");
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);
            filterContext.HttpContext.Response.Write("返回Result以後" + Message + "<br />");
        }
    }
複製代碼

  而後在調用過濾器的時候,添加上該參數,Controller代碼以下:

        [Filter(Message="劉備")]  //參數給上
        public ActionResult Index()
        {
            return View();
        }

  輸出結果以下:

  

   若是標籤打到Controller上的話,TestFilterAttributeFilter將做用到Controller下的全部的Action。

  默認狀況下Action上打了某個自定義標籤後,雖然在Controller上也打上了此標籤,但它只有Action上的標籤起做用了。
  補充:若是Action沒有打上該標籤,那麼Controller上的標籤便會被執行。

   若是想讓Action上的標籤執行一次,而後Controller上的標籤也執行一次,那麼應該如何操做呢?

   咱們只需在FilterAttribute類的定義上打上標記[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]便可【下面類的最上面紅色字體部分】,也就是讓其成爲能夠屢次執行的Action代碼以下:

    [AttributeUsage(AttributeTargets.All,AllowMultiple = true)]
    public class FilterAttribute : ActionFilterAttribute
    {
        public string Message { get; set; }
        ......
  }

  三、全局過濾器

  有時咱們想有些公共的方法須要每一個Action都執行,可是又不想再每個Controller上都打上Action標籤,怎麼辦?幸虧Asp。Net MVC3帶來了一個美好的東西,全局Filter。而怎麼註冊全局Filter呢?答案就在Global.asax中。讓咱們看如下代碼,我是如何將上面咱們定義的TestFilterAttribute 註冊到全局Filter中。

     public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
            //註冊全局過濾器
            filters.Add(new TestFilterAttribute() { Message="全局"});
        }

  這樣就每一個Action都會執行此過濾器,而沒必要每一個Controller頂部都加上標籤。

 

 

 
 
分類: MVC
 
1
0
 
(請您對文章作出評價)
 
« 上一篇: 進程、應用程序域與上下文之間的關係
» 下一篇: Process類 進程管理器Demo
轉:http://www.cnblogs.com/kissdodog/archive/2013/01/21/2869298.html
相關文章
相關標籤/搜索