简体   繁体   English

混合使用MVC和Web API错误处理

[英]Mixing MVC and Web API Error Handling

We have an MVC 4 web application where we use the web.config file to handle custom errors. 我们有一个MVC 4 Web应用程序,我们在其中使用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>

All ,of which works as expected. 所有这些都按预期工作。

We are now beginning to implement some new features in this project using AngularJS and Web API . 现在,我们开始使用AngularJSWeb API在此项目中实现一些新功能。 In our Web API controller actions, we are consistently returning a HttpResponseMessage to indicate success/failure of the call. 在我们的Web API控制器操作中,我们将始终返回HttpResponseMessage来指示调用成功/失败。 For example: 例如:

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

The problem (I think!) we are having is that originally MVC error handling is intercepting the BadRequest result (as is reasonable) so that the HttpResponseMessage result data never gets returned to the calling AngularJS method. 我们遇到的问题(我认为!)是,最初的MVC错误处理正在拦截BadRequest结果(合理),因此HttpResponseMessage结果数据永远不会返回到调用的AngularJS方法。

What is the best way to handle errors in this mixed ( MVC/Web API ) environment so that the Web API HttpResponseMessages are not lost? 在这种混合( MVC/Web API )环境中处理错误的最佳方法是什么,以使Web API HttpResponseMessages不丢失?

Thanks. 谢谢。

I am not sure I have found the best solution, but in the end I removed the httpErrors section from the Web.config and built my own error handler in the Global.asax assisted by the following posts: 我不确定是否找到了最佳的解决方案,但是最后我从Web.config中删除了httpErrors部分,并在以下帖子的帮助下在Global.asax中构建了自己的错误处理程序:

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

My error controller then looked like this: 然后,我的错误控制器如下所示:

[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();
     }
 }

} }

I also turned the custom error mode off in the Web.config 我还关闭了Web.config中的自定义错误模式

<customErrors mode="Off" />

This solution needs more testing , but so far it seems to be performing as expected/as required. 该解决方案需要更多的测试 ,但到目前为止,它似乎正在按预期/要求执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM