MVC过滤器:自定义操作过滤器
一、操作过滤器
1、定义
操作过滤器用于实现IActionFilter接口以及包装操作方法执行。IActionFilter接口声明两个方法:OnActionExecuting和OnActionExecuted。OnActionExecuting在操作方法之前运行。OnActionExecuted在操作方法之后运行,可以执行其他处理,如向操作方法提供额外数据、检查返回值或取消执行操作方法。
查看ActionFilterAttribute类的定义:
#region 程序集 System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// D:\Practice\MVC\自定义操作过滤器\MVCCustomerActionFilterDemo\packages\Microsoft.AspNet.Mvc.5.2.7\lib\net45\System.Web.Mvc.dll
#endregion namespace System.Web.Mvc
{
//
// 摘要:
// 表示筛选器特性的基类。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
{
//
// 摘要:
// 初始化 System.Web.Mvc.ActionFilterAttribute 类的新实例。
protected ActionFilterAttribute(); //
// 摘要:
// 在执行操作方法后由 ASP.NET MVC 框架调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
public virtual void OnActionExecuted(ActionExecutedContext filterContext);
//
// 摘要:
// 在执行操作方法之前由 ASP.NET MVC 框架调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
public virtual void OnActionExecuting(ActionExecutingContext filterContext);
//
// 摘要:
// 在执行操作结果后由 ASP.NET MVC 框架调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
public virtual void OnResultExecuted(ResultExecutedContext filterContext);
//
// 摘要:
// 在执行操作结果之前由 ASP.NET MVC 框架调用。
//
// 参数:
// filterContext:
// 筛选器上下文。
public virtual void OnResultExecuting(ResultExecutingContext filterContext);
}
}
根据方法的名字就知道4个方法执行的顺序了:
OnActionExecuting是Action执行前的操作、OnActionExecuted则是Action执行后的操作、OnResultExecuting是解析ActionResult前执行、OnResultExecuted是解析ActionResult后执行。
即:Action执行前:OnActionExecuting方法先执行→Action执行 →OnActionExecuted方法执行→OnResultExecuting方法执行→返回的ActionRsult中的 executeResult方法执行→OnResultExecuted执行。
2、案例
2.1、创建自定义操作过滤器
新建一个自定义过滤器,然后重新里面的方法,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCCustomerActionFilterDemo.Extension
{
public class CustomerActionFilter :ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法准备执行");
base.OnActionExecuting(filterContext);
} public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法执行结束");
base.OnActionExecuted(filterContext);
}
}
}
2.2、新建控制器
创建一个控制器,用来测试自定义操作过滤器,代码如下:
using MVCCustomerActionFilterDemo.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCCustomerActionFilterDemo.Controllers
{
public class ActionFiltersController : Controller
{
// GET: ActionFilters
[CustomerActionFilter]
public ActionResult Index()
{
Response.Write("<h2>执行Index...</h2>");
return View();
}
}
}
Index方法对应的视图代码如下:
@{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<h1>操作过滤器测试页面</h1>
</div>
</body>
</html>
运行结果;
二、结果过滤器
1、定义
结果筛选器用于实现IResultFilter接口以及包装ActionResult对象的执行。IResultFilter接口声明两个方法OnResultExecuting和OnResultExecuted。OnResultExecuting在执行ActionResult对象之前运行。OnResultExecuted在结果之后运行,可以对结果执行其他处理,如修改 HTTP 响应。
结果过滤器也是实现了ActionFilterAttribute类。
2、案例
修改CustomerActionFilter类,重写OnResultExecuting和OnResultExecuted,修改后的代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCCustomerActionFilterDemo.Extension
{
public class CustomerActionFilter :ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法准备执行");
base.OnActionExecuting(filterContext);
} public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法执行结束");
base.OnActionExecuted(filterContext);
} public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法执行结束,准备呈现视图");
base.OnResultExecuting(filterContext);
} public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("视图呈现结束");
base.OnResultExecuted(filterContext);
}
}
}
运行结果:
三、案例
1、记录操作
在真实项目中,可以利用操作过滤器记录哪个用户登录系统以后进行了哪些操作。
1.1、创建实体类
新建用于记录信息的实体类。代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace MVCCustomerActionFilterDemo.Models
{
public class LogEntity
{
/// <summary>
/// 控制器名称
/// </summary>
public string ControllerName { get; set; } /// <summary>
/// Action方法名称
/// </summary>
public string ActionName { get; set; } /// <summary>
/// 操作用户id
/// </summary>
public string OperationUserId { get; set; } /// <summary>
/// 操作时间
/// </summary>
public DateTime OperationTime { get; set; }
}
}
1.2、创建日志类
创建日志帮助类,代码如下:
using MVCCustomerActionFilterDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO; namespace MVCCustomerActionFilterDemo.Util
{
public class LogHelper
{
/// <summary>
/// 记录操作日志
/// 这里为了方便测试记录到txt文件里面,实际中应该是记录到数据库中
/// 然后有界面可以显示这些操作记录
/// </summary>
/// <param name="entity"></param>
public static void WriteOperRecore(LogEntity entity)
{
string strPath = @"C:\log.txt";
using (StreamWriter sw = new StreamWriter(strPath, true))
{
sw.WriteLine("**************************");
sw.WriteLine($"操作时间:{entity.OperationTime}");
sw.WriteLine($"当前Controller名称:{entity.ControllerName}");
sw.WriteLine($"当前Action名称:{entity.ActionName}");
sw.WriteLine($"当前操作用户id:{entity.OperationUserId}");
sw.Close();
}
}
}
}
1.3、修改操作过滤器类
修改后的操作过滤器类代码如下:
using MVCCustomerActionFilterDemo.Models;
using MVCCustomerActionFilterDemo.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCCustomerActionFilterDemo.Extension
{
public class CustomerActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法准备执行");
string strControllerName = filterContext.RouteData.Values["controller"].ToString();
string strActionName = filterContext.RouteData.Values["action"].ToString();
LogEntity entity = new LogEntity()
{
OperationTime = DateTime.Now,
ControllerName = strControllerName,
ActionName = strActionName,
// 为了方便测试写admin,真实案例需要获取当前登录的用户
OperationUserId = "admin"
};
// 记录操作记录
LogHelper.WriteOperRecore(entity);
base.OnActionExecuting(filterContext);
} public override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法执行结束");
base.OnActionExecuted(filterContext);
} public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Write("Action方法执行结束,准备呈现视图");
base.OnResultExecuting(filterContext);
} public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Write("视图呈现结束");
base.OnResultExecuted(filterContext);
}
}
}
运行程序,查看生成的日志:
2、实现权限控制功能
可以重写OnActionExecuting方法实现授权过滤器一样的功能,因为OnActionExecuting方法是在Action方法执行前执行的,自定义一个实现ActionFilterAttribute类的CustomerActionPremisFilters类,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVCCustomerActionFilterDemo.DataBase;
using MVCCustomerActionFilterDemo.Models; namespace MVCCustomerActionFilterDemo.Extension
{
public class CustomerActionPremisFilters :ActionFilterAttribute
{
public string ActionName { get; set; } //用于保存Action配置的别名
public string AreaName { get; set; }
public string Roles { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// 如果未登录,则跳转到登录界面
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect("/Account/LogOn");
return;
}
//当前登录用户的用户名
string userName = filterContext.HttpContext.User.Identity.Name;
//当前登录用户对象
User user = SampleData.users.Find(u => u.UserName == userName); if (user != null)
{
//当前登录用户的角色
Role role = SampleData.roles.Find(r => r.Id == user.RoleId); //获得controller:
string controllerName = filterContext.RouteData.Values["controller"].ToString().ToLower();
if (ActionName == null)
{
ActionName = filterContext.RouteData.Values["action"].ToString();
} //查询角色id
RoleWithControllerAction roleWithControllerAction = SampleData.roleWithControllerAndAction.Find(r => r.ControllerName.ToLower() == controllerName && ActionName.ToLower() == ActionName.ToLower());
if (roleWithControllerAction != null)
{
//有权限操作当前控制器和Action的角色id
this.Roles = roleWithControllerAction.RoleIds;
}
if (!string.IsNullOrEmpty(Roles))
{
foreach (string roleid in Roles.Split(','))
{
if (role.Id.ToString() == roleid)
{
//return就说明有权限了,后面的代码就不跑了,直接返回视图给浏览器就好
return;
} }
} filterContext.Result = new ViewResult { ViewName = "Error", };
return;
}
else
{
filterContext.Result = new EmptyResult();
filterContext.HttpContext.Response.Redirect("/Account/Logon", true);
return; }
}
}
}
新建ActionPremisFilters控制器,代码如下:
using MVCCustomerActionFilterDemo.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace MVCCustomerActionFilterDemo.Controllers
{
public class ActionPremisFiltersController : Controller
{
// GET: ActionPremisFilters
[CustomerActionPremisFilters]
public ActionResult Index()
{
return View();
}
}
}
修改SampleData数据,使角色id为2、3的可以访问ActionPremisFilters的Index方法:
using MVCCustomerActionFilterDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace MVCCustomerActionFilterDemo.DataBase
{
/// <summary>
/// 测试数据(实际项目中,这些数据应该从数据库拿)
/// </summary>
public class SampleData
{
public static List<User> users;
public static List<Role> roles;
public static List<RoleWithControllerAction> roleWithControllerAndAction; static SampleData()
{
// 初始化用户
users = new List<User>()
{
new User(){ Id=, UserName="jxl", RoleId=},
new User(){ Id=, UserName ="senior1", RoleId=},
new User(){ Id=, UserName ="senior2", RoleId=},
new User(){ Id=, UserName="junior1", RoleId=},
new User(){ Id=, UserName="junior2", RoleId=},
new User(){ Id=, UserName="junior3", RoleId=}
};
// 初始化角色
roles = new List<Role>()
{
new Role() { Id=, RoleName="管理员", Description="管理员角色"},
new Role() { Id=, RoleName="高级会员", Description="高级会员角色"},
new Role() { Id=, RoleName="初级会员", Description="初级会员角色"}
};
// 初始化角色控制器和Action对应类
roleWithControllerAndAction = new List<RoleWithControllerAction>()
{
new RoleWithControllerAction(){ Id=, ControllerName="AuthFilters", ActionName="AdminUser", RoleIds=""},
new RoleWithControllerAction(){ Id=, ControllerName="AuthFilters", ActionName="SeniorUser",RoleIds="1,2"},
new RoleWithControllerAction(){ Id=, ControllerName="AuthFilters", ActionName="JuniorUser",RoleIds="1,2,3"},
new RoleWithControllerAction(){ Id=, ControllerName="AuthFilters", ActionName="Welcome",RoleIds="1,2"},
new RoleWithControllerAction(){ Id=, ControllerName="ActionFilters", ActionName="Index", RoleIds="2,3"},
// 角色2、3可以访问ActionPremisFilters控制器的Index方法
new RoleWithControllerAction(){ Id=, ControllerName="ActionPremisFilters", ActionName="Index", RoleIds="2,3"}
};
}
}
}
修改配置文件
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880" />
</authentication>
测试,访问ActionPremisFilters的Index方法,由于系统还没有登录,所以会跳转到登录页面,这时候用jxl用户登录:
由于jxl用户没有访问ActionPremisFilters控制器中Index方法的权限,所以会跳转到Error页面:
这时在用senior1用户登录,由于senior1用户有权限访问,所以会显示Index视图内容:
GitHub代码地址:git@github.com:JiangXiaoLiang1988/MVCCustomerActionFilterDemo.git
MVC过滤器:自定义操作过滤器的更多相关文章
- MVC的自定义动作过滤器(一)
感谢好朋友wolfy在园子里的很多有价值的文章,方便了很多朋友,向榜样学习,开始自己的总结之旅:) 遇到问题: 1.http://q.cnblogs.com/q/67382/#a_150210 //添 ...
- 使用ASP.NET MVC操作过滤器记录日志(转)
使用ASP.NET MVC操作过滤器记录日志 原文地址:http://www.singingeels.com/Articles/Logging_with_ASPNET_MVC_Action_Filte ...
- [翻译] 使用ASP.NET MVC操作过滤器记录日志
[翻译] 使用ASP.NET MVC操作过滤器记录日志 原文地址:http://www.singingeels.com/Articles/Logging_with_ASPNET_MVC_Action_ ...
- MVC过滤器:自定义授权过滤器
一.授权过滤器 授权过滤器用于实现IAuthorizationFilter接口和做出关于是否执行操作方法(如执行身份验证或验证请求的属性)的安全策略.AuthorizeAttribute类继承了IAu ...
- MVC之 自定义过滤器(Filter)
MVC之 自定义过滤器(Filter) 一.自定义Filter 自定义Filter需要继承ActionFilterAttribute抽象类,重写其中需要的方法,来看下ActionFilterAttri ...
- Django---MTV和MVC的了解,Django的模版语言变量和逻辑,常见的模板语言过滤器,自定义过滤器,CSRF了解,Django的母版(继承extends,块block,组件include,静态文件的加载load static),自定义simple_tag和inclusion_tag
Django---MTV和MVC的了解,Django的模版语言变量和逻辑,常见的模板语言过滤器,自定义过滤器,CSRF了解,Django的母版(继承extends,块block,组件include,静 ...
- 实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器
MVC开发中几种以AOP方式实现的Filters是非常好用的,默认情况下,我们通过App_Start中的FilterConfig来实现的过滤器注册是全局的,也就是整个应用程序都会使用的,针对单独的Fi ...
- MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器
实现MVC自定义过滤器,自定义Area过滤器,自定义Controller,Action甚至是ViewData过滤器 MVC开发中几种以AOP方式实现的Filters是非常好用的,默认情况下,我们通过A ...
- asp.net mvc 自定义全局过滤器 验证用户是否登录
一般具有用户模块的系统都需要对用户是否登录进行验证,如果用户登录了就可以继续操作,否则退回用户的登录页面 对于这样的需求我们可以通过自定义一个独立的方法来完成验证的操作,但是这样代码的重复率就大大提高 ...
随机推荐
- js中的对象知识总结
文章目录: 1. 比较两个对象是否相等 1. 比较两个对象是否相等 通过===运算符,只有在两个变量指向同一个对象时才返回true,否则返回false.要想比较两个对象中的内容是否相等,需要利用遍历对 ...
- 初步了解JVM第二篇
在一篇<初步了解JVM第一篇>中,我们已经了解了: 类加载器:负责加载*.class文件,将字节码内容加载到内存中.其中类加载器的类型有如下: 启动类加载器(Bootstrap) 扩展类加 ...
- WPF的DataGrid用法-小白向
前几天打算尝试下DataGrid的用法,起初以为应该很简单,可后来被各种使用方法和功能实现所折磨.网络上的解决方法太多,但也太杂.没法子,我只好硬着头皮阅览各种文献资料,然后不断的去尝试,总算小有成果 ...
- DOM事件流的三个阶段
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流. DOM事件流分为三个阶段,分别为: 捕获阶段:事件从Document节点自上而下向目标节点传播的阶段: 目标阶段:真正的目标 ...
- iOS开发 - 超级签名实现之描述文件
简介 因为最近企业签掉得太严重了,上头要求实现超级签进行游戏下载.故有了此文章,记录一下过程. 签名原理其实很简单,超级签名的技术就是使用个人开发者账号,将用户的设备当作开发设备进行应用分发.这也导致 ...
- 计算机组成原理——输入输出(I/O)系统考研题
(一) I/O系统基本概念 (二) 外部设备 1. 输入设备:键盘.鼠标2. 输出设备:显示器.打印机3. 外存储器:硬盘存储器.磁盘阵列.光盘存储器 (三) I/ ...
- 对《Java核心技术卷一》读者的一些建议
<Java核心技术卷一>是唯一可以和<Java编程思想>媲美的一本 Java 入门书.单从技术的角度来看,前者更好一些.但上升到思想层面嘛,自然后者更好,两者的偏重点不同. 思 ...
- java的各种日志框架
本文是作者原创,版权归作者所有.若要转载,请注明出处.文章中若有错误和疏漏之处,还请各位大佬不吝指出,谢谢大家. java日志框架有很多,这篇文章我们来整理一下各大主流的日志框架, 包括log4j ...
- 流式计算(一)-Java8Stream
大约各位看官君多少也听说了Storm/Spark/Flink,这些都是大数据流式处理框架.如果一条手机组装流水线上不同的人做不同的事,有的装电池,有的装屏幕,直到最后完成,这就是典型的流式处理.如果手 ...
- Python-xlwt库的基本使用
安装xlwt库 pip install xlwt 基本使用 ①创建工作簿 wa = xlwt.Workbook() ②添加工作表 添加“class”工作表 b = wa.add_sheet('clas ...