您的位置:首页 > 编程语言 > ASP

ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)

2017-11-17 11:47 411 查看
  上一篇文章介绍了使用Authorize特性实现了ASP.NET MVC中针对Controller或者Action的授权功能,实际上这个特性是MVC功能的一部分,被称为过滤器(Filter),它是一种面向切面编程(AOP)的实现,本章将从以下几个方面来介绍ASP.NET MVC中的过滤器。

  ● ASP.NET MVC 中的过滤器及其类型
  ● ASP.NET MVC 中常用的过滤器
  ● ASP.NET MVC 过滤器的应用方法
  ● ASP.NET MVC Action方法的调用与Filter的执行
  ● ASP.NET MVC 过滤器的创建与获取
  ● ASP.NET MVC Action及Result过滤器的管道执行

ASP.NET MVC中的过滤器及其类型

  在之前的Entity Framework文章中介绍了EF自带的拦截器(interceptors)功能,ASP.NET MVC中的过滤器也和拦截器一样是一种面向切面(AOP)的编程方式,是一种不修改源代码的前提下对应用程序进行拓展的编程方式。一般AOP用来处理日志记录、性能统计、安全控制、事务处理、异常处理等不会对原有业务数据进行修改的功能。
  ASP.NET MVC中把过滤器分为以下几类,每一类都是通过一个对应的接口定义的:
  ● 身份验证过滤器(IAuthenticationFilter):这个过滤器是在MVC5中加入的,它是所有过滤器中优先级最高的,使用身份验证过滤器可以为Action、Controller或者所有的Controller添加身份验证逻辑。身份验证过滤器的核心在于根据请求信息创建一个Principal对象(注:使用Identity的身份验证功能实际上也是创建一个Principal对象),以下是IAuthenticationFilter的定义:

  

/// <summary>Invokes the specified action by using the specified controller context.</summary>
/// <returns>The result of executing the action.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="actionName">The name of the action to invoke.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="controllerContext" /> parameter is null.</exception>
/// <exception cref="T:System.ArgumentException">The <paramref name="actionName" /> parameter is null or empty.</exception>
/// <exception cref="T:System.Threading.ThreadAbortException">The thread was aborted during invocation of the action.</exception>
/// <exception cref="T:System.Exception">An unspecified error occurred during invocation of the action.</exception>
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(actionName) && !controllerContext.RouteData.HasDirectRouteMatch())
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);//根据Controller信息及Action名称获取Action的描述信息
if (actionDescriptor != null)
{
FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);//获取所有过滤器
try
{
AuthenticationContext authenticationContext = this.InvokeAuthenticationFilters(controllerContext, filters.AuthenticationFilters, actionDescriptor);//调用身份验证过滤器
if (authenticationContext.Result != null)
{
AuthenticationChallengeContext authenticationChallengeContext = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authenticationContext.Result);
this.InvokeActionResult(controllerContext, authenticationChallengeContext.Result ?? authenticationContext.Result);
}
else
{
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);//调用授权过滤器
if (authorizationContext.Result != null)
{
AuthenticationChallengeContext authenticationChallengeContext2 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, authorizationContext.Result);
this.InvokeActionResult(controllerContext, authenticationChallengeContext2.Result ?? authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)//判断是否需要验证请求,使用ValidateInput特性并设置EnableValidation为False时跳过验证
{
ControllerActionInvoker.ValidateRequest(controllerContext);
}
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);//执行Action过滤器和Action方法
AuthenticationChallengeContext authenticationChallengeContext3 = this.InvokeAuthenticationFiltersChallenge(controllerContext, filters.AuthenticationFilters, actionDescriptor, actionExecutedContext.Result);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, authenticationChallengeContext3.Result ?? actionExecutedContext.Result);//执行Result过滤器及Result
}
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception exception)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);//当捕获异常时执行异常过滤器
if (!exceptionContext.ExceptionHandled)//如果异常过滤器并没有对异常进行处理则继续抛出异常
{
throw;
}
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}
return false;
}


View Code
  通过对上面代码的分析得出以下几个结论:
  1. 通过Controller上下文及Action的信息找到真实的Action方法后,获取所有过滤器。
  2. 先执行身份验证过滤器。
  3. 通过身份验证过滤器后执行授权过滤器。
  4. 授权过滤器通过后,执行Action过滤器及Action方法。
  5. 执行Result过滤器及Result。

ASP.NET MVC 过滤器的创建与获取

  根据上面的介绍知道了可以通过全局过滤器、特性标记以及重载Controller过滤器方法这三种方式来应用过滤器的,那么在执行过程中是如何通过ActionInvoker的GetFilters方法创建和获取它们的呢?
  ● 过滤器提供器(FilterProvider):ASP.NET MVC中有一个过滤器提供器的概念和实际对象,它有三种实现分别对应上述的三种应用方式:
    ○ GlobalFilterCollection:用于保存全局过滤器实例,可以直接通过它添加和获取过滤器实例,通过它创建的过滤器的Scope为Gobal,创建时可以通过Order参数来决定全局过滤器的执行顺序:

  


    ○ FilterAttributeFilterProvider:过滤器特性提供器,通过查找Controller以及Action上的特性来创建过滤器,根据特性标记位置将Scope分为Controller以及Action,在应用特性时可以设置特性的Order属性来决定过滤器的执行顺序:

    


    ○ ControllerInstanceFilterProvider:控制器实例过滤器提供器,它用于获取当前Controller实例的过滤器,并且过滤器的Scope为First:

    


  ● 过滤器提供器集合(FilterProviderCollection):它包含了上述的所有过滤器提供器,ActionInvoker就是通过它来获取所有相关过滤器的:

  


  FitlerProviderCollection获取过滤器时通过以上三种提供器获取所有相关的过滤器并根据Scope以及Order对过滤器进行排序,以决定过滤器执行顺序。

ASP.NET MVC Action及Result过滤器的管道执行

  在Action和Result过滤器的定义中都有两个方法,分别是OnXXXExecuting以及OnXXXExecuted,它们对应Action或者Reuslt执行前和执行后。当一个Action上存在多个Action或者Result过滤器时就会形成一个过滤器管道,其执行方式如下图所示:

  


小结

  本文除了介绍ASP.NET MVC的过滤器功能及常用的过滤器外,还通过代码的形式分析了它创建与执行的过程。在一般的项目中使用ASP.NET MVC自带的过滤器就可以满足需求,如授权、错误处理等,但过滤器作为ASP.NET MVC中的一种重要的AOP拓展方式,合理的运用过滤器可以实现,如日志记录、性能分析、Action的事务执行(http://blog.gauffin.org/2012/06/how-to-handle-transactions-in-asp-net-mvc3/,这篇文章就利用Action过滤器实现了数据库的事务)等等功能,并且可以灵活的在不影响原有代码逻辑的情况下对系统进行拓展。

参考:
  https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/controllers-and-routing/understanding-action-filters-cs
  http://blog.gauffin.org/2012/06/how-to-handle-transactions-in-asp-net-mvc3/

本文链接:http://www.cnblogs.com/selimsong/p/7839459.html

ASP.NET没有魔法——目录
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: