1,在项目中添加Filters文件夹,所有Filters都放置在该文件夹中,方便后期归档
2,在Filters文件夹中添加一个类:CheckUserRoleAttribute.cs,在这里我们按照MVC约定的方式来命名,过滤器以Attribute来结尾。让其继承: System.Web.Mvc.ActionFilterAttribute。查看ActionFilterAttribute定义,其成员如下:
// 摘要: // 在执行操作方法后由 ASP.NET MVC 框架调用。 // // 参数: // filterContext: // 筛选器上下文。 public virtual void OnActionExecuted(ActionExecutedContext filterContext); // // 摘要: // 在执行操作方法之前由 ASP.NET MVC 框架调用。 // // 参数: // filterContext: // 筛选器上下文。 public virtual void OnActionExecuting(ActionExecutingContext filterContext); // // 摘要: // 在执行操作结果后由 ASP.NET MVC 框架调用。 // // 参数: // filterContext: // 筛选器上下文。 public virtual void OnResultExecuted(ResultExecutedContext filterContext); // // 摘要: // 在执行操作结果之前由 ASP.NET MVC 框架调用。 // // 参数: // filterContext: // 筛选器上下文。 public virtual void OnResultExecuting(ResultExecutingContext filterContext);
看注解可以知道4个成员:
OnActionExecuted
OnActionExecuting
OnResultExecuted
OnResultExecuted
而我一般都是重写OnActionExecuting方法:
public class CheckUserRoleAttribute : System.Web.Mvc.ActionFilterAttribute { public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext) { /* * 这里为了方便演示,直接在请求参数中获取了userName * 假设某一个Action只有Lucy可以访问。 */ string userName = filterContext.HttpContext.Request["userName"]; if (userName=="Lucy") { base.OnActionExecuting(filterContext); return; } else { //这里构造了一个心得ActionResult.如果userName不是Lucy,则返回权限不足 filterContext.Result = new System.Web.Mvc.ContentResult() { Content = "权限不足,无法访问" }; return; } } }
然后在HomeController中添加SayHello(),并且添加特性[CheckUserRole]
public class HomeController : Controller { [HttpGet] public ActionResult Index(string msg) { return Content("I'm come from Get Method."); } [HttpPost] public ActionResult Index() { return Content("I'm come from Post Method."); } //添加特性 [Filters.CheckUserRole] public ActionResult SayHello() { return Content("我是Lucy,这只能给我访问"); } }
点击调试:
这样子,一个简单的过滤器就实现了。
我们可以根据实际的逻辑去重写自己的过滤器。
**********************简单优雅的分隔符**********************
另外一个比较常用的是异常过滤器
1,同样新建SystemErrorAttribute.cs
需要注意,这里继承的是:System.Web.Mvc.HandleErrorAttribute
public class SystemErrorAttribute : System.Web.Mvc.HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { base.OnException(filterContext); //处理错误消息,将其跳转到一个页面 string controllerName = (string)filterContext.RouteData.Values["controller"]; string actionName = (string)filterContext.RouteData.Values["action"]; //这里简单向C盘的test.log写入了文件 FileStream fs = new FileStream(@"C: est.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter sw = new StreamWriter(fs); sw.BaseStream.Seek(0, SeekOrigin.End); string writeText = string.Format("controllerName:[{0}]actionName:[{1}]{2}", controllerName, actionName, filterContext.Exception.ToString()); sw.WriteLine(writeText); sw.Flush(); sw.Close(); fs.Close(); /*//这里是使用log4net来记录 log4net.ILog log = log4net.LogManager.GetLogger("controllerName:[" + controllerName + "]actionName:[" + actionName+"]"); log.Error(filterContext.Exception.ToString()); */ //錯誤友好輸出,这里重新构造了一个ActionResult filterContext.Result = new System.Web.Mvc.ContentResult() { Content = "系统错误,请联系管理员" }; return; } }
2,在HomeController中添加MyError()
public class HomeController : Controller { [Filters.SystemError]//添加 public ActionResult MyError() { //人为制造一个错误 int a = 1; int b = 0; return Content((a/b).ToString()); } }
3,调试:注意:这里需要采用Ctrl+F5的方式运行,结果如下:
到这里,可能会有很大疑问,为什么没有产生友好提示呢?在过滤器中不是明明有添加友好提示吗?
先看一下C盘的日志:test.log
日志有成功产生。没有出现友好提示的原因在于不是正式的环境,VS为了方便调试,不会隐藏错误信息。下面将应用部署到真实的环境中去调试,看结果:
这下友好提示又出来了。。。
当然对于异常处理过滤器来说,我在每个Action都来添加特性,还是很麻烦,这里我们就要注册成为全局过滤器:
①,打开App_Start文件夹中的FilterConfig.cs
添加:filters.Add(new Filters.SystemErrorAttribute());
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //添加这个 filters.Add(new Filters.SystemErrorAttribute()); filters.Add(new HandleErrorAttribute()); } }
②,在HomeController去掉[Filters.SystemError]特性,然后发布,调试结果:结果一样
就这样,全局异常处理就完成了。
2、对于过滤器,我们可以把它们加在三个地方,一个是控制器上面(控制器下面的所有Action),一个是Action上面(指定标识的Action),另一个就是全局位置(所有控制器中的Action)。这里我只演示在Action上面加
[MyCustormFilter]
public ActionResult Index()
{
return View();
}
public ActionResult Index1()
{
return View();
}
3、build然后运行
Result
1、新建类TestResultFilter,继承ActionFilterAttribute
public class TestResultFilter:ActionFilterAttribute { /// <summary> /// 加载 "视图" 前执行 /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuting(System.Web.Mvc.ResultExecutingContext filterContext) { filterContext.HttpContext.Response.Write("加载视图前执行 OnResultExecuting <br/>"); base.OnResultExecuting(filterContext); } /// <summary> /// 加载"视图" 后执行 /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext) { filterContext.HttpContext.Response.Write("加载视图后执行 OnResultExecuted <br/>"); base.OnResultExecuted(filterContext); } }
2、这里我把TestResultFilter过滤器加在控制器上面
[TestResultFilter] public class FilterTestController : Controller { [MyCustormFilter] public ActionResult Index() { return View(); } public ActionResult Index1() { return View(); } }
3、运行看下结果
注意:Result过滤器,无论Action的返回类型为什么(甚至void)都将执行。
RouteData中保存了当前请求匹配的路由信息和路由对象
修改MyCustormFilter.cs
public override void OnActionExecuting(ActionExecutingContext filterContext) { //1.获取获取请求的类名和方法名 string strController = filterContext.RouteData.Values["controller"].ToString(); string strAction = filterContext.RouteData.Values["action"].ToString();//2.另一种方式 获取请求的类名和方法名 string strAction2 = filterContext.ActionDescriptor.ActionName; string strController2 = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; filterContext.HttpContext.Response.Write("Action执行前</br>"); filterContext.HttpContext.Response.Write("控制器:" + strController + "</br>"); filterContext.HttpContext.Response.Write("控制器:" + strController2+"</br>"); filterContext.HttpContext.Response.Write("Action:" + strAction + "</br>"); filterContext.HttpContext.Response.Write("Action:" + strAction2 + "</br>"); base.OnActionExecuting(filterContext); }
AuthorizeAttribute
1、 新建TestAuthorizeAttribute
/// <summary> /// 授权过滤器 --在Action过滤器前执行 /// </summary> public class TestAuthorizeAttribute:AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { filterContext.HttpContext.Response.Write("<br/>OnAuthorization<br/>"); //注释掉父类方法,因为父类里的 OnAuthorization 方法会调用asp.net的授权验证机制! //base.OnAuthorization(filterContext); } }
2、在控制器FilterTest中的Index上添加TestAuthorize标记
[MyCustormFilter] [TestAuthorize] public ActionResult Index() { return View(); }
运行看下结果:
Exception
1、新建TestHandleError.cs
/// <summary> /// 异常处理 过滤器 /// </summary> public class TestHandleError : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { //1.获取异常对象 Exception ex = filterContext.Exception; //2.记录异常日志 //3.重定向友好页面 filterContext.Result = new RedirectResult("~/error.html"); //4.标记异常已经处理完毕 filterContext.ExceptionHandled = true; base.OnException(filterContext); } }
2、在Action上面加TestHandleError
[TestHandleError] public ActionResult GetErr() { int a = 0; int b = 1 / a; return View(); }
注意:通常这样的异常处理我们是放在全局过滤器上面的。
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); //添加全局过滤器 filters.Add(new TestHandleError()); } }