Asp.Net MVC Filter 实现方式和作用范围控制

MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多。但本文不是讨论Filter这些功能点,而是总结Filter实现的方式。说实现也不太准确,也就是它的呈现方式。自带有四种Filter(借用了Liam wang的图)

如果要实现自己的Filter,根本还是在于是实现第二项的接口。

   实现方式:

一、特性式

从上图可以看到,Filter的默认实现方式就是带有Attribute后缀的,有了Attribute,我们就可以将我们的Filter像标签一样的贴在方法或者控制器的上方。这样直观又简洁。最简单的自定义就是继承默认Filter。比如我定义一个LogFilter,继承于ActionFilter记录方法名,参数,和备注信息。

  1. public class LogFilterAttribute : ActionFilterAttribute
  2. {
  3. public string Message { get; set; }
  4. public override void OnActionExecuting(ActionExecutingContext filterContext)
  5. {
  6. var cname = filterContext.RouteData.Values["controller"].ToString();
  7. var actionName = filterContext.RouteData.Values["action"].ToString();
  8. var str = filterContext.ActionParameters.Aggregate("", (current, actionParameter) => current + (actionParameter.Key + ":" + actionParameter.Value));
  9. var message = string.Format("控制器:{0} 方法:{1} 参数:{2},执行时间:{3},备注信息:{4}", cname, actionName, str, DateTime.Now,
  10. Message);
  11. Logger.Debug(message);
  12. }
  13. public override void OnResultExecuted(ResultExecutedContext filterContext)
  14. {
  15. }
  16. }

调用的时候,贴在指定的方法上面就可以了。(当然你命名的时候可以把“Filter”拿掉),当然也可以分别去继承接口 比如public class MyLogAttribute : FilterAttribute, IActionFilter

  1. [LogFilter(Message = "管理员新增产品")]
  2. public ActionResult Create(Product product){
  3. //.....
  4. }

二、控制器实现

查看我们的Controller类,它本身是继承于IActionFilter 等这些接口的,同样,我们在控制器里面实现了这些方法也能发挥Filter的作用。没了Attribute,继续AOP

  1. public class UserController : Controller
  2. {
  3. //这里实现一个方法
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
  4. {
  5. filterContext.HttpContext.Response.Write("控制器实现,Action正在执行");
  6. }
    //.....
  7. }

这样在当前控制器下的所有方法执行时,页面都会输出这样一句话。

这种做法的作用不大,可以将前控制器作为一个控制器基类。

三、依赖注入式

这种方式意义不大,感觉绕了大弯子,而且不灵活。权当熟悉一下Ninject。

1.创建接口并实现。(IOC总是离不开接口)

 

2.实现一个自定义Filter

 

3.需要定义一个Filter Provider 在获取到上面类型的Filter的时候进行处理。

  1. public class DIFilterProvider : FilterAttributeFilterProvider
  2. {
  3. public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext,
  4. ActionDescriptor actionDescriptor)
  5. {
  6. IEnumerable<Filter> filters = base.GetFilters(controllerContext,
  7. actionDescriptor);
  8. var dependencyResolver = DependencyResolver.Current as NinjectDependencyResolver;
  9.  
  10. if (dependencyResolver != null)
  11. {
  12. foreach (Filter f in filters)
  13. {
  14. dependencyResolver.Kernel.Inject(f.Instance);
  15. }
  16. //Inject 方法会让Ninject去检查我们传入的对象,当它发现了Inject特性,就会为那个属性创造一个实例 前面的message
  17. }
  18. return filters;
  19. }
  20. }

4.绑定接口并加入Provider

我们需要在NinjectDependencyResolver 中绑定IMessageProvider和SimpleMessageProvider

 

在Global中加人

  1. protected void Application_Start() {
  2. AreaRegistration.RegisterAllAreas();
  3. DependencyResolver.SetResolver(new NinjectDependencyResolver());
  4.  
  5. FilterProviders.Providers.Insert(0,new DIFilterProvider()); //插在第一个。(这样便于实现需要IOC的Filter,不然其他的Provider找到Filter就返回了)
  6.  
  7. RegisterGlobalFilters(GlobalFilters.Filters);
  8. RegisterRoutes(RouteTable.Routes);
  9. }

这样在方法前面加入[DIMessage] 即可

用的最多的还是继承默认Filter和继承接口实现,他们的作用范围除了可以通过直接“贴”在Action或者Controller上面来控制还可以通过全局注册和Provider的方式来控制。

一、全局注册

在App_Start 文件夹中的FilterConfig已经默认注册了一个全局的 HandleErrorAttribute,这样相当于给所有的方法加上了HandleError标签

  1. public class FilterConfig
  2. {
  3. public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  4. {
  5. filters.Add(new HandleErrorAttribute()
  6. {
  7. ExceptionType = typeof(NullReferenceException),//可以设置捕获的异常类型
  8. View = "SpecialError"//默认跳转的视图
  9. });
  10. }
  11. }

二、FilterProvider

但如果我不想全局注册,也不想一个一个去加在方法的上方,我想一次性给所有控制器的Index方法加一个Filter,那怎么办? 用Filter provider 。

从IFilterProvider接口开始

  1. public interface IFilterProvider {
  2. IEnumerable<Filter> GetFilters(ControllerContext controllerContext,
  3. ActionDescriptor actionDescriptor);
  4. }

实现了这个接口并注册,在触发一个Action时候,GetFilters就会被调用。

而上文的Filter类是这样的,它包装了filter对象,而真正执行的filter就是这个instance。

  1. namespace System.Web.Mvc {public class Filter {
  2. public const int DefaultOrder = -1;
  3. public Filter(object instance, FilterScope scope, int? order) {
  4. // ...statements removed for clarity...
  5. }
  6. public object Instance { get; protected set; }
  7. public FilterScope Scope { get; protected set;}
  8. public int Order { get; protected set; }
  9. }
  10. }

Order和Scope定义了这个Filter的优先级和范围。FilterScope是枚举类型,包含First,Global,Controller,Action,Last。

我们先定义一个CustomFilterWrapper ,继承Filter,让其支持lambda 便于选择过滤。

  1. public class CustomFilterWrapper : Filter
  2. {
  3. public CustomFilterWrapper(object instance, FilterScope scope, int? order,Func<ControllerContext,ActionDescriptor,bool> selector ) : base(instance, scope, order)
  4. {
  5. Selector = selector;
  6. }
  7.  
  8. public Func<ControllerContext, ActionDescriptor, bool> Selector//便于通过控制器名称和action名称来过滤
  9. {
  10. get;
  11. set;
  12. }
    }

我们再实现一个CustomFilterProvider

  1. public class CustomFilterProvider : IFilterProvider
  2. {
  3. private IList<CustomFilterWrapper> wrappers;
  4.  
  5. public CustomFilterProvider()
  6. {
  7. wrappers = new List<CustomFilterWrapper>();
  8. }
  9. public IList<CustomFilterWrapper> Wrappers
  10. {
  11. get { return wrappers; }
  12. }
  13.  
  14. public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  15. {
  16. return wrappers.Where(e => e.Selector(controllerContext, actionDescriptor));
  17. }
  18. }

这样我们就可以Global中注册了。这样我们可以通过LINQ来选择我们需要加入Filter的方法了。

  1. protected void Application_Start() {
  2. AreaRegistration.RegisterAllAreas();

  3. CustomFilterProvider customFilterProvider = new CustomFilterProvider();
  4. customFilterProvider.Wrappers.Add(new CustomFilterWrapper(new LogFilterAttribute(), FilterScope.Action, 1, (c, a) => a.ActionName == "Index"));//所有控制器的Action方法会触发Logfilter
    FilterProviders.Providers.Add(customFilterProvider);
  1. RegisterGlobalFilters(GlobalFilters.Filters);
  2. RegisterRoutes(RouteTable.Routes);
  3. }

特此分享,希望对你有帮助,Thanks!

参考:Pro Asp.Net MVC3 FrameWork

 
 
分类: MVC读书笔记
标签: ASP.NET MVCAOPFilterIOC

MVC Filter 实现方式和作用范围控制的更多相关文章

  1. Asp.Net MVC Filter 实现方式和作用范围控制

    MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多.但本文不是讨论Filter这些功能点,而是总结Filter实现的方式.说实现也不太准确,也就是它的呈现方 ...

  2. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

  3. asp.net mvc各种传值方式大全

    MVC 各种传值方式 ViewData传值. HomeController.cs Co de: public ActionResult Index(){       ViewData["Ti ...

  4. MVC下载文件方式

    MVC下载文件方式 http://www.cnblogs.com/liang--liang/archive/2012/10/20/2732745.html 方式一: public FileStream ...

  5. 学习之-ASP.NET MVC Filter

    MVC Filter 是典型的AOP应用,对MVC框架处理客户端请求注入额外的一些逻辑,如日志记录.缓存处理.异常处理和权限验证,性能检测(横切关注点),而这些逻辑通常与主要业务无关,被独立分开作为公 ...

  6. Shiro入门之二 --------基于注解方式的权限控制与Ehcache缓存

    一  基于注解方式的权限控制 首先, 在spring配置文件applicationContext.xml中配置自动代理和切面 <!-- 8配置自动代理 -->    <bean cl ...

  7. .NET MVC 学习笔记(七)— 控制input控件

    .NET MVC 学习笔记(七)— 控制input控件 画面中有时候需要输入数字,这时就需要控制input的输入.以下为保留两位有效数字. /* * 初始化数字输入 */ function initD ...

  8. 013——VUE中多种方式使用VUE控制style样式属性

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. MVC下载文件方式 包括网络地址文件

    MVC下载文件方式 方式一: public FileStreamResult DownFile(string filePath, string fileName){      string absol ...

随机推荐

  1. JVM可支持的最大线程数(转)

    摘自:http://sesame.iteye.com/blog/622670 工作中碰到过这个问题好几次了,觉得有必要总结一下,所以有了这篇文章,这篇文章分为三个部分:认识问题.分析问题.解决问题. ...

  2. Ubuntu 14.04 LAMP搭建(Apache 2.47+MySQL 5.5+PHP5.5)

    原文:Ubuntu LAMP搭建 为了数据库课程设计,只好自己搭一个数据库系统,采用LAMP方式. 一.安装 1.安装Apache sudo apt-get install apache2 Apach ...

  3. NYNU_省赛选拔题(6)

    题目描述 有一天,小米找到了一个藏宝的迷宫地图,迷宫在一个沙漠里有,迷宫里面有许多宝藏.迷宫里可能有N个藏宝地点,用1到K标记.藏宝地点之间最多有一条通路相连.标记1为迷宫的进出口. 他已经知道其中K ...

  4. JavaScript 数组的indexOf()、remove()、splice() , pop()方法

    js中,按照值删除数组中的某个元素 Array.prototype.indexOf = function(val) {            for (var i = 0; i < this.l ...

  5. HDU - 1394 Minimum Inversion Number (线段树求逆序数)

    Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs ( ...

  6. linux_创建用户_copy远程文件_解压缩_执行

    查看历史命令: history 创建用户: sudo useradd -m -s /bin/bash cph  [会自动创建cph文件夹,并将才cph文件夹权限和组设为cph] 创建用户密码: pas ...

  7. 修改vim/terminal配色

    http://blog.csdn.net/angle_birds/article/details/11694325

  8. BZOJ 3282 Tree Link-Cut-Tree(LCT)

    题目大意: 给定N个点以及每一个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y ...

  9. asp.net 获得客户端 mac 地址

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  10. 有趣Web之Json(四)---json与(Object/List/Map)相互转化

    干web报名时间.通常,他们需要json转换为Object/list/map要么Object/List/map转换为json,由能够编写代码的简单包装非常多,以减轻负担. 本文将给出json的一系列的 ...