ASP.NET MVC过滤器

1、引言

在ASP.NET MVC开发中,在控制器中定义的方面通常与界面上的View是一对一的关系,例如点击一个连接或者提交一个表单,如当用户点击一个连接,请求被路由到目的路由,相应的方法被调用,有时我们想要在方法执行之前或者执行之后指向一个额外的逻辑操作,为了支持这种需求,在ASP.NET MVC中提供了过滤器, 过滤器是自定义类,它们提供了一种声明性和程序性的方法来向控制器操作方法添加动作前和动作后的行为。

2、过滤器介绍

ASP.NET MVC中提供了四种过滤器类型,分别是Authorization(授权),Action(行为),Result(结果)和Exception(异常),具体如下表

过滤器类型 接口 默认实现 描述
Authorization filters IAuthorizationFilter AuthorizeAttribute 首先允许在任何过滤器或者方法之前
Action filters IActionFilter ActionFilterAttribute 在动作方法执行前与后
Result filters IResultFilter ActionFilterAttribute 在动作结果被执行前或者后执行
Exception filters IExceptionFilter HandleErrorAttribute 只在另一个过滤器、动作方法、动作结果弹出异常时允许


  授权筛选器。这些筛选器用于实现IAuthorizationFilter和做出关于是否执行操作方法(如执行身份验证或验证请求的属性)的安全决策。AuthorizeAttribute类和RequireHttpsAttribute类是授权筛选器的示例。授权筛选器在任何其他筛选器之前运行。

   操作筛选器。这些筛选器用于实现IActionFilter以及包装操作方法执行。IActionFilter接口声明两个方法:OnActionExecuting和OnActionExecuted。OnActionExecuting在操作方法之前运行。OnActionExecuted在操作方法之后运行,可以执行其他处理,如向操作方法提供额外数据、检查返回值或取消执行操作方法。

  结果筛选器。这些筛选器用于实现IResultFilter以及包装ActionResult对象的执行。IResultFilter声明两个方法:OnResultExecuting和OnResultExecuted。OnResultExecuting在执行ActionResult对象之前运行。OnResultExecuted在结果之后运行,可以对结果执行其他处理,如修改HTTP响应。OutputCacheAttribute类是结果筛选器的一个示例。

  异常筛选器。这些筛选器用于实现IExceptionFilter,并在ASP.Net MVC管道执行期间引发了未处理的异常时执行。异常筛选器可用于执行诸如日志记录或显示错误页之类的任务。HandleErrorAttribute类是异常筛选器的一个示例

下面来看看每个Filter的作用时机(执行顺序),如下图:
这里写图片描述

3、过滤器常见得应用

下面是个人在开发中,常用到的Filter处理:

  • 权限验证

      使用Authorization filters,拦截请求,在进入到Controller处理之前,验证用户是否登录或者登录用户是否有权限访问改页面。如果合法,就继续交由Controller处理,如果非法,中断流程,跳转到登录页面。

  • 日志记录

      通过Action Filter跟踪记录Action处理开始的时间,结束时间,访问的具体Controller和Action, 参数,访问者ip等信息。

  • 异常处理

      异常处理Exception filter能够在发生异常的时候,记录异常信息。如果是session过期引起的异常,则跳转到登录页面,如果是程序运行导致的无法处理异常,则跳转到友好的错误页面。

  • 提升SEO效果

      每篇博客文章的meta信息能够帮助提高SEO效果,但是很多人对于填写keyword, description等信息觉得太繁琐。可以使用Result filters,在最后呈现页面前,使用程序分析内容,提取keyword和description来,然后填充到meta信息中。这样,每篇博客文章都能够有程序实现最佳的SEO效果,甚至生成一份SEO报告出来。

4、过滤器的应用

对于过滤器,我们可以把它们加在三个地方一个是控制器上面(控制器下面的所有Action)或者直接实现控制器的上述filter,一个是Action上面(指定标识的Action),另一个就是全局位置(所有控制器中的Action),下面我们分别演示过滤器引用到这三个地方,首先我们定义过滤器,将过滤器定义到网站的Filter目录下
授权过滤器代码如下:

 public class PermissionHandlerFilterAttribute : AuthorizeAttribute
    {

        public System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> ExecuteActionFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>> continuation)
        {
            return null;
        }
        //代码顺序为:OnAuthorization-->AuthorizeCore-->HandleUnauthorizedRequest 
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {

         //return false;返回false,执行HandleUnauthorizedRequest方法    
        return true;
        }
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.Write("OnAuthorization执行了<br/>");
            base.OnAuthorization(filterContext);//必须有这句,否则不能调用AuthorizeCore方法, 否则不能验证
        }
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            base.HandleUnauthorizedRequest(filterContext);
        }

    }

行为过滤器代码如下:

 public class ActionHandlerFilterAttribute:FilterAttribute,IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.Write("OnActionExecuted执行了<br/>");
        }
        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.Write("OnActionExecuting执行了<br/>");
        }
    }

结果过滤器代码如下:

public class ResultHandlerFilterAttribute:FilterAttribute,IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.Write("OnResultExecuted执行了<br/>");
        }

        public void OnResultExecuting(ResultExecutingContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.Write("OnResultExecuting执行了<br/>");
        }
    }

异常过滤器代码如下:

 public class ExceptionHandlerFilterAttribute:FilterAttribute,IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            filterContext.RequestContext.HttpContext.Response.Write("OnException执行了<br/>");
        }
    }

注意:在此需要引入的命名空间是using System.Web.Mvc;而不是System.Web.Http.Filters(Web Api使用)

  • 注册全局过
    打开网站的Global.asax.cs,代码如下,可以看到一运行就把过滤器给加载上了,代码如下:
    这里写图片描述
    然后打开网站的App_Start文件夹下面的FilterConfig.cs,代码如下:
 public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            //注册全局的filter
            filters.Add(new PermissionHandlerFilterAttribute());
            filters.Add(new ActionHandlerFilterAttribute());
            filters.Add(new ResultHandlerFilterAttribute());
            filters.Add(new ExceptionHandlerFilterAttribute());
            //filters.Add(new HandleErrorAttribute());//系统默认加载异常处理过滤器,我们在此注释掉,只用自定义的异常处理过滤器
        }
    }

至此,在网站的所有action都添加了过滤器,允许网站,如下图:
这里写图片描述
可以看到定义的过滤器执行了。

  • 将过滤器应用到Controller
    接着上面,我们把在App_Start文件夹的FilterConfig.cs注册的过滤器注释到,添加到控制器上,代码如下:
    这里写图片描述
    执行结果同上,
  • 将过滤器应用到Action
    接下来我们将在Controller上添加的过滤器,添加到action,代码如下:
    这里写图片描述

5、全局授权过滤器(排除指定Controller和action方法)

在开发网站的时候,当用户没有登录的时候,我们希望用户跳转到登录页面,而在加载登录页面是,检测到没有登录,重新跳转到登录页面,这样就形成了死循环,这就要求我们排除指定Controller和action方法,代码如下:

[AllowAnonymous]//表示一个特性,该特性用于标记在授权期间要跳过 System.Web.Mvc.AuthorizeAttribute 的控制器和操作。
        public ActionResult Login()
        {
            return View();
        }
        [AllowAnonymous]
        [HttpPost]
        public ActionResult Login(TUsers user)
        {
             TUsers u = db.TUsers.Where(d => d.Account == user.Account && d.Password == user.Password).FirstOrDefault<TUsers>();
             if (u != null)
             {
                 HttpCookie cookie = new HttpCookie("login");
                 cookie.Value = DateTime.Now.ToString("yyyyMMddHHmmmss");
                 Response.AppendCookie(cookie);
                 Session["account"] = u.Account;
                 return RedirectToAction("Index", "TNews");
             }
             else
             {
                 ModelState.AddModelError("", "账号或者密码错误,请重试");
                 //return Content("账号或者密码错误");
             }
            return View();
        }

参考资料
1、Filtering in ASP.NET MVC
2、FilterScope Enumeration

猜你喜欢

转载自blog.csdn.net/u011872945/article/details/72989052