ASP .NET MVC - Filter
1. 直接在 Controller 或者它的子类中重写过滤方法
public class BaseController : Controller { /// <summary> /// Controller > ControllerBase /// </summary> /// <param name="requestContext"></param> protected override void Initialize(RequestContext requestContext) { base.Initialize(requestContext); requestContext.HttpContext.Response.Write("Initialize <br />"); } /// <summary> /// 在进行授权时调用 /// Controller > IAuthenticationFilter /// </summary> /// <param name="filterContext"></param> protected override void OnAuthentication(AuthenticationContext filterContext) { base.OnAuthentication(filterContext); filterContext.HttpContext.Response.Write("OnAuthentication <br />"); } /// <summary> /// 在进行授权时调用 /// Controller > IAuthorizationFilter /// </summary> /// <param name="filterContext"></param> protected override void OnAuthorization(AuthorizationContext filterContext) { base.OnAuthorization(filterContext); filterContext.HttpContext.Response.Write("OnAuthorization <br />"); } /// <summary> /// 在调用操作方法前调用 /// Controller > IActionFilter /// </summary> /// <param name="filterContext"></param> protected override void OnActionExecuting(ActionExecutingContext filterContext) { /****************************************************************************/ // 模型验证 // 在请求控制器绑定模型时就触发 // Api 模型验证失败的话, 直接就返回一个 if (!ModelState.IsValid) { var error = ModelState.Values.Where(d => d.Errors.Any()).FirstOrDefault(); if (error != null) { if (Request.IsAjaxRequest()) { filterContext.Result = Json(Failed(error.Errors[0].ErrorMessage)); } else { ModelState.AddModelError("", error.Errors[0].ErrorMessage); filterContext.Result = View(); } } } /****************************************************************************/ base.OnActionExecuting(filterContext); filterContext.HttpContext.Response.Write("OnActionExecuting <br />"); } // Action /// <summary> /// 在调用操作方法后调用 /// Controller > IActionFilter /// </summary> /// <param name="filterContext"></param> protected override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); filterContext.HttpContext.Response.Write("OnActionExecuted <br />"); } /// <summary> /// 在执行由操作方法返回的操作结果前调用 /// Controller > IResultFilter /// </summary> /// <param name="filterContext"></param> protected override void OnResultExecuting(ResultExecutingContext filterContext) { base.OnResultExecuting(filterContext); filterContext.HttpContext.Response.Write("OnResultExecuting <br />"); } // ActionResult() /// <summary> /// 在执行由操作方法返回的操作结果后调用 /// Controller > IResultFilter /// </summary> /// <param name="filterContext"></param> protected override void OnResultExecuted(ResultExecutedContext filterContext) { base.OnResultExecuted(filterContext); filterContext.HttpContext.Response.Write("OnResultExecuted <br />"); } /// <summary> /// 当操作中发生未经处理的异常时调用 /// Controller > IExceptionFilter /// </summary> /// <param name="filterContext"></param> protected override void OnException(ExceptionContext filterContext) { /*****************************************************************/ // 最好可以生成一个唯一数据, 方便进行查看 var result = Failed("操作失败! 请联系管理员"); var stack = filterContext.Exception.StackTrace; var message = filterContext.Exception.Message; filterContext.Result = Json(result); //当结果为json时,设置异常已处理 filterContext.ExceptionHandled = true; /*****************************************************************/
base.OnException(filterContext); filterContext.HttpContext.Response.Write("OnException <br />"); } }
2. 使用 自定义的 FilterAttribute 特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class MyActionFilterAttribute : FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("hello"); } public void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("world"); } }
之后直接在 Action 头部引用就可以
[MyActionFilter] public ActionResult Index() { return View(); }
3. 可以直接继承自 MVC 框架中的 ActionFilterAttribute
这个方法跟上面的一样, 只是 Mvc 自己实现了过滤器接口而已
public class MyActionFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.Result = new ContentResult { Content = @"抱歉,你不具有当前操作的权限!" }; } public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); } }
例子:
/// <summary> /// 身份验证过滤器 /// 第一位执行 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class ApiAuthorizeAttribute : AuthorizationFilterAttribute { public override void OnAuthorization(HttpActionContext actionContext) { //如果用户方位的Action带有AllowAnonymousAttribute,则不进行授权验证 if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()) { return; } // 获取客户端传回来的 经过编码的 token string tokenBase64 = HttpContext.Current.Request.Headers["Authorization"]; // 如果 token 不存在 说明客户端非法 if (tokenBase64 != null) { // 解码 token var token = SecurityHelper.Base64Decrypt(tokenBase64); // 还原为 user 对象 var user = JsonConvert.DeserializeObject<CurrentUserCookie>(token); // 读取 cache var cache = HttpRuntime.Cache["token_" + user.CurrentUser.UserId.ToString()]; // 对比客户端传过来的和服务器保存的 if (!token.Equals(cache)) { // 不匹配的话 说明 token 遭到过修改 actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, new HttpError("Token 错误")); } HttpContext.Current.User = user; return; } else { // 未登录 actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, new HttpError("未登录")); return; } } } /// <summary> /// Action 过滤器 /// 第二位执行 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class ApiActionAttribute : ActionFilterAttribute { private const string Origin = "Origin"; /// <summary> /// Access-Control-Allow-Origin是HTML5中定义的一种服务器端返回Response header,用来解决资源(比如字体)的跨域权限问题。 /// </summary> private const string AccessControlAllowOrigin = "Access-Control-Allow-Origin"; /// <summary> /// originHeaderdefault的值可以使 URL 或 *,如果是 URL 则只会允许来自该 URL 的请求,* 则允许任何域的请求 /// </summary> private const string originHeaderdefault = "*"; /// <summary> /// 在Action执行之前执行 /// </summary> /// <param name="actionContext"></param> public override void OnActionExecuting(HttpActionContext actionContext) { //If you only want to validate the post request. if (actionContext.Request.Method != HttpMethod.Post) { return; } // 模型验证 var modelState = actionContext.ModelState; // 模型验证 // 在请求控制器绑定模型时就触发 // Api 模型验证失败的话, 直接就返回一个 if (!modelState.IsValid) { var errorMessageList = modelState .Values .Where(d => d.Errors.Any()) .Select(s => s.Errors[0]?.ErrorMessage); var errorMessage = string.Join("\r\n", errorMessageList); actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, errorMessage); } } /// <summary> /// 在Action执行完成之后执行 /// </summary> /// <param name="actionExecutedContext"></param> public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { // 该方法允许api支持跨域调用 // 添加头部 以允许跨域 actionExecutedContext.Response.Headers.Add(AccessControlAllowOrigin, originHeaderdefault); } } /// <summary> /// 错误过滤器 /// 第三位执行 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class ApiExceptionAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext actionExecutedContext) { var stack = actionExecutedContext.Exception.StackTrace; var message = actionExecutedContext.Exception.Message; LogHelper.Error(stack, message); actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError, message); return; } }