【ASP.NET MVC 学习笔记】- 12 Filter
本文参考:http://www.cnblogs.com/willick/p/3331520.html
1、Filter(过滤器)是基于AOP(Aspect-Oriented Programming 面向切面编程)的设计。作用是对MVC框架处理客户端请求注入额外的逻辑,以非常优美简单的方式实现横切关注点(Cross-cutting Concerns)。所谓横切关注点是指横越应用程序多个甚至所有模块的功能,经典的横切关注点有日志记录、缓存处理、异常处理和权限验证等。
2、MVC框架支持的Filter可以分为四类,每一个类都可以在处理请求的不同时间点注入额外的逻辑处理。这四类Filter如下图:
其中ActionFilter是一个抽象类,使用之前必须对它进行实现;而另外两个则有默认实现可以直接调用。这些Filter既可以用在单个Action上,也可以用在整个Controller上。
对于自定义的Controller基类,应用于该基类的Filter也将对继承自该基类的子类有效。
2、Authorization Filter是在Action和其他种类的Filter之前运行的,作用是强制实施权限策略,保证Action只被授权了的用户调用。它实现的接口如下:
namespace System.Web.Mvc
{
public interface IAuthorizationFilter
{
void OnAuthorization(AuthorizationContext filterContext);
}
}
我们可以通过继承IAuthorizationFilter接口自定义Authorization Filter。下列示例自定义了一个Filter用于验证是否允许本地请求。
//AuthorizeAttribte 类帮我们内置地实现了很多东西,我们只需把重点放在 AuthorizeCore 方法上,在该方法中实现权限认证的逻辑。
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;
}
}
}
[Authorize(Users = "jim, steve, jack", Roles = "admin")]//使用内置的Authorization Filter,该语句的意思是只允许角色为admin、且用户名必须是jim、steve、jack中的一个的用户访问该Action
public string Index()
{
return "This is the Index action on the Home controller";
}
3、Exception Filter在下面三种来源抛出未处理异常时运行:
- 另外一种Filter(如Authorization、Action或Result等Filter)。
- Action方法本身。
- Action方法执行完成(即处理ActionResult的时候)。
Exception Filter 必须实现接口IExceptionFilter,该接口定义为:
namespace System.Web.Mvc
{
public interface IExceptionFilter
{
void OnException(ExceptionContext filterContext);
}
}
ExceptionContext继承自ControllerContext,后者的常用属性说明:
- Controller,返回当前请求的controller对象。
- HttpContext,提供请求和响应的详细信息。
- IsChildAction,如果是子action则返回true(稍后将简单介绍子action)。
- RequestContext,提供请求上下文信息。
- RouteData,当前请求的路由实例信息。
ExceptionContext的常用属性说明:
- ActionDescriptor,提供action方法的详细信息。
- Result,是一个 ActionResult 类型,通过把这个属性值设为非空可以让某个Filter的执行取消。
- Exception,未处理异常信息。
- ExceptionHandled,如果另外一个Filter把这个异常标记为已处理则返回true。
一个Exception Filter可以通过把 ExceptionHandled 属性设置为true来标注该异常已被处理过,这个属性一般在某个action方法上应用了多个Exception Filter时会用到。ExceptionHandled 属性设置为true后,就可以通过该属性的值来判断其它应用在同一个action方法上的Exception Filter是否已经处理了这个异常,以免同一个异常在不同的Filter中重复被处理。示例:
//1、Filter的定义,通过重定向到Content目录下的一个静态html文件来显示友好的 ArgumentOutOfRangeException 异常信息。
//RangeExceptionAttribute 类继承了FilterAttribute类,并且实现了IException接口。
//作为一个MVC Filter,它的类必须实现IMvcFilter接口,你可以直接实现这个接口,但更简单的方法是继承 FilterAttribute 基类
public class RangeExceptionAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled && filterContext.Exception is ArgumentOutOfRangeException)
{
filterContext.Result = new RedirectResult("~/Content/RangeErrorPage.html");
filterContext.ExceptionHandled = true;
}
}
} //2、RangeErrorPage.html页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Range Error</title>
</head>
<body>
<h2>Sorry</h2>
<span>One of the arguments was out of the expected range.</span>
</body>
</html> //3、HomeController中添加一个值越限时抛出异常的action
public class HomeController : Controller
{
[RangeException]
public string RangeTest(int id)
{
if (id > )
{
return String.Format("The id value is: {0}", id);
}
else
{
throw new ArgumentOutOfRangeException("id", id, "");
}
}
}
由于静态的html文件是和后台脱离的,所以实际项目中更多的是用一个View来呈现友好的错误信息,以便很好的对它进行一些动态的控制:
//1、定义Filter
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 ViewResult
{
ViewName = "RangeError",
ViewData = new ViewDataDictionary<int>(val)
};
filterContext.ExceptionHandled = true;
}
}
} //2、RangeError.cshtml
@model int <!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Range Error</title>
</head>
<body>
<h2>Sorry</h2>
<span>The value @Model was out of the expected range.</span>
<div>
@Html.ActionLink("Change value and try again", "Index")
</div>
</body>
</html>
4、程序发布后不应该显示异常信息给用户看。我们可以通过配置Web.config让应用程序不管在何时何地引发了异常(即使是在View中的异常)都可以显示统一的友好错误信息。在Web.config文件中的<system.web>节点下添加如下子节点:
<system.web><customErrors mode="On" defaultRedirect="/Content/RangeErrorPage.html"/>//这个配置只对远程访问有效,本地运行站点依然会显示跟踪信息。
</system.web>
5、MVC框架内置的 HandleErrorAttribute包含ExceptionType、View和Master三个属性。当ExceptionType属性指定类型的异常被引发时,这个Filter将用View属性指定的View(使用默认的Layout或Mast属性指定的Layout)来呈现一个页面。示例:
[HandleError(ExceptionType = typeof(ArgumentOutOfRangeException), View = "RangeError")]
public string RangeTest(int id)
{
if (id > )
{
return String.Format("The id value is: {0}", id);
} else
{
throw new ArgumentOutOfRangeException("id", id, "");
}
}
使用内置的HandleErrorAttribute,将异常信息呈现到View时,这个特性同时会传递一个HandleErrorInfo对象作为View的model。HandleErrorInfo类包含ActionName、ControllerName和Exception属性,如下面的 RangeError.cshtml 使用这个model来呈现信息:
@model HandleErrorInfo
@{
ViewBag.Title = "Sorry, there was a problem!";
} <!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Range Error</title>
</head>
<body>
<h2>Sorry</h2>
<span>The value @(((ArgumentOutOfRangeException)Model.Exception).ActualValue)
was out of the expected range.</span>
<div>
@Html.ActionLink("Change value and try again", "Index")
</div>
<div style="display: none">
@Model.Exception.StackTrace
</div>
</body>
</html>
6、ActionFilter是对Action方法的执行进行筛选的,包括执行前和执行后。它实现了以下接口:
namespace System.Web.Mvc
{
public interface IActionFilter
{
//在action方法执行之前被调用
void OnActionExecuting(ActionExecutingContext filterContext); //在action方法执行之后被调用
void OnActionExecuted(ActionExecutedContext filterContext);
}
}
下列示例自定义了一个ActionFilter:
//自定义ActionFilter
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("<div>Action method elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));
}
}
} //在HomeController中添加一个Action并应用该Filter
[ProfileAction]
public string FilterTest()
{
return "This is the ActionFilterTest action";
}
7、Result Filter用来处理action方法返回的结果,是在Action Filter之后执行的。用法和Action Filter类似,它需要实现 IResultFilter 接口,定义如下:
namespace System.Web.Mvc
{
public interface IResultFilter
{
void OnResultExecuting(ResultExecutingContext filterContext);
void OnResultExecuted(ResultExecutedContext filterContext);
}
}
示例代码:
//1、Filter 定义
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("<div>Result elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));
}
} //2、应用
[ProfileAction]
[ProfileResult]
public string FilterTest()
{
return "This is the ActionFilterTest action";
}
8、MVC框架内置了一个 ActionFilterAttribute 类用来创建action 和 result 筛选器,即可以控制action方法的执行也可以控制处理action方法返回结果。它是一个抽象类,定义如下:
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)
{
}
}
}
使用这个抽象类方便之处是你只需要实现需要加以处理的方法。示例:
//1、定义
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("<div>Total elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));
}
} //2、应用
[ProfileAction]
[ProfileResult]
[ProfileAll]
public string FilterTest()
{
return "This is the FilterTest action";
}
我们也可以Controller中直接重写 ActionFilterAttribute 抽象类中定义的四个方法,效果和使用Filter是一样的,例如:
public class HomeController : Controller
{
private Stopwatch timer;
...
public string FilterTest()
{
return "This is the FilterTest action";
} protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
timer = Stopwatch.StartNew();
} protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
timer.Stop();
filterContext.HttpContext.Response.Write(string.Format("<div>Total elapsed time: {0}</div>", timer.Elapsed.TotalSeconds));
}
}
9、全局Filter对整个应用程序的所有controller下的所有action方法有效。在App_Start/FilterConfig.cs文件中的RegisterGlobalFilters方法,可以把一个Filter类注册为全局,如:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new ProfileAllAttribute()); //如此,ProfileAllAttribute将对所有的action有效
}
}
10、MVC框架内置了很多Filter,常见的有RequireHttps、OutputCache、AsyncTimeout等等。下面是几个常用的:
- RequireHttps,强制使用HTTPS协议访问。它将浏览器的请求重定向到相同的controller和action,并加上 https:// 前缀。
- OutputCache,将action方法的输出内容进行缓存。
- AsyncTimeout/NoAsyncTimeout,用于异步Controller的超时设置。
- ChildActionOnlyAttribute,使用action方法仅能被Html.Action和Html.RenderAction方法访问。
【ASP.NET MVC 学习笔记】- 12 Filter的更多相关文章
- ASP.NET MVC学习笔记-----Filter
ASP.NET MVC学习笔记-----Filter(1) Filter类型 接口 MVC的默认实现 Description Authorization IAuthorizationFilter Au ...
- ASP.NET MVC学习笔记-----Filter(2)
接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用,它需要实现IActionFilter接口: public ...
- ASP.NET MVC学习笔记-----Filter2
ASP.NET MVC学习笔记-----Filter(2) 接上篇ASP.NET MVC学习笔记-----Filter(1) Action Filter Action Filter可以基于任何目的使用 ...
- Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建
Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...
- ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现
ASP.NET MVC 学习笔记-2.Razor语法 1. 表达式 表达式必须跟在“@”符号之后, 2. 代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...
- ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则
ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...
- ASP.NET MVC5学习笔记之Filter基本介绍
Filter是ASP.NET MVC框架提供的基于AOP(面向方面)设计,提供在Action执行前后做一些非业务逻辑通用处理,如用户验证,缓存等.现在来看看Filter相关的一些类型信息. 一.基本类 ...
- ASP.NET MVC学习笔记-----Filter(1)
Filter类型 接口 MVC的默认实现 Description Authorization IAuthorizationFilter AuthorizeAttribute 最先执行,在其他类型的fi ...
- ASP.NET MVC5学习笔记之Filter提供体系
前面我们介绍了Filter的基本使用,但各种Filter要在合适的时机运行起来,需要预先准备好,现在看看ASP.NET MVC框架是怎么做的. 一.Filter集合 在ControlerActionI ...
随机推荐
- 201521123071 《JAVA程序设计》第十二周学习总结
第12周作业-多线程 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件线程相关内容. 2. 书面作业 1. 字符流与文本文件:使用 PrintWriter(写),Buff ...
- 201521123035《Java程序设计》第十周实验总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题目4-2 1.1 截图你的提交结果(出 ...
- 201521123031 《Java程序设计》第13周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...
- 杭电acm-2007平方和立方和
#include<stdio.h>int main(){ int t,m,n,x,y,i; while(scanf("%d%d",&n, ...
- python 浅析模块
今天买了一本关于模块的书,说实话,模块真的太多了,小编许多也不知道,要是把模块全讲完,可能得出本书了,所以小编在自己有限的能力范围内在这里浅析一下自己的见解,同时讲讲几个常用的模块. 首先说一下对模块 ...
- Project Euler:Product-sum numbers (problem 88) C++
A natural number, N, that can be written as the sum and product of a given set of at least two natur ...
- 使用Spring的JavaConfig 和 @Autowired注解与自动装配
1 JavaConfig 配置方法 之前我们都是在xml文件中定义bean的,比如: 1 2 3 4 5 6 7 8 <beans xmlns="http://www.springf ...
- GCD之信号量机制二
在前面GCD之信号量机制一中介绍了通过信号量设置并行最大线程数,依此信号量还可以防止多线程访问公有变量时数据有误,下面的代码能说明. 1.下面是不采用信号量修改公有变量的值 1 2 3 4 5 6 7 ...
- asp.net mvc项目实记-开启伪静态-Bundle压缩css,js
百度这些东西,还是会浪费了一些不必要的时间,记录记录以备后续 一.开启伪静态 如果不在web.config中配置管道开关则伪静态无效 首先在RouteConfig.cs中中注册路由 routes.Ma ...
- Bit Byte WORD DWORD的区别和联系
typedef unsigned short WORD; 16位短整数,可以表示0-65535之间的整数 而char是8位. int和机器类型有关.如16位机,就表示16位.32位机就表示32位 基本 ...