AOP(面向切面编程)是一种架构思想,用于把公共的逻辑放到一个单独的地方,这样就不用每个地方都写重复的代码了。比如程序中发生异常,不用每个地方都try…catch…只要在(Global 的Application_Error)中统一进行异常处理。不用每个Action中都检查当前用户是否有执行权限,
ASP.net MVC中提供了一个机制,每个Action执行之前都会执行我们的代码,这样统一检查即可。这就是过滤器的原理。
在ASP.Net MVC中提供了四个Filter(过滤器)接口实现了这种AOP机制:
IAuthorizationFilter、IActionFilter、IResultFilter、IExceptionFilter。
1,IAuthorizationFilter
一般用来检查当前用户是否有Action的执行权限,在每个Action被执行前执行OnAuthorization方法;
2,IActionFilter
也是在每个Action被执行前执行OnActionExecuting方法,每个Action执行完成后执行OnActionExecuted方法和IAuthorizationFilter的区别是IAuthorizationFilter在IActionFilter之前执行,检查权限一般写到IAuthorizationFilter中;
3,IResultFilter,在每个ActionResult的前后执行IResultFilter。用的很少,后面有一个应用。
4,IExceptionFilter,当Action执行发生未处理异常的时候执行OnException方法。
在ASP.net MVC 中仍然可以使用“Global 的Application_Error”,但是建议用IExceptionFilter。
如果某个Action过滤器运用了多种过滤器,那么过滤器的执行顺序是如何呢?
即执行顺序是:授权过滤器->动作过滤器->结果过滤器->异常过滤器。
注意:如果ActionFilter过滤器执行过程中发生了异常,那么会执行ExceptionFilter过滤器,不会执行ResultFilter过滤器。上图所示的是正常情况下的执行顺序。
编写一个类CheckAuthorFilter,实现IAuthorizationFilter接口(需要引用System.Web.Mvc程序集)
public class CheckLoginFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
string ctrlName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string actionName = filterContext.ActionDescriptor.ActionName;
if (ctrlName == "Login" && (actionName == "Index" || actionName == "Login"))
{
//什么都不做
}
else
{
if (filterContext.HttpContext.Session["username"] == null)
{
ContentResult contentResult = new ContentResult();
contentResult.Content = "没有登录";
//filterContext.Result = contentResult;
filterContext.Result = new RedirectResult("/Login/Index");
}
}
}
}
2.在Globel中注册这个Filter:GlobalFilters.Filters.Add(new CheckAuthorFilter());
示例代码:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalFilters.Filters.Add(new CheckLoginFilter());
}
3.CheckAuthorFilter中实现OnAuthorization方法。
filterContext.ActionDescriptor 可以获得Action的信息:
filterContext.ActionDescriptor.ActionName 获得要执行的Action的名字;
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName 为要执行的Controller的名字;
filterContext.ActionDescriptor.ControllerDescriptor.ControllerType 为要执行的Controller的Type;
filterContext.HttpContext 获得当前请求的HttpContext;
如果给“filterContext.Result”赋值了,那么就不会再执行要执行的Action,而是以“filterContext.Result”的值作为执行结果(注意如果是执行的filterContext.HttpContext.Response.Redirect(),那么目标Action还会执行的)。
4,检查当前用户是否登录,
如果没有登录则filterContext.Result = new ContentResult() { Content = “没有权限” };
或者filterContext.Result = new RedirectResult(“/Login/Index”);
最好不要filterContext.HttpContext.Response.Redirect(“/Login/Index”);)
public class ExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
File.AppendAllText("d:/error.log", filterContext.Exception.ToString());
filterContext.ExceptionHandled = true;//如果有其他的IExceptionFilter不再执行
filterContext.Result = new ContentResult() { Content = "error" };
}
}
然后:
GlobalFilters.Filters.Add(new ExceptionFilter());
总结好处:
一次编写,其他地方默认就执行了。可以添加多个同一个类型的全局Filter,按照添加的顺序执行。
(*)非全局Filter:
只要让实现类继承自FilterAttribute类,然后该实现哪个Filter接口就实现哪个(四个都支持)。不添加到GlobalFilters中,而是把这个自定义Attribute添加到Controller类上这样就只有这个Controller中操作会用到这个Filter。
如果添加到Action方法上,则只有这个Action执行的时候才会用到这个Filter。