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
相关文章
相关标签/搜索