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. css3颜色

    镂空字的2种做法

  2. 第八十八天请假 PHP smarty模板 变量调节器,方法和块函数基本书写格式

    变量调节器 : 文件命名格式(modifier.名称.php)  前端调用方式<{变量|名称:参数:参数……}>可组合使用,用|隔开 <?php /* 命名格式 smarty_mod ...

  3. 在本地机器上能访问tomcat,远程机器访问不了的解决方法

    问题描述:在测试服务器上搭建了一个tomcat,在测试服务器上能用ip打开tomcat.我用自己的机器能远程桌面能登录到测试服务器上,但在自己的机器上无法通过ip来访问测试服务器上的tomcat. 解 ...

  4. Tcp之异常

    Tcp异常 昨研发报异常,据CMCC说是我方服务器主动断开的,于是怀疑是超时设置过短,于是我抓包,由于我接触socket时日尚短,搞不清为什么三次握手成功之后我方服务器会立刻发送fin 今天本来做实验 ...

  5. ORACLE服务端详细安装步骤(配图解)

    ORACLE服务端的安装及配置 l 将下载的安装包解压缩,双击[setup.exe]文件,系统检查监听参数,耐心等待,完成后出现如下界面,电子邮件可不填,"我希望..."建议不勾选 ...

  6. 统计学习方法 AdaBoost

    提升方法的基本思路 在概率近似正确(probably approximately correct,PAC)学习的框架中, 一个概念(一个类),如果存在一个多项式的学习算法能够学习它,并且正确率很高,那 ...

  7. 虚拟机VMware新增硬盘无法识别问题

    添加硬盘前的硬盘信息 在虚拟机中新增硬盘 添加后发现使用fdisk -l信息不变,新增的硬盘并没有识别,试过重启虚拟机硬盘就会识别出来.如果不想重启则按照如下方法: 先查看/proc/scsi/scs ...

  8. Spring 4 官方文档学习(十一)Web MVC 框架之异常处理

    1.HandlerExceptionResolver Spring HandlerExceptionResolver的实现们会处理controller执行过程中发送的unexpected except ...

  9. unreal3的坐标系统和vector/rotator

    unreal3的坐标系有点奇葩,属于[z轴向上的左手坐标系]: 1.左手食指指前方,x正向 2.大拇指指上方,z正向 3.中指指右方,y正向 若以我们人头摆正时来参考: 1.目视的是前方,x正向 2. ...

  10. 【erlang】执行linux命令的两种方法

    os.cmd(Cmd) os模块提供了cmd函数可以执行linux系统shell命令(也可以执行windows命令).返回一个Cmd命令的标准输出字符串结果.例如在linux系统中执行os:cmd(& ...