您的位置:首页 > 编程语言 > ASP

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

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

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>();
}
}


View Code
在Global中加人

protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
DependencyResolver.SetResolver(new NinjectDependencyResolver());

FilterProviders.Providers.Insert(0,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 = -1;
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, 1, (c, a) => a.ActionName == "Index"));//所有控制器的Action方法会触发Logfilter
FilterProviders.Providers.Add(customFilterProvider);

RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}


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

参考:Pro Asp.Net MVC3 FrameWork
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: