电子说
MVC中的每一个请求,都会分配给相应的控制器(Controller)和对应的行为方法(Action)去处理,那么如果我们想要在Action处理的前后加上一些额外的处理逻辑怎么办呢?这时候就用到了过滤器(Filters)。
在ASP.NET MVC的请求处理过程中有19个管道事件,这些事件分布在请求处理的各个节点中,比如BeginRequest(开始处理请求时触发)、AuthenticateRequest(对请求进行身份验证时触发)、AuthorizeRequest(对请求进程授权时触发)…等等等等。而过滤器的主要作用就是将我们的附加逻辑注入到这些请求处理管道中。
在实际业务中,在Action方法前后添加额外附加逻辑的情况有很多,过滤器就是用来完成此功能。通过过滤器可以将与业务逻辑无关但经常需要执行的代码分离开,使我们的代码逻辑性更加清晰,代码更加简洁。
MVC给我们提供了四种过滤器,基本满足了我们实际业务中常用的需求,包括以下:
类型名称 | 实现的接口 | 默认的实现类 | 作用 |
---|---|---|---|
授权过滤器 | IAuthorizationFilter | AuthorizeAttribute | 用于限制进入控制器或控制器的某个行为方法 |
动作过滤器 | IActionFilter | ActionFilterAttribute | 用于进入动作方法之前或之后的处理 |
结果过滤器 | IResultFilter | ActionFilterAttribute | 用于动作方法返回结果之前或之后的处理 |
异常处理过滤器 | IExceptionFilter | HandleErrorAttribute | 用于处理某个动作方法或某个控制器里面抛出的异常 |
这四种类型的接口是MVC对过滤器的一个接口规范,同时MVC默认通过AuthorizeAttribute(授权)、HandleErrorAttribute(异常处理)、ActionFilterAttribute(动作和结果)三个类实现了这四个接口。
需要注意的是ActionFilterAttribute类既实现了IActionFilter接口,也实现了IResultFilter接口。这是个抽象类,要求必须提供一个实现,AuthorizeAttribute和HandleErrorAttribute类则包含了一些有用的特性,可以不必创建派生类进行使用。所以我们一般都会通过继承ActionFilterAttribute类,实现自定义的过滤器。
除以上接口之外,我们还要用到FilterAttribute类,这个类将我们的过滤器包装成了特性,使我们的过滤器可以方便的在Action方法上方使用。
过滤器有以下几个特点:
下面我们逐一介绍下基本过滤器的使用方法。
所有实现了IAuthorizationFilter接口的都可以称之为授权过滤器。它的接口定义如下:
namespace System.Web.Mvc
{
//
// 摘要:
// 定义授权筛选器所需的方法。
public interface IAuthorizationFilter
{
//
// 摘要:
// 在需要授权时调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
void OnAuthorization(AuthorizationContext filterContext);
}
}
授权过滤器是最先运行的过滤器,它运行在其它过滤器和Action方法之前。客户端请求在调用Action之前,MVC框架会检测Action上是否有授权过滤器,如果有会调用OnAuthorization方法,如果此方法批准了请求,才会调用相应的Action。流程如图:
MVC默认使用AuthorizeAttribute实现了IAuthorizationFilter接口,所以我们可以在Action方法上直接添加Authorize特性标签来验证授权:
打开Index页面,会显示无权限:
由于使用的是MVC自带的授权验证方法,未能符合它的验证机制,所以无权限查看。通常我们需要添加一个新的派生自AuthorizeAttribute类的授权过滤器来完成我们自己业务逻辑。
下面我们自定义一个授权过滤器。我们在MVC项目中添加一个Filters文件夹,我们所有自定义的过滤器都放可以到这个文件夹下,便于管理。
在Filters下创建一个类,类名为MyAuthorizeAttribute。需要注意,过滤器要以Attribute结尾,这是MVC的约定。代码如下:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
//重写授权检查方法,返回值为true,允许访问,false,禁止访问。
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//请求参数user为空,禁止访问
if (string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["user"]))
{
return false;
}
return true;
}
}
可以看到,我们只要重写AuthorizeCore方法就可以根据我们的业务需求判断是否有权限访问,返回值为true允许访问,返回值为false禁止访问。
回到HomeController,我们给About方法加上我们自定义的特性:
我们看看效果:
可以看到,当About页面没有user参数时,会提示无权限,有user参数则可以访问通过。
在实际业务中我们可以使用授权过滤器来管理用户登录状态的授权验证。当然,我的这个例子只是基础的用法,实际业务比这复杂的多,那么就需要我们自己去思考设计授权过滤器方法了。
动作过滤器需要实现IActionFilter接口,接口定义如下:
//
// 摘要:
// 定义操作筛选器中使用的方法。
public interface IActionFilter
{
//
// 摘要:
// 在执行操作方法后调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
void OnActionExecuted(ActionExecutedContext filterContext);
//
// 摘要:
// 在执行操作方法之前调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
void OnActionExecuting(ActionExecutingContext filterContext);
}
我们看到该接口里有两个方法OnActionExecuting和OnActionExecuted,前者在动作方法执行前调用,后者在动作方法执行后调用。
OnActionExecuting方法是在Action方法执行前调用的,那么我们可以利用这个方法来检测请求,并且可以在这里修改请求,取消请求等等操作。
客户端的请求信息是一个ActionExecutingContext对象,它继承自ControllerContext类,属性如下:
名称 | 类型 | 说明 |
---|---|---|
ActionDescriptor | ActionDescriptor | 获取或设置操作描述符。 |
ActionParameters | IDictionary | 获取或设置操作方法参数。 |
Result | ActionResult | 获取或设置由操作方法返回的结果。 |
我们添加一个自定义的Action过滤器。由于ActionFilterAttribute类实现了IActionFilter接口,所以我们直接继承ActionFilterAttribute类即可,并且重写OnActionExecuting和OnActionExecuted方法。如下:
public class MyActionAttribute : ActionFilterAttribute
{
///
/// Action调用之前运行
///
///
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (string.Equals(filterContext.HttpContext.Request.HttpMethod, "get", StringComparison.CurrentCultureIgnoreCase))
{
filterContext.Result = new HttpNotFoundResult("只允许POST请求!");
}
}
///
/// Action调用之后运行
///
///
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
我们给Index方法添加上MyAction特性标签:
打开Index页,显示如下:
可以看到,页面返回了404错误,提示信息为我们设置的Message。
全部0条评论
快来发表一下你的评论吧 !