热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MVC4过滤器(转)

先来看看一个例子演示过滤器有什么用:

public class AdminController : Controller { 
// ... instance variables and constructor 
public ViewResult Index() { 
if (!Request.IsAuthenticated) { 
FormsAuthentication.RedirectToLoginPage(); 
} 
// ...rest of action method 
} 
public ViewResult Create() { 
if (!Request.IsAuthenticated) { 
FormsAuthentication.RedirectToLoginPage(); 
} 
// ...rest of action method 
} 
...

AdminController控制器的众多Action中我们都需要判定当前验证用户,这里有很多重复的代码,我们可以简化为:

[Authorize] 
public class AdminController : Controller { 
// ... instance variables and constructor 
public ViewResult Index() { 
// ...rest of action method 
} 
public ViewResult Create() { 
// ...rest of action method 
} 
...

Authorize特性类AuthorizeAttribute就称作MVC的Filter,它在横向为MVC框架扩展功能,让我们可以更方便的处理日志、授权、缓存等而不影响纵向主体功能。

MVC常用的滤器类型:

  • Authorization:实现IAuthorizationFilter接口,默认实现类AuthorizeAttribute,在调用Action方法前首先处理认证信息。
  • Action:实现IActionFilter接口,默认实现类ActionFilterAttribute,在运行Action前后调用实现一些额外的动作。
  • Result:实现IResultFilter接口,默认实现类ActionFilterAttribute,在action result运行前后调用实现额外的动作。
  • Exception:实现IExceptionFilter接口,默认实现类HandleErrorAttribute,仅在其他过滤器或者action方法或者action result抛出异常时调用。

过滤器可以应用在整个控制器类上,也可以单对某个Action方法,当然也可以是同时应用多个过滤器:

[Authorize(Roles="trader")] // applies to all actions 
public class ExampleController : Controller { 
[ShowMessage] // applies to just this action 
[OutputCache(Duration=60)] // applies to just this action 
public ActionResult Index() { 
// ... action method body 
} 
} 

Authorization过滤器

Authorization过滤器用于控制仅授权的用户可以调用某个Action方法,它必须实现IAuthorizationFilter接口:

namespace System.Web.Mvc { 
public interface IAuthorizationFilter { 
  void OnAuthorization(AuthorizationContext filterContext); 
} 
} 

处理安全方面的代码必须谨慎全面,一般我们不要直接实现接口IAuthorizationFilter,而从AuthorizeAttribute扩展自定义类:

public class CustomAuthAttribute : AuthorizeAttribute { 
  private bool localAllowed; 
  public CustomAuthAttribute(bool allowedParam) { 
    localAllowed = allowedParam; 
  } 
  protected override bool AuthorizeCore(HttpContextBase httpContext) { 
    if (httpContext.Request.IsLocal) { 
    return localAllowed; 
    } else { 
    return true; 
    } 
  } 
} 

这里定义了CustomAuthAttribute过滤器,如果请求来自于非本机总是允许,如果是本机请求则视传入参数allowedParam而定:

public class HomeController : Controller { 
  [CustomAuth(false)] 
  public string Index() { 
    return "This is the Index action on the Home controller"; 
  } 
} 

 默认实现AuthorizeAttribute足够应付多数授权功能限制,我们可以传入参数限制访问的用户或者角色:

[Authorize(Users = "adam, steve, jacqui", Roles = "admin")] 

需要注意的是AuthorizeAttribute仅仅负责授权,而用户的认证则依赖于ASP.NET的认证机制。

Exception过滤器

Exception过滤器需要实现IExceptionFilter接口:

namespace System.Web.Mvc { 
public interface IExceptionFilter { 
void OnException(ExceptionContext filterContext); 
} 
} 

从filterContext我们可以获取很多相关信息,比如Controller、HttpContext、IsChildAction、RouteData、Result、Exception、ExceptionHandled等。异常的具体信息我们可以从Exception获取,我们设置ExceptionHandled为true报告异常已经处理,在设置为true之前最好检查异常是否已经被action方法上其他的过滤器处理,以避免重复的错误纠正动作。如果异常未被处理(ExceptionHandled!=true),MVC框架使用默认的异常处理程序显示ASP.NET的黄屏错误页面。

我们可以创建自定义的异常过滤器:

 public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter {
        public void OnException(ExceptionContext filterContext) {
            if (!filterContext.ExceptionHandled &&
                filterContext.Exception is ArgumentOutOfRangeException) {
                     int val = (int)(((ArgumentOutOfRangeException)filterContext.Exception).ActualValue);
                    //filterContext.Result = new RedirectResult("~/Content/RangeErrorPage.html");
                    filterContext.Result = new ViewResult { 
                        ViewName = "RangeError", 
                        ViewData = new ViewDataDictionary<int>(val)
                    };
                    filterContext.ExceptionHandled = true;
            }
        }
    }

注意这里RangeExceptionAttribute除了实现IExceptionFilter接口还从FilterAttribute继承,这是因为MVC的过滤器类还必须实现IMvcFilter接口,这里我们没有直接实现IMvcFilter接口,改为从默认封装类FilterAttribute继承。如下使用这个自定义过滤器:

[RangeException] 
public string RangeTest(int id) { 
  if (id > 100) { 
  return String.Format("The id value is: {0}", id); 
  } else { 
  throw new ArgumentOutOfRangeException("id"); 
  } 
} 

在发生异常时过滤器会将我们重定向到RangeError视图。

通常我们不需要创建自己的异常处理器,而使用MVC提供的默认过滤器HandleErrorAttribute:

[HandleError(ExceptiOnType= typeof(ArgumentOutOfRangeException), View = "RangeError",Master="")]

属性ExceptionType指定要处理的异常类型,如果不指定则处理所有异常类型;view指定错误时要渲染的视;master指定所用的页面布局。

在使用HandleErrorAttribute过滤前我们必须在Web.config的一节启用CusomErrors:

 

默认customErros为RemoteOnly,defaultRedirect指定一个默认的错误页面。

Action过滤器

Action过滤器必须实现IActionFilter接口:

namespace System.Web.Mvc { 
public interface IActionFilter { 
  void OnActionExecuting(ActionExecutingContext filterContext); 
  void OnActionExecuted(ActionExecutedContext filterContext); 
  } 
} 

OnActionExecuting()在调用action方法前调用,OnActionExecuted()则在调用action方法后调用。

OnActionExecuting的一个实现例子:

MVC4 过滤器(转)
public class CustomActionAttribute : FilterAttribute, IActionFilter {

        public void OnActionExecuting(ActionExecutingContext filterContext) {
            if (filterContext.HttpContext.Request.IsLocal) {
                filterContext.Result = new HttpNotFoundResult();
            }
        }

        public void OnActionExecuted(ActionExecutedContext filterContext) {
            // not yet implemented
        }
    }
MVC4 过滤器(转)

这里我们仅实现了OnActionExecuting方法,在从本地请求任何应用此过滤器的action方法时返回404错误。

OnActionExecuted的一个例子:

MVC4 过滤器(转)
 public class ProfileActionAttribute : FilterAttribute, IActionFilter {
        private Stopwatch timer;


        public void OnActionExecuting(ActionExecutingContext filterContext) {
            timer = Stopwatch.StartNew();
        }

        public void OnActionExecuted(ActionExecutedContext filterContext) {
            timer.Stop();
            if (filterContext.Exception == null) {
                filterContext.HttpContext.Response.Write(
                    string.Format("
profile result method elapsed time: {0}
", timer.Elapsed.TotalSeconds)); } } }
MVC4 过滤器(转)

 

在调用action方法前我们启动计时器,在action方法调用后停止计时器并输出计时器所计action方法运行时长。

Result过滤器

Result过滤器实现IResultFilter接口:

namespace System.Web.Mvc { 
public interface IResultFilter { 
void OnResultExecuting(ResultExecutingContext filterContext); 
void OnResultExecuted(ResultExecutedContext filterContext); 
} 
} 

Result过滤器操作的是action方法返回结果,有意思的是即使action方法返回void所应用的Result过滤器也会动作。

类似上面的ProfileAction过滤器我们可以对Result运行计时:

MVC4 过滤器(转)
public class ProfileResultAttribute : FilterAttribute, IResultFilter {
        private Stopwatch timer;

        public void OnResultExecuting(ResultExecutingContext filterContext) {
            timer = Stopwatch.StartNew();
        }

        public void OnResultExecuted(ResultExecutedContext filterContext) {
            timer.Stop();
            filterContext.HttpContext.Response.Write(
                    string.Format("
Result elapsed time: {0}
", timer.Elapsed.TotalSeconds)); } }
MVC4 过滤器(转)

内建的Result过滤器类ActionFilterAttribute

MVC为我们提供了ActionFilterAttribute类,它同时实现了action和result过滤器接口:

MVC4 过滤器(转)
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, 
IResultFilter{ 
public virtual void OnActionExecuting(ActionExecutingContext filterContext) { 
} 
public virtual void OnActionExecuted(ActionExecutedContext filterContext) { 
} 
public virtual void OnResultExecuting(ResultExecutingContext filterContext) { 
} 
public virtual void OnResultExecuted(ResultExecutedContext filterContext) { 
} 
} 
} 
MVC4 过滤器(转)

我们只需要继承该类并重载需要的方法,比如:

MVC4 过滤器(转)
public class ProfileAllAttribute : ActionFilterAttribute {
        private Stopwatch timer;

        public override void OnActionExecuting(ActionExecutingContext filterContext) {
            timer = Stopwatch.StartNew();
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext) {
            timer.Stop();
            filterContext.HttpContext.Response.Write(
                    string.Format("
Total elapsed time: {0}
", timer.Elapsed.TotalSeconds)); } }
MVC4 过滤器(转)

 Controller类的过滤器支持

MVC的Controller类内部实现了IAuthorizationFilter、IActionFilter、IResultFilter、IExceptionFilte四个接口,并提供OnXXX的虚函数供调用,比如:

    public class HomeController : Controller {
        private Stopwatch timer;
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            timer = Stopwatch.StartNew();
        }
        protected override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            timer.Stop();
            filterContext.HttpContext.Response.Write(
                    string.Format("
Total elapsed time: {0}
", timer.Elapsed.TotalSeconds)); }

全局过滤器

全局过滤器应用于应用程序内所有控制器的所有action方法,我们在App_Start/FilterConfig.cs可以注册全局过滤器:

public class FilterConfig {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
            filters.Add(new HandleErrorAttribute());
            filters.Add(new ProfileAllAttribute());
        }
    }

HandleErrorAttribute是VS为我们默认添加的,用于未处理异常错误时显示/Views/Shared/Error.cshtml页面;ProfileAllAttribute则是我们添加的自定义过滤器,运行任何action方法时都会调用这个过滤器。

其他MVC内建过滤器

MVC框架还内建提供以下过滤器:

  • RequireHttps:指示必须以HTTPS访问action方法,仅用于HTTP get方法
  • OutputCache:缓存action方法的结果
  • ValidateInput和ValidationAntiForgeryToken:安全授权相关的过滤器
  • AsnycTimeOut和NoAsyncTimeout:用于异步控制器
  • ChildActionOnlyAttribute:用于授权Html.Action或者Html.RenderAction调用子action方法

这些过滤器的使用方法可以参见MSDN。

过滤器的运行顺序

过滤器的运行按先后顺序是:authorization过滤器、action过滤器、result过滤器,期间任何时刻发生未处理异常调用异常处理器。这是针对不同类型的过滤器,但是如果所应用的是同一类的过滤器呢?MVC默认并不保证同类型过滤器的调用程序,也就是说很可能并非按照出现在代码中的先后程序来调用过滤器,但是我们可以显式的指定它们的调用顺序:

MVC4 过滤器(转)
... 
[SimpleMessage(Message="A", Order=2)] 
[SimpleMessage(Message="B", Order=1)] 
public ActionResult Index() { 
Response.Write("Action method is running"); 
return View(); 
} 
... 
MVC4 过滤器(转)

这里SimpleMessage是一个action过滤器,通过order我们指定它们的运行顺序: B->OnActionExecuting、A->OnActionExecuting、A->OnActionExecuted、B->OnActionExecuted。注意A的OnActionExecuted先于B的OnActionExecuted,和OnActionExecuting正好相反,这是无法改变的。在不指定order时,MVC内部指定为-1。另外如果同类型过滤器指定相同的order比如都是1,还要根据在哪里应用的过滤器来分先后执行:首先执行的是全局过滤器、然后是控制器类上、最后才是action方法;例外的是exception过滤器,它的顺序正好与此相反

更多:

Action过滤器使用实例(一)


推荐阅读
  • Asp.net Mvc Framework 七 (Filter及其执行顺序) 的应用示例
    本文介绍了在Asp.net Mvc中应用Filter功能进行登录判断、用户权限控制、输出缓存、防盗链、防蜘蛛、本地化设置等操作的示例,并解释了Filter的执行顺序。通过示例代码,详细说明了如何使用Filter来实现这些功能。 ... [详细]
  • 本文介绍了Sencha Touch的学习使用心得,主要包括搭建项目框架的过程。作者强调了使用MVC模式的重要性,并提供了一个干净的引用示例。文章还介绍了Index.html页面的作用,以及如何通过链接样式表来改变全局风格。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • Todayatworksomeonetriedtoconvincemethat:今天在工作中有人试图说服我:{$obj->getTableInfo()}isfine ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • SpringBoot整合SpringSecurity+JWT实现单点登录
    SpringBoot整合SpringSecurity+JWT实现单点登录,Go语言社区,Golang程序员人脉社 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文介绍了Python函数的定义与调用的方法,以及函数的作用,包括增强代码的可读性和重用性。文章详细解释了函数的定义与调用的语法和规则,以及函数的参数和返回值的用法。同时,还介绍了函数返回值的多种情况和多个值的返回方式。通过学习本文,读者可以更好地理解和使用Python函数,提高代码的可读性和重用性。 ... [详细]
author-avatar
uigrdg更好_154
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有