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

时间:2015-01-08 08:40:10

标签: asp.net-mvc json exception-handling custom-action-filter

我正在通过自定义操作过滤器为我的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;
        }
    }
}

在我的Base Controller类中,我正在处理 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;
        }
    }
}

此机制适用于返回 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);
    }
})

在Controller

上转到以下方法
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);
    }
}

但是当我未通过授权检查时,它会直接显示"内部服务器错误"消息而不是落入 AjaxPostMethodName 方法的catch块并显示正确的消息。

如何使此类代码显示 filterContext.Exception 而不是静态" 内部服务器错误"消息?

问候。

3 个答案:

答案 0 :(得分:1)

我终于在另一个Stack Overflow帖子(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
            };
        }
    }
}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我刚刚检查了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调用error时。

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

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