zoukankan      html  css  js  c++  java
  • Action Filtering in ASP.NET MVC Applications

    Base Interview

    MVC中一个重要的功能——Filter,我们通过研究源代码来了解Filter的原理,以及AOP 模式和各种Filter的执行。最重要的是大家通过理解Filter的代码,明白Filter的机制,从而对Filter有一个灵活的运用。

    比如你在Action上使用的每一个 [Attribute]大都是Filter,mvc提供四种类型的 Filter:IActionFilter,IAuthorizationFilter,IExceptionFilter,IResultFilter,这四种Filter足以我们所要实现的功能了,还提供了几个现成的可以使用的Filter:OutputCacheAttribute、 HandleErrorAttribute、AuthorizeAttribute。我们知道Filter是横切在Action上的,所以每次执行一个 Action,就会牵扯到这个Action的执行,不同类型的Filter提供不同类型的操作,Filter的设计就是一种AOP设计模式,所以这种方式十分灵活。

    AuthorizeAttribute 介绍如何使用 Authorize 特性控制对操作方法的访问。
    OutputCacheAttribute 介绍如何使用 OutputCache 特性缓存操作方法的输出结果。
    HandleErrorAttribute 解释如何向 MVC 应用程序添加自定义操作筛选器。

    对于四种类型的Filter,各自有不同的方法,并以此来实现不同的功能,我们可以发挥自己的创造力,定制一个自己的Filter,来完成自己想要的功能。一般的Filter应用的场景有:缓存、验证、异常,以及处理Action上下文等,要想实现自己的Filter 只要继承相应的接口并重写接口的方法就可以了。

    • 授权筛选器,用于做出关于是否执行操作方法(如执行身份验证或验证请求的属性)的安全决策。 AuthorizeAttribute 类是授权筛选器的一个示例。
    • 操作筛选器,用于包装操作方法的执行操作。此筛选器可以执行其他处理,如向操作方法提供额外数据、检查返回值或取消执行操作方法。
    • 结果筛选器,用于包装 ActionResult 对象的执行操作。此筛选器可以对结果执行其他处理,如修改 HTTP 响应。 OutputCacheAttribute 类是结果筛选器的一个示例。
    • 异常筛选器,如果在操作方法中某处引发了未经处理的异常,则从授权筛选器开始执行,执行结果筛选器后结束。异常筛选器可用于执行诸如日志记录或显示错误页之类的任务。 HandleErrorAttribute 类是异常筛选器的一个示例

    Why Use Filter


    我们知道Filter是一种AOP模式,也就是说它提供我们可以对一系列操作进行横切干扰的手段,而且它解耦了依赖关系。想想这么一种场景,在传统的WebForm中,某一个页面的访问必须去验证当前用户是否符合某一个要求,比如已登录,这时,我们需要获取请求的上下文,分析当前用户的行为状态,从而得到这个条件是否成立,如果我们有很多这种页面,比如所有的后台管理页面需要管理员的登录,我们是不是每一页都写一个这样的验证呢?我们当然不会这么蠢,我们会聪明的把验证的逻辑封装成一个验证类,然后从各个页面调用验证类的验证逻辑,从而得知当前用户是否通过验证。
    这样还是不够好,因为我们不得不在每一处反复写我们的调用验证类的验证代码,显然这些工作是重复的,因为那个时候还没有AOP的概念,所以我们不得不多付出点代价。
    现在有了mvc,它理所应当为我们提供一个AOP的框架,而Filter就是这么一种模式,它的出现容许我们以一种更为简单的方式来实现类似的功能,在使用的时候我们只需要像该某个商品贴标签式的方式给Action“贴”上一个Attribute就行了,一切搞定,没有一点多于的代码。

    Use default Filter

    操作筛选器的某些可能用途包括:

    • 日志记录,目的是跟踪用户交互。
    • “反图像攫取”,用于防止在自己网站之外的网页中加载图像。
    • 爬网程序筛选,用于根据浏览器用户代理来更改应用程序行为。
    • 本地化,用于设定区域设置。
    • 动态操作,用于将操作注入到控制器中。

    操作筛选器是以从 ActionFilterAttribute 中继承的特性类的形式实现的。 ActionFilterAttribute 是一个具有以下四个可以重写的虚拟方法的抽象类:OnActionExecuting、OnActionExecuted、OnResultExecuting 和 OnResultExecuted。若要实现操作筛选器,您至少必须重写这些方法之一。

    ASP.NET MVC 框架将先调用操作筛选器的 OnActionExecuting 方法,然后再调用以操作筛选器特性标记的任意操作方法。同样,该框架将在操作方法完成后调用 OnActionExecuted 方法。

    调用 OnResultExecuting 方法后,要立即调用您的操作返回的 ActionResult 实例。执行结果后,紧接着就要调用 OnResultExecuted 方法。这些方法对于执行日志记录、缓存输出结果之类的操作非常有用。

    下面演示自带的Filter 如OutputCacheAttribute

    配置缓存文件如下

    <system.web>
      <caching>
        <outputCacheSettings>
          <outputCacheProfiles>
            <add name="MyProfile" duration="60" varyByParam="*" />
          </outputCacheProfiles>
        </outputCacheSettings>
      </caching>
    </system.web>

    标记制作器中的Action

    [OutputCache(CacheProfile = "MyProfile", Duration = 10)]
    public ActionResult About()
    {
        ViewData["Message"] = "This page was cached at " + DateTime.Now;
    
        return View();
    }

    Creating a custom action filter

    下面的示例演示一个简单的操作筛选器,该操作筛选器记录调用操作方法之前和之后的跟踪消息

    注意: 按照约定,操作筛选器特性的名称应以“Attribute”作为结尾,LogFilterAttribute 或 OutputFilterAttribute。如创建一个日志异常的Filter

    public class LoggingFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            filterContext.HttpContext.Trace.Write("(Logging Filter)Action Executing: " +
                filterContext.ActionDescriptor.ActionName);
    
            base.OnActionExecuting(filterContext);
        }
    
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (filterContext.Exception != null)
                filterContext.HttpContext.Trace.Write("(Logging Filter)Exception thrown");
    
            base.OnActionExecuted(filterContext);
        }
    }

    使用也很简单 ,用操作筛选器特性标记的操作方法的控制器

            [LoggingFilter]
            public ActionResult Index()
            {
                ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序。";
    
                return View();
            }
            [LoggingFilter]
            public ActionResult About()
            {
                ViewBag.Message = "你的应用程序说明页。";
    
                return View();
            }

    或者在控制器中重写

    image

            protected override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                filterContext.HttpContext.Trace.Write("(Controller)Action Executing: " +
                    filterContext.ActionDescriptor.ActionName);
    
                base.OnActionExecuting(filterContext);
            }
            [NonAction]
            protected override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                if (filterContext.Exception != null)
                    filterContext.HttpContext.Trace.Write("(Controller)Exception thrown");
    
                base.OnActionExecuted(filterContext);
            }
            [LoggingFilter]
            public ActionResult Index()
            {
                ViewBag.Message = "修改此模板以快速启动你的 ASP.NET MVC 应用程序。";
    
                return View();
            }
            [LoggingFilter]
            public ActionResult About()
            {
                ViewBag.Message = "你的应用程序说明页。";
    
                return View();
            }

    或者注册全局的Filter,在App_Start 中的 FilterConfig.cs文件中(MVC4)注册我们的LoggingFilterAttribute

          public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new LoggingFilterAttribute());
                filters.Add(new HandleErrorAttribute());
            }

    我们也可以看下HandleErrorAttribute类 F12

    // 摘要:
        //     表示一个特性,该特性用于处理由操作方法引发的异常。
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
        public class HandleErrorAttribute : FilterAttribute, IExceptionFilter
        {
            // 摘要:
            //     初始化 System.Web.Mvc.HandleErrorAttribute 类的新实例。
            public HandleErrorAttribute();
    
            // 摘要:
            //     获取或设置异常的类型。
            //
            // 返回结果:
            //     异常的类型。
            public Type ExceptionType { get; set; }
            //
            // 摘要:
            //     获取或设置用于显示异常信息的母版视图。
            //
            // 返回结果:
            //     母版视图。
            public string Master { get; set; }
            //
            // 摘要:
            //     获取此特性的唯一标识符。
            //
            // 返回结果:
            //     此特性的唯一标识符。
            public override object TypeId { get; }
            //
            // 摘要:
            //     获取或设置用于显示异常信息的页视图。
            //
            // 返回结果:
            //     页视图。
            public string View { get; set; }
    
            // 摘要:
            //     在发生异常时调用。
            //
            // 参数:
            //   filterContext:
            //     操作-筛选器上下文。
            //
            // 异常:
            //   System.ArgumentNullException:
            //     filterContext 参数为 null。
            public virtual void OnException(ExceptionContext filterContext);
        }

    如我看可以看到 Master的额外参数,我们可以在控制器中如下标记

           [HandleErrorAttribute(Master="我是参数 但不是模板页")]
            public ActionResult Contact()
            {
                ViewBag.Message = "你的联系方式页。";
    
                return View();
            }

    我们也可以添加我们想要的值,如添加一个属性在 (public string Message { get; set; } )在LoggingFilterAttribute 类

    我们也可以把该filter特性标记上面的方法中,如:

    [LoggingFilterAttribute (Message = "action")]
    
    public class IndexController : Controller
    
    {…}

    全局中我们可以通过下面方式获取控制器与action的名称

    filterContext.RouteData.GetRequiredString("Controller") + filterContext.RouteData.GetRequiredString("action");

    Summary

    在本篇文章中,讲述的内容非常有限,主要讨论了怎么获取Filter的,以及Controller与各种 Filter的关系,还有Filter的4种类型,但是我们没有具体讨论4种类型Filter的方法。还有最终要的就是大家通过这个探究这个过程,真正了理解Filter的设计思想和AOP在mvc中的运用,以及Filter的功能强大之处。

    Link:

    http://msdn.microsoft.com/zh-cn/library/dd410209(v=vs.100).aspx

    http://weblogs.asp.net/rashid/archive/2010/05/27/mvcextensions-actionfilter.aspx

  • 相关阅读:
    asp.net服务器控件button先执行js再执行后台的方法
    详谈ASP.NET的DataReader对象
    ASP.NET Web API的Controller是如何被创建的?
    富文本编辑器复制粘贴图片上传
    富文本编辑器的使用和图片上传,复制粘贴图片上传
    能够粘贴Word文档公式的编辑器
    可以粘贴Word公式的编辑器
    可以粘贴Word文档公式的编辑器
    可以粘贴Word文档中公式的编辑器
    openstack nova 深入
  • 原文地址:https://www.cnblogs.com/Irving/p/2812867.html
Copyright © 2011-2022 走看看