混合MVC和Web API错误处理

时间:2015-11-17 09:35:05

标签: asp.net-mvc-4 asp.net-web-api error-handling

我们有一个MVC 4网络应用程序,我们使用web.config文件来处理自定义错误。

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="403" />
        <error statusCode="403" responseMode="ExecuteURL" path="/Error/AccessDenied" />
        <remove statusCode="404" />
        <error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
        <remove statusCode="500" />
        <error statusCode="500" responseMode="ExecuteURL" path="/Error/ApplicationError" />
     </httpErrors>
</system.webServer>

所有这些都按预期工作。

我们现在开始使用AngularJSWeb API在此项目中实施一些新功能。在我们的Web API控制器操作中,我们一直返回一个HttpResponseMessage来指示调用的成功/失败。例如:

return Request.CreateResponse(HttpStatusCode.BadRequest, result);

我们遇到的问题(我认为!)原来MVC错误处理正在拦截BadRequest结果(合理),以致HttpResponseMessage结果数据永远不会被返回调用AngularJS方法。

在此混合(MVC/Web API)环境中处理错误的最佳方法是什么,以便Web API HttpResponseMessages不会丢失?

感谢。

1 个答案:

答案 0 :(得分:0)

我不确定我是否找到了最佳解决方案,但最后我从Web.config中删除了httpErrors部分,并在以下帖子的帮助下在Global.asax中构建了自己的错误处理程序:

<强> Global.asax中

public void Application_Error(Object sender, EventArgs e)
{
    var httpContext = ((MvcApplication) sender).Context;
    var currentController = "";
    var currentAction = "";
    var currentRouteData =
        RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

    if (currentRouteData != null)
    {
        if (
            !String.IsNullOrEmpty(
                currentRouteData.Values["controller"]?.ToString()))
        {
            currentController = currentRouteData.Values["controller"].ToString();
        }

        if (!String.IsNullOrEmpty(currentRouteData.Values["action"]?.ToString()))
        {
            currentAction = currentRouteData.Values["action"].ToString();
        }
    }

    var ex = Server.GetLastError();
    var httpEx = ex as HttpException;
    var controller = new ErrorController();
    var routeData = new RouteData();
    var statusCode = httpEx?.GetHttpCode() ?? 500;
    string action;

    switch (statusCode)
    {
        case 400:
            action = "BadRequest";
            break;
        case 403:
            action = "AccessDenied";
            break;
        case 404:
            action = "NotFound";
            break;
        default:
            action = "Index";
            break;
    }

    httpContext.ClearError();
    httpContext.Response.Clear();
    httpContext.Response.StatusCode = statusCode;
    httpContext.Response.TrySkipIisCustomErrors = true;

    if (statusCode >= 500)
    {
        Server.Transfer("/Error/ServerError.html");
        return;
    }

    routeData.Values["controller"] = "Error";
    routeData.Values["action"] = action;
    routeData.Values["statusCode"] = statusCode;

    controller.ViewData.Model = new HandleErrorInfo(ex, currentController,
        currentAction);

    ((IController) controller).Execute(
        new RequestContext(new HttpContextWrapper(httpContext), routeData));
}

我的错误控制器看起来像这样:

[AllowAnonymous]
 public sealed class ErrorController
     : AblController
 {
     public ActionResult Index(int statusCode)
     {
         ViewBag.StatusCode = statusCode;
         return View("Error");
     }


     // HTTP 400 - Bad Request
     public ActionResult BadRequest()
     {
         // Now handled by Global.asax - Application_Error
         // Response.StatusCode = (int) HttpStatusCode.BadRequest;
         // Response.TrySkipIisCustomErrors = true;

         if (Request.IsAjaxRequest())
         {
             return Json(
                 new
                 {
                     error = new ErrorSummary("Bad Request")
                 });
         }

         return View();
     }


     // HTTP 403 - Access Denied
     public ActionResult AccessDenied()
     {
         // Now handled by Global.asax - Application_Error
         // Response.StatusCode = (int) HttpStatusCode.Forbidden;
         // Response.TrySkipIisCustomErrors = true;

         if (Request.IsAjaxRequest())
         {
             return Json(
                 new
                 {
                     error = new ErrorSummary("Access Denied")
                 });
         }

         return View();
     }


     // HTTP 404 - Not Found
     public ActionResult NotFound()
     {
         // Now handled by Global.asax - Application_Error
         // Response.StatusCode = (int) HttpStatusCode.NotFound;
         // Response.TrySkipIisCustomErrors = true;

         if (Request.IsAjaxRequest())
         {
             return Json(
                 new
                 {
                     error = new ErrorSummary("Not Found")
                 });
         }

         return View();
     }
 }

}

我还在Web.config中关闭了自定义错误模式

<customErrors mode="Off" />

此解决方案需要 更多测试 ,但到目前为止,它似乎按预期/按要求执行。