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

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

  实现方式:

一、特性式

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

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

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

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

二、控制器实现

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

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

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

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

三、依赖注入式

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

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

  public interface IMessageProvider
{
string Message { get; }
} public class SimpleMessageProvider : IMessageProvider
{
public string Message
{
get
{
return "Hello IOC";
}
}
}

2.实现一个自定义Filter

public class DIMessageAttribute : FilterAttribute, IActionFilter {

        [Inject]//告诉我们的DI容器 这个属性需要依赖注入来获取实例
public IMessageProvider Provider { get; set; } public void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write(string.Format("[Before Action:{0}]",Provider.Message));
} public void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write(string.Format("[After Action:{0}]", Provider.Message));
}
}

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

 public class DIFilterProvider : FilterAttributeFilterProvider
{
public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext,
ActionDescriptor actionDescriptor)
{
IEnumerable<Filter> filters = base.GetFilters(controllerContext,
actionDescriptor);
var dependencyResolver = DependencyResolver.Current as NinjectDependencyResolver; if (dependencyResolver != null)
{
foreach (Filter f in filters)
{
dependencyResolver.Kernel.Inject(f.Instance);
}
//Inject 方法会让Ninject去检查我们传入的对象,当它发现了Inject特性,就会为那个属性创造一个实例 前面的message
}
return filters;
}
}

4.绑定接口并加入Provider

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

 public class NinjectDependencyResolver : IDependencyResolver
{
private readonly IKernel _kernel; public NinjectDependencyResolver()
{
_kernel = new StandardKernel();
AddBindings();
} public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
} public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType);
}
public IBindingToSyntax<T> Bind<T>()
{
return _kernel.Bind<T>();
} public IKernel Kernel
{
get { return _kernel; }
} private void AddBindings()
{
_kernel.Bind<IUserRepository>().To<UserRepository>();
_kernel.Bind<IDownloadFileRepository>().To<DownloadRepository>();
_kernel.Bind<IAuthProvider>().To<FormsAuthProvider>(); //绑定
Bind<IMessageProvider>().To<SimpleMessageProvider>();
}
}

在Global中加人

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

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

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

一、全局注册

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

 public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()
{
ExceptionType = typeof(NullReferenceException),//可以设置捕获的异常类型
View = "SpecialError"//默认跳转的视图
});
}
}

二、FilterProvider

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

从IFilterProvider接口开始

public interface IFilterProvider {
IEnumerable<Filter> GetFilters(ControllerContext controllerContext,
ActionDescriptor actionDescriptor);
}

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

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

namespace System.Web.Mvc {public class Filter {
public const int DefaultOrder = -;
public Filter(object instance, FilterScope scope, int? order) {
// ...statements removed for clarity...
}
public object Instance { get; protected set; }
public FilterScope Scope { get; protected set;}
public int Order { get; protected set; }
}
}

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

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

 public class CustomFilterWrapper : Filter
{
public CustomFilterWrapper(object instance, FilterScope scope, int? order,Func<ControllerContext,ActionDescriptor,bool> selector ) : base(instance, scope, order)
{
Selector = selector;
} public Func<ControllerContext, ActionDescriptor, bool> Selector//便于通过控制器名称和action名称来过滤
{
get;
set;
}
}

我们再实现一个CustomFilterProvider

 public class CustomFilterProvider : IFilterProvider
{
private IList<CustomFilterWrapper> wrappers; public CustomFilterProvider()
{
wrappers = new List<CustomFilterWrapper>();
}
public IList<CustomFilterWrapper> Wrappers
{
get { return wrappers; }
} public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return wrappers.Where(e => e.Selector(controllerContext, actionDescriptor));
}
}

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

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

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

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

参考:Pro Asp.Net MVC3 FrameWork

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

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

    Asp.Net MVC Filter 实现方式和作用范围控制 MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多.但本文不是讨论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. IoC容器Autofac(5) - Autofac在Asp.net MVC Filter中的应用

    Autofac结合EF在MVC中的使用,上一篇IoC容器Autofac(4) - Autofact + Asp.net MVC + EF Code First(附源码)已经介绍了.但是只是MVC中Co ...

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

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

  5. Asp.net Mvc (Filter及其执行顺序)

    应用于Action的Filter 在Asp.netMvc中当你有以下及类似以下需求时你可以使用Filter功能判断登录与否或用户权限,决策输出缓存,防盗链,防蜘蛛,本地化设置,实现动态Actionfi ...

  6. ASP.Net MVC Filter验证用户登录

    一.Filter是什么 ASP.NetMVC模式自带的过滤器Filter,是一种声明式编程方式,支持四种过滤器类型,各自是:Authorization(授权),Action(行为),Result(结果 ...

  7. ASP.NET MVC实现POST方式的Redirect

    我们知道,在ASP.NET MVC中,要从一个Action跳转到另一个Action,通常是用一系列以“Redirect”开头的方法 Redirect RedirectToAction Redirect ...

  8. ASP.NET MVC程序传值方式:ViewData,ViewBag,TempData和Session

    转载原地址 http://www.cnblogs.com/sunshineground/p/4350216.html 在ASP.NET MVC中,页面间Controller与View之间主要有以下几种 ...

  9. ASP.NET MVC Filter的思考

    思考了一下AOP的具体实现,后来想到ASP.NET MVC过滤器其实就是AOP的一种,于是从Filter下手研究AOP. 暂时先考虑AuthorizationFilter,ActionFilter,R ...

随机推荐

  1. 三星framebuffer驱动代码分析

    一.驱动总体概述 本次的驱动代码是Samsung公司为s5pv210这款SoC编写的framebuffer驱动,对应于s5pv210中的内部外设Display Controller (FIMD)模块. ...

  2. Linux内核模块简介

    一. 摘要 这篇文章主要介绍了Linux内核模块的相关概念,以及简单的模块开发过程.主要从模块开发中的常用指令.内核模块程序的结构.模块使用计数以及模块的编译等角度对内核模块进行介绍.在Linux系统 ...

  3. JSON.parse()和JSON.stringify()(转载)

    parse用于从一个字符串中解析出json对象,如 var str = '{"name":"huangxiaojian","age":&qu ...

  4. 设置TableViewcell标题不悬浮

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat sectionHeaderHeight = 40; if (scrol ...

  5. instancetype、id、NSObject的联系和区别

    1.id和instancetype都能省去具体类型,提高代码的通用性.而NSObject *则没有这种功能. 2.instancetype只能用于方法的返回类型,而id用处和NSObject *类似. ...

  6. win7下安装mysql

    (1)官网下载mysql: http://dev.mysql.com/downloads/mysql/ (2)解压后,进入到该目录下,将my-default.ini文件复制一份改名为my.ini 打开 ...

  7. C#键盘钩子 鼠标钩子

    最新对C#模拟键盘按键,鼠标操作产生了兴趣.特从网上收集了一些常用的API用来调用键盘,鼠标操作. class Win32API { #region DLL导入 /// <summary> ...

  8. python学习之路-day7

    本节内容: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 面向对象高级语法部分 静态方法                             ...

  9. java-GUI图形用户界面

    图形用户界面GUI(Graphical User Interface),指的是在一个程序中用户可以看到的和与之交互的部分. JavaAPI中提供两套组件用于支持编写用户界面AWT  and  Swin ...

  10. 数论(poj 1401)

    题目:Factorial 题意:求N!末尾的0 的数量. 思路:10  = 2 * 5:N!中的2 的数量肯定比 5多:只需寻找5 的数量,暴力寻找TLE: 快点的方法:f(N) = N/5 + f( ...