你的位置:首页 > ASP.net教程

[ASP.net教程]Asp.Net MVC过滤器小试牛刀


  在上学期间学习的Asp.Net MVC,基本只是大概马马虎虎的了解,基本处于知其然而不知其所以然。现在到上班,接触到真实的项目,才发现还不够用,于是从最简单的过滤器开始学习。不得不说MVC的过滤器真是简单,而又不失优雅。

  以前我写异常都是try...catch...配合log4net来记录日志,这真是一个重复造轮子的过程,一不小心还会忘记。后面在开发的过程中,逐渐学习到过滤器(Filter)这一优雅的东东,一下子爱上了它。

  在Asp.Net MVC有最基本的过滤器,添加一个Home控制器,然后添加两个Action,这里为了演示,添加了两个同名的Action,为了编译,设置了参数的区别,实际上并没有使用参数。

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.");  }}

点击调试,使用PostMan分别用get/post方式去访问Home/Index,如下图:

对于同一个Action,只是请求方式不一样,返回的结果也不一样,这就是Asp.Net最基本的过滤器。

[HttpGet]:该Action只响应get请求
[HttpPost]:该Action只响应post请求

于是我们可以思考,是不是可以考虑将很多重复的代码封装起来,例如判断用户是否有权限访问该Action,只需要简单的在Action上做一个特性标注就可以或者注册一个全局的机制,满足需要?很好,Asp.Net给我们提高了简单优雅的过滤器。

下面来简单看一下我自己写的权限判断过滤器。

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:\test.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]特性,然后发布,调试结果:结果一样

就这样,全局异常处理就完成了。

 

========================

由于学识有限,文章难免會有错误,敬请指教与批评。