过滤器本质就是对动作方法的执行过程进行干预,这种干预可以影响动作方法执行的各个过程。ASP.NET MVC 提供了4种类型的接口,并在接口中定义了各种成员,代表代码执行的各个阶段,这些接口和成员如表11-1所示。

表11-1 常见过滤器接口

过滤器类型

接口

默认实现

描述

Action

IActionFilter

ActionFilterAttribute

在动作方法之前及之后运行

Result

IResultFilter

ActionFilterAttribute

在动作结果被执行之前和之后运行

AuthorizationFilter

IAuthorizationFilter

AuthorizeAttribute

首先运行,在任何其它过滤器或动作方法之前

Execption

IExceptionFilter

HandleErrorAttribute

只在另一个过滤器、动作方法、动作结果弹出异常时运行

当动作方法同时应用了继承自这些特性的过滤器后,实际的执行过程如图11-1所示。

图11-1 过滤器执行过程

图11-1中流程并没有列出 OnException() 方法的执行时机,事实上,在执行流程中只要任何环节出现异常,就会执行 OnException()方法。

11.1 过滤器的使用

ASP.NET MVC 的这种过滤器机制,实际是体现了一种 AOP(面向切面) 设计思想,当需要为动作方法进行干预时,不需要变动动作方法内部的代码,就可以扩张横向的行为。在实际开发中,只需要继承这些接口,实现自定义的特性,并在动作方法上应用自定义的特性,就可以扩展动作方法的能力。实现自定义的过滤器特性,需要满足两个要求。一是实现表11-1中任意的接口,二是继承FilterAttribute,标识它是一个过滤器。接下来介绍自定义过滤器的用法。

11.1.1 Action 过滤器

在ASP.NET MVC 项目中创建文件夹Filter,然后新建类MyActionFilterAttribute(为了遵循默认的约定,名称以Attribute结尾),继承自ActionFilterAttribute类。ActionFilterAttribute类有如下4个方法。

public virtual void OnActionExecuted(ActionExecutedContext filterContext);

public virtual void OnActionExecuting(ActionExecutingContext filterContext);

public virtual void OnResultExecuted(ResultExecutedContext filterContext);

public virtual void OnResultExecuting(ResultExecutingContext filterContext);

MyActionFilterAttribute.cs 类的代码如示例1所示。

示例1

public class MyActionFilterAttribute : ActionFilterAttribute

{

//Action执行之前

public override void OnActionExecuting(ActionExecutingContext filterContext)

{

//1、获取请求的类名和方法名

string strController = filterContext.RouteData.Values["controller"].ToString();

string strAction = filterContext.RouteData.Values["action"].ToString();

//2、用另一种方式获取请求的类名和方法名

string strController2 = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;

string strAction2 = filterContext.ActionDescriptor.ActionName;

filterContext.HttpContext.Response.Write("控制器:" + strController + "<br/>");

filterContext.HttpContext.Response.Write("控制器:" + strController2 + "<br/>");

filterContext.HttpContext.Response.Write("Action:" + strAction + "<br/>");

filterContext.HttpContext.Response.Write("Action:" + strAction2 + "<br/>");

filterContext.HttpContext.Response.Write("Action执行前:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");

base.OnActionExecuting(filterContext);

}

//Action执行之后

public override void OnActionExecuted(ActionExecutedContext filterContext)

{

filterContext.HttpContext.Response.Write("Action执行后:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");

base.OnActionExecuted(filterContext);

}

}

对于过滤器,我们可以把它们加在3个地方,一个是控制器上面(控制器下面的所有Action),一个是Action上面(指定标识的Action),另一个就是全局位置(所有控制器中的Action)

在控制器上代码如下:

[MyActionFilter]

public ActionResult Index()

{

return View();

}

11.1.2 Result 过滤器

在Filter文件夹中新建MyResultFilterAttribute类,继承ActionFilterAttribute。如示例2所示。

示例2

public class MyResultAttribute: ActionFilterAttribute

{

// 加载"视图"前执行

public override void OnResultExecuting(ResultExecutingContext filterContext)

{

filterContext.HttpContext.Response.Write("加载视图前执行 OnResultExecuting" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");

base.OnResultExecuting(filterContext);

}

// 加载"视图"后执行

public override void OnResultExecuted(ResultExecutedContext filterContext)

{

filterContext.HttpContext.Response.Write("加载视图后执行 OnResultExecuted" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss fff") + "<br/>");

base.OnResultExecuted(filterContext);

}

}

这里把MyResultFilter过滤器加在控制器上面,相当于给Home控制器中的所有的Action方法添加了MyResultFilter过滤器。如下代码所示。

[MyResultFilter]

public class HomeController : Controller

{

[MyActionFilter]

public ActionResult Index()

{

return View();

}

}

11.1.3 AuthorizeAttribute过滤器

创建MyAuthorizeAttribute类,继承AuthorizeAttribute类。如示例3所示。

示例3

public class MyAuthorizeAttribute: AuthorizeAttribute

{

public override void OnAuthorization(AuthorizationContext filterContext)

{

filterContext.HttpContext.Response.Write("OnAuthorization<br/>");

//注释掉父类方法,

//因为父类里的OnAuthorization方法会调用ASP.NET的授权验证机制

//base.OnAuthorization(filterContext);

}

}

在控制器Home中的Index上添加MyAuthorize过滤器。

[MyActionFilter]

[MyAuthorize]

public ActionResult Index()

{

return View();

}

通常Authorize过滤器也是在全局过滤器上面的,主要用来做登录验证或者权限验证,在App_Start目录下的FilterConfig类的RegisterGlobalFilters方法中添加:

public class FilterConfig

{

public static void RegisterGlobalFilters(GlobalFilterCollection filters)

{

filters.Add(new HandleErrorAttribute());

//添加全局授权过滤器

filters.Add(new MyAuthorizeAttribute());

}

}

在全局中注册过滤器,则所有控制器的所有行为(Action)都会执行这个过滤器。

11.1.4 Exception过滤器

创建MyHandleErrorAttribute类,继承HandleErrorAttribute类。如示例4所示。

示例4

public class MyHandleErrorAttribute: HandleErrorAttribute

{

public override void OnException(ExceptionContext filterContext)

{

//1、获取异常对象

Exception ex = filterContext.Exception;

//2、记录异常日志 (将错误信息利用IO保存到文件)

//3、重定向友好页面

filterContext.Result = new RedirectResult("~/error.html");

//4、标记异常已经处理完毕

filterContext.ExceptionHandled = true;

base.OnException(filterContext);

}

}

在Action上面添加MyHandleError过滤器,如下所示。

[MyHandleError]

public ActionResult GetErr()

{

int a = 0;

int b = 1 / a;

return View();

}

运行会自动跳转到error.html页面。

如果页面没有跳转,就需要去Web.config配置文件中的<system.web>节点下面添加如下配置节点,开启自定义错误:

<customErrors mode="On"></customErrors>

通常这样的异常处理是放在全局过滤器上面的,只要任意Action方法报错就会执行MyHandleError过滤器中的代码。

修改App_Start目录下面的FilterConfig类:

public class FilterConfig

{

public static void RegisterGlobalFilters(GlobalFilterCollection filters)

{

//添加全局授权过滤器

filters.Add(new MyAuthorizeAttribute());

//添加全局异常处理过滤器

filters.Add(new MyHandleErrorAttribute());

}

}

Global.asax下的代码:

public class MvcApplication : System.Web.HttpApplication

{

protected void Application_Start()

{

App_Start.AutoMapperConfig.Config();

AreaRegistration.RegisterAllAreas();

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

RouteConfig.RegisterRoutes(RouteTable.Routes);

BundleConfig.RegisterBundles(BundleTable.Bundles);

}

}

11.2 基于Form的身份验证

身份验证流程

一、用户登录

  1、验证表单:ModelState.IsValid

  2、验证用户名和密码:通过查询数据库验证

  3、如果用户名和密码正确,则在客户端保存Cookie以保存用户登录状态:SetAuthCookie

    1):从数据库中查出用户名和一些必要的信息,并把额外信息保存到UserData中

    2):把用户名和UserData保存到 FormsAuthenticationTicket 票据中

    3):对票据进行加密 Encrypt

    4):将加密后的票据保存到Cookie发送到客户端

  4、跳转到登录前的页面

二、验证登录

  1、在Global中注册PostAuthenticateRequest事件函数,用于解析客户端发过来的Cookie数据

    1):通过 HttpContext.Current.User.Identity 判断用户是否登录(FormsIdentity,IsAuthenticated,AuthenticationType)

    2):从HttpContext 的Request的Cookie中解析出Value,解密得到 FormsAuthenticationTicket 得到UserData

  2、角色验证

    在Action加入 Authorize特性,可以进行角色验证

    在 HttpContext.Current.User 的 IsInRole 方法进行角色认证(需要重写)

APS.NET MVC + EF (11)---过滤器的更多相关文章

  1. APS.NET MVC + EF (14)---项目框架搭建

    一:框架搭建     1:先创建Model. 2:创建数据访问接口层.IUserInfoDal 在该接口中定义了常见的方法CURD以及分页方法. public interface IUserInfoD ...

  2. APS.NET MVC + EF (08)---数据注解和验证

    对于Web开发人员来说,用户输入验证一直是一个挑战.不仅在客户端浏览器中需要执行验证逻辑,在服务器端也需要执行.如果觉得验证是令人望而生畏的繁杂琐事,ASP.NET MVC框架提供了数据注解的方式帮助 ...

  3. APS.NET MVC + EF (02)---深入理解ADO.NET Entity Framework

    2.7 深入理解Entity Framework 性能问题几乎是一切ORM框架的通病,对于EF来说,引起性能低的原因主要在以下几个方面. 复杂的对象管理机制为了在.NET中更好地管理模型对象,EF提供 ...

  4. APS.NET MVC + EF (06)---模型

    在实际开发中,模型往往被划分为视图模型和业务模型两部分,视图模型靠近视图,业务模型靠近业务,但是在具体编码上,它们之间并不是隔离的. 6.1 视图模型和业务模型 模型大多数时候都是用来传递数据的.然而 ...

  5. APS.NET MVC + EF (10)---使用AJAX

    在Web系统中,Ajax技术已经成为提高用户体验的必备技术.开发Ajax程序,涉及两方面的内容:一是客户端技术,二是服务器端技术. (1)客户端技术 核心工作是通过JavaScript向服务器发送数据 ...

  6. APS.NET MVC + EF (07)---表单和HTML辅助方法

    在ASP.NET MVC中,可以借助HtmlHelper 对象来输出页面内容,提高开发效率.下面,我们将介绍一些常用的辅助方法. 7.1 HTML辅助方法 BeginForm 该辅助方法主要用来产生& ...

  7. APS.NET MVC + EF (05)---控制器

    Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务端的交互,并且负责协调Model与View之间数据传递,是ASP.NET MVC框架核心.Controller为ASP. ...

  8. APS.NET MVC + EF (04)---路由和数据传递

    4.1 视图引擎 ASP.NET MVC 提供两种视图引擎:ASPX(C#)和Razor(CSHTML),推荐使用Razor. 4.1.1 Razor的语法 在Razor视图中,所有的服务器端代码都是 ...

  9. APS.NET MVC + EF (03)---初始MVC

    3.1 MVC简介 MVC(Model-View-Controller,模型—视图—控制器模式)用于表示一种软件架构模式.它把软件系统分为三个基本部分:模型(Model),视图(View)和控制器(C ...

随机推荐

  1. CentOS用yum安装MySQL 8.0 .

    先说一句,fuck,搞了一下午. 步骤:一:安装yum源: 1.wget https://dev.mysql.com/get/mysql80-community-release-el6-3.noarc ...

  2. Redis 使用过程中遇到的具体问题

    1.缓存雪崩和缓存穿透问题 1.1缓存雪崩 简介:缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉. 解决办法:  事前:尽量保证整个 redis 集 ...

  3. Django框架(二十)-- Django rest_framework-权限组件

    一.权限组件的使用 # 用户信息表 class UserInfo(models.Model): name = models.CharField(max_length=32) # 写choice use ...

  4. 关于微信小程序中遇到的各种问题汇总(持续更新)

    1.关于 <input />标签容易忽略的问题: 使用<input />标签时容易忘记绑定bindblur()方法(输入框失去焦点时触发),因为用户用键盘输入时不一定会点击完成 ...

  5. Python之flask框架2

    Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务.本文参考自Flask官方文档,大部分代码引用自官方文档. 安装flask 首先我们来安装F ...

  6. Maven 中 dependencyManagement 元素,知识点

    Maven 提供的 dependencyManagement 元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性.在 dependencyManagement 元素下的依赖声明不会 ...

  7. Docker常用安装(九)

    一.安装mysql 1.  docker hub上面查找mysql镜像 2. 拉取镜像 #获取mysql镜像 docker pull mysql:5.6 3. 运行容器 docker run -p 1 ...

  8. yum 初始化国内

    修改为阿里源备份默认的yum源文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 下载阿里 ...

  9. [CODEVS4632][BZOJ4326]运输计划

    题目描述 Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P ...

  10. SQL中group by的注意事项

    最最最最重要的: group by有一个原则,就是select后面所有的列中,没有使用聚合函数的列,必须出现在group by子句中. group by子句中的注意事项: 1,不能使用别名(因为执行顺 ...