过滤器(1)

一直在想,怎么写这个源码分析,那些大神们是如何一步步分析写的文章。最开始不可能就了解其本质实现的,我们对任何事物总是有个认知过程的的。那门我就从这个认知过程一步步的解析一下过滤器使用和其本质实现吧。当然前提还是对Mvc有一些了解。(这里我装了ReSharp插件和Reflector一起使用的,所以有些源码格式可能不太一样)

1.初识过滤器,

往往认识事物的开始就是现象,认识了解一个方法或者一个类,也一般都是从其实例开始的。

需求:做电商的网站,那么要有用户的注册,登陆等。访问某个页面也不也说谁都能够访问的,别如我们的个人信息,购买信息等等。那肯定就需要对用户进行验证过滤。那就就有了这个需求,我们的Action需要用户过滤。简而言之,我们要在Action执行之前,进行过滤(执行自定义的代码)。

那么,第一个demo就来了。(可能是从书本上看来的,可能是网上查找的,可能是老师教的。不管怎么样,你肯定已经见过了几个类似的demo了)。

    /// <summary>

    /// 自定义用户登录特性

    /// </summary>

    public class UserLoginInfoAttribute : ActionFilterAttribute

    {

        /// <summary>

        /// 在Action执行之前

        /// </summary>

        /// <param name="filterContext"></param>

        public override void OnActionExecuting(ActionExecutingContext filterContext)

        {

            //这里是判断逻辑

        }

    }   

而且你肯定应该知道了,这个方法就是在Action执行之前执行的(即便你没有根据名称才出来,也应该msdn查出来吧),ok。这确实能够完成我们的需求,那么有这么个override的方法,根据经验,看样子应该还有Action执行之后的方法才对,根据智能提示看一下吧,哎呦我去,果然有,还有意外收获。OnActionExecuting,OnActionExecuted,OnResultExecuting,OnResultExecuted,嗯这个不能仅可以捕获Action执行前,Action执行后,还可以在Result返回前,返回后高一些东东,嗯,提供的挺全嘛。

有点经验的同学是不是就大概能猜到Action执行干了点什么了。可能就是类似的这么段代码吧。

       /// <summary>

        /// Action的执行

        /// </summary>

        public void ExcuteAction()

        {

            //1.OnActionExecuting

            //2.执行Action

            //3.OnActionExecuted

            //4.OnResultExecuting

            //5.生成结果

            //6.OnResultExecuted

        }   

我去,这都猜到了,那要不要证实下呢,嗯,还是证实下的好,要不总感觉欠人1毛钱似的,赶脚怪怪的。好吧,一起看一看吧

Action的执行,从哪里看呢,(如果同学看过些Mvc的相关知识应该就知道从哪里入手,不知道暂时也没什么),那就从Controller看看吧,别问我为什么,我也不知道,多年当猴(程序猿)进化的结果吧。(想想大概也能猜的到,Action是在Controller中的,那Action的执行最相关的估么就应该在Controller中有这么个执行的东西),转到定义看下吧。

       public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer

{

    // Fields

    private IActionInvoker _actionInvoker;

    //此处略去N行代码。。。()

}

  

我去这么一大堆,尼玛完全亮瞎了我的钛合金狗眼了,估计也没有心情完全看下去,但是瞅两眼有没有让你眼前一亮的东西呢。IActionInvoker。微软起名还是很地道的。(如果你没看见或者一点都没看,我只能说呵呵),究其实现,其实是这么个方法CreateActionInvoker。尼玛看了看实现,又往下翻了翻定义什么的,没什么头绪,算了,看这样子,换个地方吧。在这之中你肯定应该看过了这么个东西

  /// <summary>

  /// 定义操作调用程序的协定,该调用程序用于调用一个操作以响应 HTTP 请求。

  /// </summary>

  public interface IActionInvoker

  {

    /// <summary>

    /// 使用指定的控制器上下文来调用指定操作。

    /// </summary>

    ///

    /// <returns>

    /// 如果找到了指定操作,则为 true;否则为 false。

    /// </returns>

    /// <param name="controllerContext">控制器上下文。</param><param name="actionName">操作的名称。</param>

    bool InvokeAction(ControllerContext controllerContext, string actionName);

  }

  

这就是控制Action执行的接口。看看Controller的定义。ControllerBase玩意是不是应该引起我们的关注呢。嗯,应该是Controller的基类吧。看看定义吧

public abstract class ControllerBase : IController

{

    // Fields

    private DynamicViewDataDictionary _dynamicViewDataDictionary;

    private readonly SingleEntryGate _executeWasCalledGate;

    private TempDataDictionary _tempDataDictionary;

    private bool _validateRequest;

    private IValueProvider _valueProvider;

    private ViewDataDictionary _viewDataDictionary;

    // Methods

    protected ControllerBase();

    protected virtual void Execute(RequestContext requestContext);

    protected abstract void ExecuteCore();

    protected virtual void Initialize(RequestContext requestContext);

    void IController.Execute(RequestContext requestContext);

    internal void VerifyExecuteCalledOnce();

    // Properties

    public ControllerContext ControllerContext { get; set; }

    public TempDataDictionary TempData { get; set; }

    public bool ValidateRequest { get; set; }

    public IValueProvider ValueProvider { get; set; }

    [Dynamic]

    public object ViewBag { [return: Dynamic] get; }

    public ViewDataDictionary ViewData { get; set; }

}

还可以,比Controller简单很多,但是看一眼没什么收获。继续往下走

/// <summary>

  /// 定义控制器所需的方法。

  /// </summary>

  public interface IController

  {

    /// <summary>

    /// 执行指定的请求上下文。

    /// </summary>

    /// <param name="requestContext">请求上下文。</param>

    void Execute(RequestContext requestContext);

  }

哎,有点戏,Execute,执行请求上下文,应该会有Action的东西,毕竟我们的Action才是真正每次处理请求的真正内容么。

回到Controller看,我们会看到这么个方法

protected override void ExecuteCore()

        {

            // If code in this method needs to be updated, please also check the BeginExecuteCore() and

            // EndExecuteCore() methods of AsyncController to see if that code also must be updated.

            PossiblyLoadTempData();

            try

            {

                string actionName = RouteData.GetRequiredString("action");

                if (!ActionInvoker.InvokeAction(ControllerContext, actionName))

                {

                    HandleUnknownAction(actionName);

                }

            }

            finally

            {

                PossiblySaveTempData();

            }

        }  

我去,终于有点收获。ActionInvoker.InvokeAction(ControllerContext, actionName)这个是不是就是Action的执行呢。仔细一看,我去依赖接口调用的方法。我去,喷血了。(这个是我的软肋,这种依赖接口的调用,我就不会找其具体实现了该接口的代码的位置了,跪求大神指导。)。(当然如果你运气比较好直接用的reflector看的话,应该会有所发现,因为Controller和ControllerActionInvoker(这是我后面才知道的)的定义是挨着的。)这个是我之前,学习大神Artech的文章看到的。这里曲折的寻找之路大家就只能各自发挥了,我这里就直接给出ControllerActionInvoker的InvokeAction执行的。看下代码片段

    public class ControllerActionInvoker : IActionInvoker

    {

        public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)

        {

            if (controllerContext == null)

            {

                throw new ArgumentNullException("controllerContext");

            }

            if (String.IsNullOrEmpty(actionName))

            {

                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");

            }

            ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);

            ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);

            if (actionDescriptor != null)

            {

                FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);

                try

                {

                    AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);

                    if (authContext.Result != null)

                    {

                        // the auth filter signaled that we should let it short-circuit the request

                        InvokeActionResult(controllerContext, authContext.Result);

                    }

                    else

                    {

                        if (controllerContext.Controller.ValidateRequest)

                        {

                            ValidateRequest(controllerContext);

                        }

                        IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);

                        ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);

                        InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);

                    }

                }

                catch (ThreadAbortException)

                {

                    // This type of exception occurs as a result of Response.Redirect(), but we special-case so that

                    // the filters don‘t see this as an error.

                    throw;

                }

                catch (Exception ex)

                {

                    // something blew up, so execute the exception filters

                    ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);

                    if (!exceptionContext.ExceptionHandled)

                    {

                        throw;

                    }

                    InvokeActionResult(controllerContext, exceptionContext.Result);

                }

                return true;

            }

            // notify controller that no method matched

            return false;

        }

    }  

  

恩恩,大概看看,应该能够找到这么两个方法InvokeActionMethodWithFilters,InvokeActionResultWithFilters,这尼玛也太容易了,这方法名不就写的很清楚了么。(让我们体验了一把见名知意的重要性)。继续看一看,最后看到这么两个方法InvokeActionMethodFilter,InvokeActionResultFilter

internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)

        {

            filter.OnActionExecuting(preContext);

            if (preContext.Result != null)

            {

                return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true /* canceled */, null /* exception */)

                {

                    Result = preContext.Result

                };

            }

            bool wasError = false;

            ActionExecutedContext postContext = null;

            try

            {

                postContext = continuation();

            }

            catch (ThreadAbortException)

            {

                // This type of exception occurs as a result of Response.Redirect(), but we special-case so that

                // the filters don‘t see this as an error.

                postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, null /* exception */);

                filter.OnActionExecuted(postContext);

                throw;

            }

            catch (Exception ex)

            {

                wasError = true;

                postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, ex);

                filter.OnActionExecuted(postContext);

                if (!postContext.ExceptionHandled)

                {

                    throw;

                }

            }

            if (!wasError)

            {

                filter.OnActionExecuted(postContext);

            }

            return postContext;

        }

internal static ResultExecutedContext InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func<ResultExecutedContext> continuation)

        {

            filter.OnResultExecuting(preContext);

            if (preContext.Cancel)

            {

                return new ResultExecutedContext(preContext, preContext.Result, true /* canceled */, null /* exception */);

            }

            bool wasError = false;

            ResultExecutedContext postContext = null;

            try

            {

                postContext = continuation();

            }

            catch (ThreadAbortException)

            {

                // This type of exception occurs as a result of Response.Redirect(), but we special-case so that

                // the filters don‘t see this as an error.

                postContext = new ResultExecutedContext(preContext, preContext.Result, false /* canceled */, null /* exception */);

                filter.OnResultExecuted(postContext);

                throw;

            }

            catch (Exception ex)

            {

                wasError = true;

                postContext = new ResultExecutedContext(preContext, preContext.Result, false /* canceled */, ex);

                filter.OnResultExecuted(postContext);

                if (!postContext.ExceptionHandled)

                {

                    throw;

                }

            }

            if (!wasError)

            {

                filter.OnResultExecuted(postContext);

            }

            return postContext;

        }

  

嗯,看方法第一行和最有一行,好了大概跟我们猜的差不多,只不过实现要比我们的想想复杂的多。我们猜测的一行注释基本上就省去了千百行的代码。从看的过程中,也能学到很多别的东西,微软的一些设计思路和方式。以后再看的话,是不是会容易一些呢。

过滤器的实现,是不是就是种面向切面的AOP思想呢,之前我也写过类似的东东,但是能不能提升到微软这个层次呢,至少从几十几百行代码一下子变成小几千行,是不是有种很牛逼的赶脚,呵呵,开个玩笑,代码还是要精简些的。AOP,不是很熟悉,要不要找篇文章再深入研究下呢,先把这个研究完再说吧。

面向抽象,依赖接口的编程,有木有。(如果不是的话,我就可以直接转到定义了,不需要花费精力找Action的执行了)

单例模式有木有。别说你没看到。(看这个名称貌似也是个内部Descriptor缓存类的东东)

确实学到不少东西。我去,我们要干嘛来着,研究过滤器的本质和实现。我去基本木有进展。

 public class ControllerActionInvoker : IActionInvoker

    {

       private static readonly ControllerDescriptorCache _staticDescriptorCache = new ControllerDescriptorCache();

    }

  

算了,尼玛一个问题折腾了半天,不过还好有些收获。休息休息,等待继续研究吧。周末得回家,估计不能发blog了,不过研究还是得继续,否则没法完整的贯通下来了。

  注:1.文章中提到了(这种依赖接口的调用,我就不会找其具体实现了该接口的代码的位置了,跪求大神指导。)

    2.由于个人水平问题,难免会有一些错误,忘大神支出共同进步。

过滤器(1),布布扣,bubuko.com

时间: 2024-10-14 06:11:02

过滤器(1)的相关文章

webapi 如何添加过滤器,并在过滤器中获取客户端传过来的参数

给控制器下的行为添加过滤器 新建一个类ActionFilter 名字随便取,然后让他集成ActionFilterAttribute并实现虚方法,虚方法有好几种,我使用的是进入方法之前的,如需了解更多虚方法,点击这里 public class ActionFilter : ActionFilterAttribute { public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actio

java web 过滤器跟拦截器的区别和使用

1.首先要明确什么是拦截器.什么是过滤器 1.1 什么是拦截器: 拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. 在Webwork的中文文档的解释为--拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行.同时也是提供了一种可以提取action中可重用的部分的方式.

AngularJs自定义过滤器filter

AngularJs自带有很多过滤器,现在Insus.NET演示一个自定义的过滤器,如实现一个数据的平方. 本演示是在ASP.NET MVC环境中进行. 创建一个app: 创建一个控制器: 接下来是重点,创建一个过滤器,例子中的过滤器是实现一个数值的平方. 以上的所指的App,控制器和过滤器均是依Angularjs而言. 下面是ASP.NET MVC的视图,实现数据过滤: 程序运行结果:

hbase过滤器(1)

最近在公司做hbase就打算复习下它的过滤器以便不时之需,RowFilter根据行键(rowkey)筛选数据 public void filter() throws IOException { Filter rf = new RowFilter(CompareFilter.CompareOp.LESS, new BinaryComparator(Bytes.toBytes("35643b94-b396-4cdc-abd9-029ca495769d"))); Scan s = new S

Java Web开发——Filter过滤器

一.过滤器 1.1定义 过滤器是一个服务器端的组件,它可以截取用户端的请求与响应信息,并对这些信息进行过滤. 1.2工作原理 1.项目启动时,从Web容器中加载过滤器: 2.过滤器存在于用户请求和Web资源之间: 3.用户请求和Web响应之间的收发都经由过滤器按照过滤规则进行过滤筛选. 1.3过滤器的生命周期 实例化(web.xml加载)→初始化(init方法)→过滤(doFilter方法)→销毁(destroy方法) 1.初始化:当容器第一次加载该过滤器时,init() 方法将被调用.该类在这

【JavaWeb学习】过滤器Filter

一.简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息等一些高级功能. Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter.通过Filter技

Java web--Filter过滤器分IP统计访问次数

分IP统计访问次数即网站统计每个IP地址访问本网站的次数. 分析 因为一个网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,所以使用过滤器最为方便. 因为需要分IP统计,所以可以在过滤器中创建一个Map,使用IP为key,访问次数为value.当有用户访问时,获取请求的IP,如果IP在Map中存在,说明以前访问过,那么在访问次数上加1,即可:IP在Map中不存在,那么设置次数为1. 那么问题来了! 问题一:为什么使用Map存放? Map是一个由键值对组成的数据结构,其中所有的key组成一

MVC过滤器详解

APS.NET MVC中(以下简称“MVC”)的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理.这时候就用到了过滤器. MVC支持的过滤器类型有四种,分别是:Authorization(授权),Action(行为),Result(结果)和Exception(异常).如下表, 过滤器类型 接口 描述 Authorization IAuthorizationFilter 此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法 Exce

Filter简单过滤器的实现

1.过滤器简单编写 package cn.buaa.core.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import ja

ng中的过滤器

angular中对输出的值提供过滤器,用法如下: {{name | currency:"¥"}}</p> 这是在在html中的用法,用 | 来添加过滤器,过滤器后面通过 : 来添加相应的一些参数,angular内置的过滤器有 currency  number  lowercase/uppercase  json  limitTo  date  orderBy  filter 在js中的用法: m1.controller('Aaa',['$scope','$filter',f