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

 

posted @ 2016-07-19 09:21  `Laimic  阅读(149)  评论(0)    收藏  举报