zoukankan      html  css  js  c++  java
  • ASP.NET MVC学习之过滤器篇(2)

    下面我们继续之前的ASP.NET MVC学习之过滤器篇(1)进行学习。

    3.动作过滤器

    顾名思义,这个过滤器就是在动作方法调用前与调用后响应的。我们可以在调用前更改实际调用的动作,也可以在动作调用完成之后更改最终返回的结果,当然很多人一定不太明白这个到底可以干什么,

    下面我们举一个比较实际的例子:

    相信理解过网站的安全的一定知道跨站请求(CSRF具体可以自行百度,这里我就不去解释了),当然也有解决方案,那就是给页面中增加一个识别码,当页面进行POST请求时,首先判断识别码是否正确,

    如果正确则继续进行操作。并且在执行完成之后重新分配一个新的识别码(当然也可以只用一个识别码直到会话结束),这样就可以加大进行跨站请求的难度。而动作过滤器的所处的生命周期刚好符合,

    下面我们就开始编写这个过滤器类。

    首先我们在Filter文件夹中新建一个ViewMacFilterAttribute类,并且这个类需要继承FilterAttribute,同时还要实现IActionFilter接口:

     1 namespace MvcStudy.Filter
     2 {
     3     public class ViewMacFilterAttribute : FilterAttribute , IActionFilter
     4     {
     5 
     6         public void OnActionExecuted(ActionExecutedContext filterContext)
     7         {
     8             string viewMac = Guid.NewGuid().ToString();
     9             filterContext.HttpContext.Session["vmac"] = viewMac;
    10             filterContext.Controller.ViewBag.ViewMac = viewMac;
    11         }
    12 
    13         public void OnActionExecuting(ActionExecutingContext filterContext)
    14         {
    15             object viewMac = filterContext.HttpContext.Session["vmac"];
    16             string strMac = filterContext.HttpContext.Request.Form["viewMac"];
    17             filterContext.Result = new HttpNotFoundResult();
    18             if (viewMac != null && strMac != null)
    19             {
    20                 if (viewMac.Equals(strMac))
    21                 {
    22                     filterContext.Result = null;
    23                 }
    24             }
    25         }
    26     }
    27 }

     这里我们实现了IActionFilter 接口中的OnActionExecuted方法和OnActionExecuting方法,它们分别对应着动作执行结束和动作执行前,通过OnActionExecuting中的代码,我们可以清楚的看到我们首先从Session中获取识别码,然后又从页面中的表单获取客户端的识别码,

    这里我们可以看到我们首先默认返回的结果是404,如果比配成功则将Result设置为NULL,如果ResultNULL是会正常调用对应的活动的。接着就是OnActionExecuted方法中的功能,仅仅只是重新分配一个识别码,并且保存进Session中。

     

    注:这种方式会导致一个页面进行了POST请求之后,识别码变换之后。其他页面的提交功能就会失败,所以还要加以ajax去辅助,或者就是一个用户会话分配一个识别码,直到用户会话结束。

     

    有了这个过滤器之后我们就可以进行实际的测试了,首先我们先在Home控制器中写入如下代码,并在Views/Home下新建Index.cshtml以及List.cshtml,其中List.cshtml中的页面如下所示:

     1 @{
     2     ViewBag.Title = "List";
     3 }
     4 
     5 <h2>List</h2>
     6 @using(Html.BeginForm())
     7 {
     8     @Html.Hidden("viewMac", (string)ViewBag.ViewMac)
     9     <input type="submit" value="submit" />
    10 }

    然后就是Home控制器:

     1 namespace MvcStudy.Controllers
     2 {
     3     public class HomeController : Controller
     4     {
     5         [MobilResultFilter]
     6         public ActionResult Index()
     7         {
     8 
     9             return View();
    10         }
    11 
    12 
    13         public ActionResult List()
    14         {
    15             string viewMac = Guid.NewGuid().ToString();
    16             Session["vmac"] = viewMac;
    17             ViewBag.ViewMac = viewMac;
    18             return View();
    19         }
    20 
    21         [ViewMacFilter]
    22         [HttpPost]
    23         public ActionResult List(string action)
    24         {
    25             return View();
    26         }
    27     }
    28 }

    这里我们可以看到默认的List动作中会分配识别码,而POST请求对应的List方法加上了我们之前写的过滤器,现在我们可以先打开这页面然后提交,会发现只是刷新了,接着我们把List.cshtml中的@Html.Hidden("viewMac", (string)ViewBag.ViewMac) 删去,重新进入这个页面,在点击提交,就能发现出现了404的错误,这样我们就可以防止跨站请求了。

    4.结果过滤器

    上面讲的仅仅只是动作过滤器,在动作执行完成之后都会返回一个结果,即使到这里了,我们依然可以修改最终的结果,之前在讲路由器部分的时候,曾今举过一个例子,就是根据UserAgent去判断是否为手机,并跳转到对应的控制器下的对应动作。但是很多时候手机页面与PC页面的数据都是一摸一样的,如果像之前那样就会导致重复代码的出现,那么我们就可以利用结果过滤器,在动作执行完成之后,判断是否为手机从而改变最后呈现的视图。

     

    下面我们继续在Filter文件夹下新建一个MobilResultFilterAttribute类,并且这个类依然要继承FilterAttribute,同时还要实现IResultFilter接口,实现代码如下:

     1 namespace MvcStudy.Filter
     2 {
     3     public class MobilResultFilterAttribute : FilterAttribute , IResultFilter
     4     {
     5 
     6         public void OnResultExecuted(ResultExecutedContext filterContext)
     7         {
     8 
     9         }
    10 
    11         public void OnResultExecuting(ResultExecutingContext filterContext)
    12         {
    13             if (filterContext.HttpContext.Request.UserAgent.Contains("Android"))
    14             {
    15                 ((ViewResult)filterContext.Result).ViewName = "List";
    16             }
    17         }
    18     }
    19 }

     为了能够以最简单的方式说明,所以笔者仅仅判断了UserAgent是否含有Android,如果含有就修改最终的视图名称,这样我们就可以通过注解属性的方式实现,而不需要放在控制器中或者在动作中进行判断。

    下面我们依然要以测试为主,我们还是使用Home控制器:

    1         [MobilResultFilter]
    2         public ActionResult Index()
    3         {
    4 
    5             return View();
    6         }

     首先我们通过正常的方式访问,然后让Chrome模拟手机进行访问,这个时候我们就可以发现最终的页面会是List而不是Index

    上面的3和4我们都要自己去继承对应的接口,同时还要继承FilterAttribute类,其实ASP.NET MVC中已经为我们写好了一个默认的类,就是ActionFilterAttribute,我们源码中的定义:

    1 public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IresultFilter

     它已经继承了FilterAttribute,同时也实现了IActionFilterIResultFilter接口,这样可以可以少记一些关键的名称。

    5.无注解属性过滤与全局过滤器

    通过之前的几点,大家可以发现我们都是使用注解属性的方式进行过滤,其他我们也可以直接在控制器中实现,比如下面的代码:

     1 namespace MvcStudy.Controllers
     2 {
     3     public class HomeController : Controller
     4     {
     5         protected override void OnActionExecuted(ActionExecutedContext filterContext)
     6         {
     7             base.OnActionExecuted(filterContext);
     8         }
     9 
    10         protected override void OnActionExecuting(ActionExecutingContext filterContext)
    11         {
    12             base.OnActionExecuting(filterContext);
    13         }
    14 
    15         protected override void OnAuthorization(AuthorizationContext filterContext)
    16         {
    17             base.OnAuthorization(filterContext);
    18         }
    19 
    20         protected override void OnException(ExceptionContext filterContext)
    21         {
    22             base.OnException(filterContext);
    23         }
    24 
    25         protected override void OnResultExecuted(ResultExecutedContext filterContext)
    26         {
    27             base.OnResultExecuted(filterContext);
    28         }
    29 
    30         protected override void OnResultExecuting(ResultExecutingContext filterContext)
    31         {
    32             base.OnResultExecuting(filterContext);
    33         }
    34 
    35         [MobilResultFilter]
    36         public ActionResult Index()
    37         {
    38 
    39             return View();
    40         }
    41 
    42 
    43         public ActionResult List()
    44         {
    45             string viewMac = Guid.NewGuid().ToString();
    46             Session["vmac"] = viewMac;
    47             ViewBag.ViewMac = viewMac;
    48             return View();
    49         }
    50 
    51         [ViewMacFilter]
    52         [HttpPost]
    53         public ActionResult List(string action)
    54         {
    55             return View();
    56         }
    57     }
    58 }

    我们可以看到控制器中其实已经实现了上面所有的接口,当然我建议使用注解属性,这样可以尽量的分离关注点,控制器的代码会很杂乱。

    关于全局过滤器,唯一的区别就是我们需要在FilterConfig类中的RegisterGlobalFilters方法中使用filters.add增加上面我们所写的过滤器即可,并没有太大的特殊(FilterConfig在App_Start,在ASP.NET MVC 4以上才有这个文件

     

    6.内建过滤器

    关于内建过滤器我们这里就列举出来以下,因为上手很快。

    RequireHttps   强迫对动作使用Https协议

    OutputCache   缓存一个动作方法的输出

    ValidateInput   与安全有关的授权过滤器

    AsyncTimeout/NoAsyncTimeout  用于异步控制器

    ChildActionOnly 只能作为子操作进行调用

    到此为止关于过滤器部分就结束了。

    下面是之前的前面ASP.NET MVC学习连载:

    ASP.NET MVC学习之路由器篇(1)

    ASP.NET MVC学习之路由器篇(2)

    ASP.NET MVC学习之路由器篇(3)

    ASP.NET MVC学习之控制器篇

    ASP.NET MVC学习之过滤器篇(1)

  • 相关阅读:
    $(document).ready() 与$(window).load()
    关于.NET玩爬虫这些事 【初码干货】
    关于c# .net爬虫
    UIScollView Touch事件
    UISearchBar 点击X 按钮收键盘
    IOS7 UITableView一行滑动删除后 被删除行的下一行的点击事件将被忽略解决办法
    IOS 使用dispatch_once 创建单例
    IOS 定位 单例
    IOS拷贝文件到沙盒
    IOS后台运行
  • 原文地址:https://www.cnblogs.com/yaozhenfa/p/asp_net_mvc_filter_2.html
Copyright © 2011-2022 走看看