1

我有一个 MVC 2 应用程序,我希望所有请求都返回 json。我已经覆盖了 aHandleErrorAttribute和 a AuthorizeAttribute。我的目标是所有错误(甚至 403 和 404)都作为 json 返回。

这是我的错误处理程序。 ExceptionModel是一个简单的类,定义了我的应用程序返回的任何错误。异常处理程序是将错误详细信息转换为格式化的电子邮件并将其发送给我的类。

public class HandleErrorJsonAttribute : System.Web.Mvc.HandleErrorAttribute
{
    public override void OnException(ExceptionContext context)
    {
        context.ExceptionHandled = true;

        RaiseErrorSignal(context.Exception);

        context.RequestContext.HttpContext.Response.ContentType = "application/json";

        JsonSerializer serializer = new JsonSerializer();
        serializer.Serialize(context.HttpContext.Response.Output, new ExceptionModel(context.Exception));
    }

    private static void RaiseErrorSignal(Exception ex)
    {
        IExceptionHandler handler = Resolve();

        handler.HandleError(ex.GetBaseException());
    }

    private static IExceptionHandler Resolve()
    {
        return ServiceLocator.Locate<IExceptionHandler>();
    }
}

这是澄清的异常模型

public class ExceptionModel
{
    public int ErrorCode { get; set; }
    public string Message { get; set; }

    public ExceptionModel() : this(null)
    {

    }

    public ExceptionModel(Exception exception)
    {
        ErrorCode = 500;
        Message = "An unknown error ocurred";

        if (exception != null)
        {
            if (exception is HttpException)
                ErrorCode = ((HttpException)exception).GetHttpCode();

            Message = exception.Message;
        }
    }

    public ExceptionModel(int errorCode, string message)
    {
        ErrorCode = errorCode;
        Message = message;
    }
}

最后,我的自定义授权属性。我使用表单身份验证,但我不想要任何自动重定向。我只是希望错误显示在屏幕上并停止任何进一步的处理。

public class AuthorizeTokenAttribute : System.Web.Mvc.AuthorizeAttribute
{
    public bool SuperAdminOnly { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        bool authorized = base.AuthorizeCore(httpContext);

        if(!SuperAdminOnly)
            return authorized;

        if(!authorized)
            return authorized;

        return SessionHelper.UserIsSuperAdmin(httpContext.User.Identity.Name);
    }

    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        throw new HttpException(403, "Access Denied");
    }
}

这一切都适用于大多数错误,但它缺少一件事。我有一个这样的控制器动作。

[AuthorizeToken]
[HttpPost]
public JsonResult MyAction()
{
    return new JsonResult();
}

当您通过帖子提交时它工作正常,但在获取时我收到未处理的 404 错误。

“/”应用程序中的服务器错误。

无法找到该资源。

说明:HTTP 404。您要查找的资源(或其依赖项之一)可能已被删除、名称已更改或暂时不可用。请查看以下 URL 并确保其拼写正确。

请求的 URL:/MyController/MyAction

版本信息:Microsoft .NET Framework 版本:4.0.30319;ASP.NET 版本:4.0.30319.1

这发生在 GET 上,这是预期的默认行为。但是,我该如何处理这种情况,以便我可以像这样返回 json

{"ErrorCode":404,"Message":"Page Not Found"}
4

1 回答 1

2

为了亲自处理错误,我更喜欢Application_ErrorGlobal.asax 中的事件:

protected void Application_Error(object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    Response.Clear();
    Server.ClearError();

    var httpException = exception as HttpException;
    var routeData = new RouteData();
    routeData.Values["controller"] = "Errors";
    routeData.Values["action"] = "Index";
    routeData.Values["error"] = exception;

    IController errorController = new ErrorsController();
    errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}

然后有一个ErrorsController:

public class ErrorsController : Controller
{
    public ActionResult Index(Exception exception)
    {
        var errorCode = 500;
        var httpException = exception as HttpException;
        if (httpException != null)
        {
            errorCode = httpException.ErrorCode;
        }

        return Json(new
        {
            ErrorCode = errorCode,
            Message = exception.Message
        }, JsonRequestBehavior.AllowGet);
    }
}
于 2011-02-21T20:15:07.490 回答