MVC Filter 实现方式和作用范围控制
Asp.Net MVC Filter 实现方式和作用范围控制
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总是离不开接口)
2.实现一个自定义Filter
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
在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
MVC Filter 实现方式和作用范围控制的更多相关文章
- Asp.Net MVC Filter 实现方式和作用范围控制
MVC中的Filte 简单又优雅的实现了AOP ,在日志,权限,缓存和异常处理等方面用的比较多.但本文不是讨论Filter这些功能点,而是总结Filter实现的方式.说实现也不太准确,也就是它的呈现方 ...
- 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, ...
- asp.net mvc各种传值方式大全
MVC 各种传值方式 ViewData传值. HomeController.cs Co de: public ActionResult Index(){ ViewData["Ti ...
- MVC下载文件方式
MVC下载文件方式 http://www.cnblogs.com/liang--liang/archive/2012/10/20/2732745.html 方式一: public FileStream ...
- 学习之-ASP.NET MVC Filter
MVC Filter 是典型的AOP应用,对MVC框架处理客户端请求注入额外的一些逻辑,如日志记录.缓存处理.异常处理和权限验证,性能检测(横切关注点),而这些逻辑通常与主要业务无关,被独立分开作为公 ...
- Shiro入门之二 --------基于注解方式的权限控制与Ehcache缓存
一 基于注解方式的权限控制 首先, 在spring配置文件applicationContext.xml中配置自动代理和切面 <!-- 8配置自动代理 --> <bean cl ...
- .NET MVC 学习笔记(七)— 控制input控件
.NET MVC 学习笔记(七)— 控制input控件 画面中有时候需要输入数字,这时就需要控制input的输入.以下为保留两位有效数字. /* * 初始化数字输入 */ function initD ...
- 013——VUE中多种方式使用VUE控制style样式属性
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- MVC下载文件方式 包括网络地址文件
MVC下载文件方式 方式一: public FileStreamResult DownFile(string filePath, string fileName){ string absol ...
随机推荐
- SQL Server 2012 复制(发布订阅的研究)
原文:SQL Server 2012 复制(发布订阅的研究) 已实现发布订阅功能,可以实现局域网内双击备份. 一.注意事项: a) 使用[事务复制]功能 b) 必须是相同的SqlServer 帐号和密 ...
- 关于接收POST请求 $GLOBALS['HTTP_RAW_POST_DATA']
总是产生变量包含有原始的 POST 数据.否则,此变量仅在碰到未识别 MIME 类型的数据时产生.不过,访问原始 POST 数据的更好方法是 php://input.$HTTP_RAW_POST_DA ...
- [置顶] 纯手工打造漂亮的瀑布流,五大插件一个都不少Bootstrap+jQuery+Masonry+imagesLoaded+Lightbox!
前两天写的文章<纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身!>受到很多网友的喜爱,今天特别推出姊妹篇<纯手工打造漂亮的瀑 ...
- 第8章 装饰模式(Decorator Pattern)
原文 第8章 装饰模式(Decorator Pattern) 概述: 装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. ...
- Atitit.软体guibuttonand面板---通信子系统(范围)-- github 采用....
Atitit.软体guibuttonand面板---通讯子系统(区)-- github 的使用.... 1. 1.注冊账户以及创建仓库 1 2. 二.在GitHub中创建项目(create a new ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(12)-实现用户异步登录和T4模板
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(12)-实现用户异步登录和T4模板 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 ...
- Mac OS下SVN的使用:服务的和客户端
在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境.在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还 ...
- MVC验证11-对复杂类型使用jQuery异步验证
原文:MVC验证11-对复杂类型使用jQuery异步验证 本篇体验使用"jQuery结合Html.BeginForm()"对复杂类型属性进行异步验证.与本篇相关的"兄弟篇 ...
- VS2013中实现angular代码智能提示
第一步:在项目同添加angular js文件的引用: 这里使用NuGet包管理器来给项目添加angular js install-package angularjs 第二步:添加智能提示js文件 我们 ...
- C# .NET ASP.NET 其中关系你了解多少
有些人一直在做这方面..但突然有人来问你这些问题..估计有很多答不上来. 1..NET是一个平台,一个抽象的平台的概念. .NET平台其本身实现的方式其实还是库,抽象层面上来看是一个平台. 个人理解. ...