通过自定义操作过滤器处理 Ajax cal 异常

Handling Ajax cal exceptions via Custom Action Filters

我正在通过自定义操作过滤器为我的 MVC 应用程序实施授权机制。

我已提供以下自定义操作过滤器以供授权:

[AttributeUsageAttribute(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizationFilterAttribute : ActionFilterAttribute
{
    public AuthorizationEntity Entity { get; set; }
    public AuthorizationPermission Permission { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        AuthorizationResult result = null;
        // Base actions (Authentication first)
        base.OnActionExecuting(filterContext);
        BaseController controller = filterContext.Controller as BaseController;
        if (controller != null)
        {   // Base actions (Authorizatioın next)
            User usr = controller.currentUser;
            AuthorizationResult ar = AuthorizationManager.GetAuthorizationResult(this.Entity, this.Permission, usr.UserId, usr.RoleId);
            if (!ar.IsAuthorized)
            {
                throw new UnauthorizedAccessException(ar.Description);
            }
            // Authorized, continue
            return;
        }
    }
}

并且在我的基本控制器中 class 我正在处理 UnauthorizedAccessException 类型的异常并通过以下代码将它们重定向到警告页面

protected override void OnException(ExceptionContext filterContext)
{
    if (filterContext.Exception is UnauthorizedAccessException)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
        {
            Exception ex = filterContext.Exception;

            filterContext.ExceptionHandled = true;
            filterContext.Result = new ViewResult()
            {
                ViewName = "UnauthorizedAccess"
            };
        }
        else
        {
            throw filterContext.Exception;
        }
    }
}

此机制适用于 return ActionResult 的操作。但我也有一些 AJAX 调用,我不想将其重定向到警告页面,而是希望显示警告弹出窗口。这就是我检查请求是否是 Ajax 调用的原因。

我正在使用以下代码进行 Ajax 调用:

$.ajax({
    type: "POST",
    url: "AjaxPostMethodName",
    dataType: "json",
    data:
        {
            postval: [some value here]
        },
    success: function (msg) {
        // Do some good actions here
    },
    error: function (x, t, m, b) {
        // Display error
        alert(m);
    }
})

控制器上的以下方法

public JsonResult AjaxPostMethodName(string postval)
{
    try
    {
       // Some cool stuff here
        return Json(null);
    }
    catch (Exception ex)
    {
        Response.StatusCode = UNAUTHORIZED_ACCESS_HTTP_STATUS_CODE;
        return Json(ex.Message);
    }
}

但是当我未通过授权检查时它直接显示 "Internal Server Error" 消息而不是落入 AjaxPostMethodName 方法的 catch 块并显示正确的消息。

如何让这样的代码显示 filterContext.Exception 而不是静态的“Internal Server Error”消息?

问候。

当您的代码中存在未处理的异常时,将调用您的 OnException 方法。在您的 ajax 方法 AjaxPostMethodName 中,您已将代码放入 try catch blcok。因此,此方法中的任何异常都不会进入您的 OnException 方法。

我刚刚检查了 Response.StatusCode 行为,对我来说它有效。

Index.cshtml

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>


<script type="text/javascript">
    $(document).ready(function () {
        alert('doc ready');
        $.ajax({
            type: "POST",
            url: '@Url.Action("AjaxPostMethodName")',                
            dataType: "json",
            data:
                {
                    test: '10'
                },
            success: function (msg) {
                // Do some good actions here
                alert('success');
                alert(msg);
            },
            error: function (x, t, m, b) {
                // Display error
                alert('error');
            }
        });
    });
</script>

HomeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public JsonResult AjaxPostMethodName(string postval)
        {
            Response.StatusCode = 401;
            return Json("test");
        }

    }
}

当我设置 Response.StatusCode 为 200 时它调用成功,当 401 时它调用错误。

请验证您的代码的其他部分是否不会以某种方式干扰它。

您也可以尝试以下变通方法 - 如果 AjaxPostMethodName 抛出返回的异常 JSON 有一个标志 isValid 和一条消息 errorMessage,那么在您的 ajax 成功方法中您可以只检查 isValid 是否正常并且处理错误。

我终于在另一个 Stack Overflow post (Can I return custom error from JsonResult to jQuery ajax error method?) 中找到了解决方案的答案。我应该使用 JsonExceptionFilterAttribute 如下:

public class JsonExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.StatusCode = 500;
            filterContext.ExceptionHandled = true;

            string msg = filterContext.Exception.Message;
            if (filterContext.Exception.GetType() == Type.GetType("System.UnauthorizedAccessException"))
            {
                msg = "Unauthorized access";
            }

            filterContext.Result = new JsonResult
            {
                Data = new
                {
                    errorMessage = msg
                },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
    }
}