来源:http://www.php.cn/csharp-article-359736.html
 

一、过滤器简介

1.1、理解什么是过滤器

1、过滤器(Filters)就是向请求处理管道中注入额外的逻辑。提供了一个简单而优雅的方式来实现横切关注点。

2、所谓的过滤器(Filters),MVC框架里面的过滤器完全不同于ASP.NET平台里面的Request.Filters和Response.Filter对象,它们主要是实现请求和响应流的传输。通常我们所说的过滤器是指MVC框架里面的过滤器。

3、过滤器可以注入一些代码逻辑到请求处理管道中,是基于C#的Attribute的实现。当负责调用Action的类ControllerActionInvoker在调用执行Action的时候会检查Action上面的Attribute并查看这些Attribute是否实现了指定的接口,以便进行额外的代码注入处理

1.2、理解为什么要使用过滤器

假设你做了一个小项目,其中某个功能是操作管理用户信息模块,有这样一个需求,对用户信息管理必须是已通过认证的用户才能操作,我们可以在每一个Action方法里面检查认证请求,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using MvcFilterDmo.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
 
namespace MvcFilterDmo.Controllers
{
  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      if (!Request.IsAuthenticated)
      {
        FormsAuthentication.RedirectToLoginPage();
      }
      //操作部分...
      return View();
    }
    public ActionResult Insert()
    {
      if (!Request.IsAuthenticated)
      {
        FormsAuthentication.RedirectToLoginPage();
      }
      //操作部分...
      return View();
    }
    public ActionResult Update()
    {
      if (!Request.IsAuthenticated)
      {
        FormsAuthentication.RedirectToLoginPage();
      }
      //操作部分...
      return View();
    }
    public ActionResult Delete()
    {
      if (!Request.IsAuthenticated)
      {
        FormsAuthentication.RedirectToLoginPage();
      }
      //操作部分...
      return View();
    }
    //其他Action操作方法
    //...
  }
}

通过上面的代码,可以发现使用这种方式检查请求认证有许多重复的地方,这也就是为什么要使用过滤器的原因,使用过滤器可以实现相同的效果。如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using MvcFilterDmo.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
 
namespace MvcFilterDmo.Controllers
{
  [Authorize]
  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      //操作部分...
      return View();
    }
    public ActionResult Insert()
    {
      //操作部分...
      return View();
    }
    public ActionResult Edit()
    {
      //操作部分...
      return View();
    }
    public ActionResult Delete()
    {
      //操作部分...
      return View();
    }
    //其他Action操作方法
    //...
  }
}

过滤器是.NET里面的特性(Attributes),它提供了添加到请求处理管道的额外方法。这里使用Authorize过滤器可以实现同样的效果,不过代码就显然比之前更加简洁优雅。

二、过滤器的使用

2.1、基本类型的过滤器

过滤器实现的机制:在MVC框架调用一个Action之前,它会检查方法的定义中是否实现了特性(Attributes),如果实现的话,那么在请求处理管道适当的位置,该特性定义的方法会被调用。

ActionFilterAttribute类既实现了IactionFilter接口,也实现IResultFilter接口。这是一个抽象类,它要求你必须提供一个实现。AuthorizeAttribute和HandleErrorAttribute类,则包含了一些有用的特性,并且可以不必创建派生类进行使用。

2.2、过滤器的应用、应用方式以及执行顺序

应用: 过滤器可以被应用到控制器上也可以用到Action方法上,应用到控制上时,表示所有的Action方法都有了这个过滤器,并且可以混合使用,或多次使用,如下所示:

1
2
3
4
5
6
7
8
9
10
11
[A] //表示所有的Action方法都会应用A过滤器
Public class DemoController:Controller
{
  [B]//B,C过滤器只作用于此Action方法,但它也会有A过滤器的应用效果
  [C]
  Public ActionResult Index()
  {
     //操作部分...
     return View();
  }
}

应用方式:特性的方式,如上面代码所示。

执行顺序:相同类型过滤器,执行顺序靠近方法的先执行,不同类型的过滤器一般执行顺序为【authorize--->action--->actionResult】至于异常过滤器不分先后,只要抛出异常时就会执行异常过滤器。如果要调整执行顺序,可以通过调整Order方法值大小来控制执行顺序,值越小,越先执行。下图是Action/Result过滤器应用的执行顺序图

(1)、相同类型过滤器应用示例:两个自定义Action过滤器MyFirstFilter,MyThreeFilter应用到同一个Action方法Index上。

Three控制器代码如下:

MyFirstFilter 代码如下:

MyThreeFilter代码如下:

运行结果如下:

(2)、不同类型过滤器应用示例:有一个自定义Action过滤器MyFirstFilter,有一个自定义Result过滤器MySecondFilter,应用到同一个Action方法Index上。

Three控制器代码如下:

MyFirstFilter 代码如下:

MySecondFilter代码如下:

运行结果如下:

看完上面的解释,可能你现在对这些过滤器的执行顺序,以及如何自定义过滤器还不明白,不要紧,下面我们会逐一介绍这几个基本的过滤器的使用,以及如何自定义过滤器。

2.3、使用授权过滤器

所有实现了IAuthorizationFilter接口的都可以称之为授权过滤器:其定义如下:

1
2
3
4
public interface IAuthorizationFilter
   {
      void OnAuthorization(AuthorizationContext filterContext);
   }

由于MVC框架系统自带的AuthorizeAttribute实现有一些突出的功能,而这种牵涉到安全的代码一定要谨慎的编写,所以一般我们不会直接实现这个接口,而是去继承AuthorizeAttribute这个类,并重写其AuthorizeCore方法,签名为: bool AuthorizeCore(HttpContextBase httpContext) 而处理授权失败的时候,可以重写其HandleUnauthorizedRequest方法,其签名为: void HandleUnauthorizedRequest(AuthorizationContext context) 。注意:验证与授权是两回事,验证发生在授权之前。

默认的授权过滤器已经有了验证的功能,其验证的机理是利用Asp.net平台自带的验证机制,如表单验证和Windows验证。除了验证功能,它本身还有授权的功能。授权过滤器是所有过滤器中最早运行的。

经过Route到达了控制器的时候,在调用Action之前,MVC框架会检测在相关的Action上是否有授权过滤器,如果有会调用OnAuthorization方法,如果此方法批准了请求,才会调用相应的Action。

使用授权过滤器几种情况如下:

1.直接在Action上或者控制器上加Authorize,表示启用了验证,但不牵涉到授权。

2.添加Authorize(Users=“a,b”)],表示启用了验证,并且也启用了授权,只有a或者b用户能访问此控制器。

3.当添加Authorize(Roles=“admin,Member”)]时的步骤如下:

---利用asp.net自带的角色提供者,或者实现自己的角色提供者,实现自己的角色提供者时,只需要集成RoleProvider类型,并实现其中的所有方法或部分方法,最好实现所有方法。

---在Web程序的根目录的Web.config文件中配置角色管理者。

---在适当的Action中利用Roles类型来访问自己创建的RoleProvider中的相关方法。

使用内置的授权过滤器

MVC框架内置的授权过滤器AuthorizeAttribute,它允许我们使用这个类的两个公共属性来指定授权策略,如下所示:

Users和Roles两者是并且的关系,例如Users=“a,b,c”,Roles=“admin”,表示用户是a,b,c 其中一个并且是Admin角色才能访问。

创建自定义的授权过滤器

方式一:直接实现IAuthorizationFilter接口,但不推荐这样做,因为牵涉到安全方面的代码。

方式二:继承AuthorizeAttribute这个类,并重写其AuthorizeCore方法,签名为: bool AuthorizeCore(HttpContextBase httpContext),代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyAuthorizeAttribute : AuthorizeAttribute
  {
    private string[] allowedUsers;
    public MyAuthorizeAttribute(params string[] users)
    {
      allowedUsers = new string[] { "admin""user1""xf" };
    }
 
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
      return httpContext.Request.IsAuthenticated &&allowedUsers.Contains(httpContext.User.Identity.Name,
        StringComparer.InvariantCultureIgnoreCase);
    }
  }

2.4、使用动作过滤器

动作过滤器是可以以用于任何目的的多用途过滤器,创建自定义动作过滤器需要实现IActionFilter接口,该接口代码如下所示:

该接口定义了两个方法,MVC框架在调用动作方法之前,会调用OnActionExecting方法。在调用动作方法之后,则会调用OnActionExecuted方法。

实现OnActionExecting方法

参数ActionExecutingContext对象继承于ControllerContext,其中的2个属性:

ActionDescriptor:提供了关于Action方法的相关信息

Result:类型为ActionResult,通过给这个属性设置一个非null的值就可以取消这个请求。

我们可以用过滤器来取消一个请求,通过设置Result属性即可。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyActionFilterAttribute : FilterAttribute, IActionFilter
  {
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
      if(filterContext.HttpContext.Request.IsLocal)
      {
        filterContext.Result = new HttpNotFoundResult();
      }
    }
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
      //未做实现
    }
  }

这个例子通过用OnActionExecuting方法检查请求是否来自本地机器,如果是,编队用户返回一个“404”未找到的响应。运行结果如下图:

实现OnActionExecuted方法

我们也可以通过OnActionExecuted方法来执行一些跨越动作方法的任务,下面这个例子是计算动作方法运行的时间,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyActionFilterAttribute : FilterAttribute, IActionFilter
  {
    private Stopwatch timer;
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
      timer = Stopwatch.StartNew();
    }
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
      timer.Stop();
      if (filterContext.Exception == null)
      {
        filterContext.HttpContext.Response.Write(
          string.Format("动作方法延迟的时间: {0}",
            timer.Elapsed.TotalSeconds));
      }
    }
  }
}

我们将自定义的动作过滤器MyActionFilter应用到HomeController的Index方法上,运行结果如下:

2.5、使用结果过滤器

结果过滤器是多用途的过滤器,他会对动作方法所产生结果进行操作,结果过滤器实现IResultFilter接口,创建自定义结果过滤器需要现IResultFilter接口,该接口代码如下所示:

当结果过滤器运用于一个动作方法时,会在动作方法返回动作结果之前,调用OnResultExecuting方法,在返回动作结果之后,会调用OnResultExecuted方法。下面这个例子是计算动作方法返回结果运行的时间,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyResultFilterAttribute : FilterAttribute, IResultFilter
  {
    private Stopwatch timer;
    public void OnResultExecuting(ResultExecutingContext filterContext)
    {
      timer = Stopwatch.StartNew();
    }
    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
      timer.Stop();
      filterContext.HttpContext.Response.Write(string.Format("结果执行延迟时间: {0}", timer.Elapsed.TotalSeconds));
    }
}

我们将自定义的结果过滤器MyResultFilter应用到HomeController的Index方法上,运行结果如下:

需要注意的是:动作过滤器是运行在页面输出之前,结果过滤器是运行在页面输出之后。

2.6、使用异常过滤器

异常过滤器只有在调用一个动作方法而抛出未处理的异常才会运行,这种异常来自以下位置:

A、另一种过滤器(授权、动作、或结果过滤器)。

B、动作方法本身。

C、当动作结果被执行时。

使用内置的异常过滤器

HandleErrorAttribute(处理程序错误特性),它是MVC内嵌的异常过滤器,有以下3个重要的属性:

1.ExceptionType:类型为Type,表示希望被此过滤器处理的异常类型,包括其子类型,默认值为System.Exception

2.View:类型为string,表示此过滤器呈递的视图页面,默认值为Error

3.Master:呈递的视图页的母板页,如果不指定,视图会用其默认的母版页

内嵌的HandleErrorException只有在配置文件Web.config中配置的CustomError 的mode设置为on的时候才生效(其默认模式为RemoteOnly),如下图所示:

此过滤器还会给视图传递一个HandleErrorInfo类型的对象给视图,以便视图可以显示一些额外的关于错误的信息。下面是使用异常过滤器的示例。

应用到Index动作方法上:

在Views/Shared文件夹下添加一个显示异常信息的视图页SpecialError.cshtml,页面代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@model HandleErrorInfo
  <!DOCTYPE html>
  <html>
  <head>
    <meta name="viewport" content="width=device-width" />
    <title>SpecialError</title>
  </head>
  <body>
    <p>
      <p>
        There was a<b>@Model.Exception.GetType().Name</b>
        while rendering<b>@Model.ControllerName</b>'s
        <b>@Model.ActionName</b> action
      </p>
    </p>
  </body>
</html>

运行结果如下:

创建自定义的异常过滤器

如果我们对异常过滤器有特殊的需求,可以通过自定义的异常过滤器来完成,创建自定义异常过滤器必须实现IExceptionFilter接口,该接口代码如下:

当一个未知处理异常发生时,OnException方法会被调用。该方法的传递一个ExceptionContext对象,派生于ControllerContext类,定义了一些额外的过滤器专有属性如下表所示:

抛出的异常通过Exception属性是可以访问的。通过把ExceptionHandled属性设置为true,一个异常过滤器可以报告它已经处理了该异常,应用于一个动作的所有异常过滤器都会被调用。

需要注意的是:如果一个动作方法的所有异常过滤器均为把ExceptionHandled属性设置为true,MVC框架将使用默认的ASP.NET异常处理程序。

Result属性有异常过滤器使用,以告诉MVC框架要做什么,异常过滤器的两个主要应用是记录该异常到日志,并把适当的消息显示给用户。下面的代码将演示通过创建一个自定义的异常过滤器,当一个特定的钟类的未处理异常出现时,把该用户重定向到一个指定的错误页面。

1
2
3
4
5
6
7
8
9
10
11
12
public class MyExectionAttribute:FilterAttribute,IExceptionFilter
  {
    public void OnException(ExceptionContext filterContext)
    {
      if(!filterContext.ExceptionHandled&&
        filterContext.Exception is NullReferenceException)
      {
        filterContext.Result = new RedirectResult("~/Content/SpecialErrorPage.html");
        filterContext.ExceptionHandled = true;
      }
    }
}

然后在项目根目录添加一个名为Content的文件夹,在该文件夹下创建SpeciErrorPage.html文件,当异常被处理时,将以这个错误页面显示个用户。该页面代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
</head>
<body>
  <h1>Sorry</h1>
  <p>this is a Excetption test</p>
  There was aNullReferenceException while renderingHome's Index action
</body>
</html>

在控制器中应用MyExection异常过滤器,并主动让其抛出一个空引用异常,以便测试。

1
2
3
4
5
6
7
8
public class HomeController : Controller
  {
    [MyExection]
    public ActionResult Index()
    {
      throw new NullReferenceException();
    }
  }

运行结果如下:

总结:本文章简单总结了对过滤器的理解以及如何使用MVC框架内置基本的过滤器和如何自定义过滤器及应用。

以上就是Asp.Net MVC学习总结之过滤器详解(图文详解)的详细内容,更多请关注php中文网其它相关文章!

Asp.Net MVC学习总结之过滤器详解(转载)的更多相关文章

  1. ASP.NET MVC学习之模型验证详解

    ASP.NET MVC学习之模型验证篇 2014-05-28 11:36 by y-z-f, 6722 阅读, 13 评论, 收藏, 编辑 一.学习前的一句话 在这里要先感谢那些能够点开我随笔的博友们 ...

  2. Asp.Net MVC 扩展 Html.ImageFor 方法详解

    背景: 在Asp.net MVC中定义模型的时候,DataType有DataType.ImageUrl这个类型,但htmlhelper却无法输出一个img,当用脚手架自动生成一些form或表格的时候, ...

  3. Asp.Net MVC part2 View、Controller详解

    View详解Razor视图引擎简介HtmlHelper强类型页面 Razor视图引擎简介强大的@:表示使用C#代码,相当于aspx中的<%%>可以完成输出功能当遇到html标签时会认为C# ...

  4. 【部分】ASP.NET MVC的Controller接收输入详解

    原文:https://blog.csdn.net/lxrj2008/article/details/79455360 ASP.NET mvc的Controller要正确的响应用户发出的请求就要获取到用 ...

  5. ASP.NET MVC学习目录

    一.ASP.NET MVC原理详解 1.了解MVC架构模式 3.学习ASP.NET MVC的必备语言知识 4.MVC中的razor语法详解 5.ASP.NET MVC路由系统机制详细讲解 6.ASP. ...

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

    下面我们继续之前的ASP.NET MVC学习之过滤器篇(1)进行学习. 3.动作过滤器 顾名思义,这个过滤器就是在动作方法调用前与调用后响应的.我们可以在调用前更改实际调用的动作,也可以在动作调用完成 ...

  7. ASP.NET MVC学习之Ajax(完结)

    一.前言 通过上面的一番学习,大家一定收获不少.但是总归会有一个结束的时候,但是这个结束也意味着新的开始. 如果你是从事ASP.NET开发,并且也使用了第三方控件,那么一定会觉得ASP.NET开发aj ...

  8. MVC过滤器详解

    MVC过滤器详解   APS.NET MVC中(以下简称"MVC")的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理. ...

  9. ASP.NET MVC学习之视图篇(2)

    继ASP.NET MVC学习之视图(1)学习 4.HTML辅助器 虽然在ASP.NET MVC中我们已经摆脱了ASP.NET的控件,但是对于页面中需要循环标签的情况依然还是存在,可能很多人认为用for ...

随机推荐

  1. 12. The Biggest Safety Threat Facing Airlines 航空公司面临的最大安全威胁

    12. The Biggest Safety Threat Facing Airlines 航空公司面临的最大安全威胁 (1) The biggest safety threat facing air ...

  2. Codeforces Round #536 (Div. 2) E dp + set

    https://codeforces.com/contest/1106/problem/E 题意 一共有k个红包,每个红包在\([s_i,t_i]\)时间可以领取,假如领取了第i个红包,那么在\(d_ ...

  3. 文件类File

    文件类File继承结构: public class File extends Object implements Serializable, Comparable<File> 常用方法: ...

  4. Latex小技巧

    最近由于离散数学课程作业的需要, 使用$\LaTeX$写pdf报告, 积累了一些$\LaTeX$小技巧, 以后还会陆续补充. 1. 查看某个包的使用手册, 在命令行中输入texdoc XXX, 其中X ...

  5. IntelliJ IDEA的破解方法

    一.下载并安装, IntelliJ IDEA的官网:https://www.jetbrains.com 下载 下载 下载 二.破解. 百度下载一个 JetbrainsCrack-2.7-release ...

  6. python多版本管理包pyenv

    前言: CentOS7  默认版本 python2.7.5 ,但是目前项目开发都是在python3的环境下,而单独编译安装python3时会出现各种异常!!! 系统默认python2.7又不能删除,否 ...

  7. 项目Alpha冲刺(团队3/10)

    项目Alpha冲刺(团队3/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...

  8. 第二十四节:Java语言基础-讲解数组的综合应用

    数组的综合应用 // 打印数组 public static void printArray(int[] arr) { for(int x=0;x<arr.length;x++) { if(x!= ...

  9. 谈谈我们对userAgent的看法,为什么爬虫中需要userAgent?

    首先打开浏览器,按 F12 进入控制台(Console),然后输入:navigator.userAgent,即可看到 UA.例如: 1 2 Mozilla/5.0 (Windows NT 10.0; ...

  10. Windows10开发手记-RelativePanel使用详解

    Windows 10已于7月29号面向全球发布,同时Universal Windows Platform(UWP) SDK也已正式放出,配合VS 2015我们可以开发出通用的Windows App. ...