Asp.net web api MVC6WebAPI返回html错误页,而不是异常对象的json版本

Asp.net web api MVC6WebAPI返回html错误页,而不是异常对象的json版本,asp.net-web-api,asp.net-core-mvc,Asp.net Web Api,Asp.net Core Mvc,我正在调用MVC 6 WebAPI中的api端点: POST http://localhost:57287/mytestapi/testentity/ HTTP/1.1 Accept: application/json X-APIKey: 00000000-0000-0000-0000-000000000000 Content-Type: application/json; charset=utf-8 Host: localhost:57287 Content-Length: 1837 Expe

我正在调用MVC 6 WebAPI中的api端点:

POST http://localhost:57287/mytestapi/testentity/ HTTP/1.1
Accept: application/json
X-APIKey: 00000000-0000-0000-0000-000000000000
Content-Type: application/json; charset=utf-8
Host: localhost:57287
Content-Length: 1837
Expect: 100-continue
Connection: Keep-Alive
在正文中,我有json序列化的测试实体

我的实体控制器代码中有一个bug,api返回500响应“服务器错误”,我知道这个bug是什么,但我需要一些帮助的问题是,api返回的是HTML而不是json序列化的异常对象-json是我所期望的:旧webapi将返回json。我已经移植了一个旧的测试项目的代码,我知道它是有效的

那么为什么MVC6WebAPI返回html而不是json呢?我需要进行一些配置吗

编辑: 我按照@danludwig的建议在标题中添加了Accept:application/json,但是这并没有解决问题,我仍然返回了一个html错误页面

我查看了StartUp.cs,发现:

if (env.IsDevelopment())
{
    //app.UseBrowserLink();
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
}
在ConfigureApp方法中。我使用app.usedeveloperceptionpage()进行了测试;评论说。这阻止了返回api响应正文中的html错误页,但是我仍然没有得到json序列化异常对象。

使用时配置的不包括对json的任何支持。它只会返回错误html页面。使用时也可以这样说

据我所知,您需要添加一些代码来处理错误并返回json

  • 一个选项是使用异常过滤器,并将其全局添加或添加到选定的控制器上,尽管此方法仅涵盖来自控制器操作方法的异常。例如,只有当请求接受为application/json时,以下过滤器才会返回一个json对象(否则它会让异常通过,例如可以由全局错误页面处理):

  • 另一个选项是使用
    app.UseExceptionHandler
    重载添加您自己的异常处理程序中间件,该重载允许您指定将处理异常的替代管道的行为。我使用内联中间件快速编写了一个类似的示例,该中间件仅在请求accept为application/json时才会返回json对象:

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");            
    }
    
    app.UseExceptionHandler(appBuilder =>
    {
        appBuilder.Use(async (context, next) =>
        {
            var excHandler = context.Features.Get<IExceptionHandlerFeature>();                    
            if (context.Request.GetTypedHeaders().Accept.Any(header => header.MediaType == "application/json"))
            {
                var jsonString = string.Format("{{\"error\":\"{0}\"}}", excHandler.Error.Message);
                context.Response.ContentType = new MediaTypeHeaderValue("application/json").ToString();
                await context.Response.WriteAsync(jsonString, Encoding.UTF8);
            }
            else
            {                        
                //I haven't figured out a better way of signally ExceptionHandlerMiddleware that we can't handle the exception
                //But this will do the trick of letting the other error handlers to intervene
                //as the ExceptionHandlerMiddleware class will swallow this exception and rethrow the original one
                throw excHandler.Error;
            }
        });
    });
    
    if(env.IsDevelopment())
    {
    app.UseDeveloperExceptionPage();
    }
    其他的
    {
    app.UseExceptionHandler(“/Home/Error”);
    }
    app.UseExceptionHandler(appBuilder=>
    {
    使用(异步(上下文,下一步)=>
    {
    var exchHandler=context.Features.Get();
    if(context.Request.GetTypedHeaders().Accept.Any(header=>header.MediaType==“application/json”))
    {
    var jsonString=string.Format(“{{\”error\”:\“{0}\”}>,excHandler.error.Message);
    context.Response.ContentType=新的MediaTypeHeaderValue(“应用程序/json”).ToString();
    wait context.Response.WriteAsync(jsonString,Encoding.UTF8);
    }
    其他的
    {                        
    //我还没有找到一种更好的方法来处理我们无法处理的异常
    //但这样做可以让其他错误处理程序介入
    //因为ExceptionHandlerMiddleware类将吞并此异常并重新调用原始异常
    抛出exchHandler.Error;
    }
    });
    });
    
这两种方法都允许您使用其他错误处理程序,这些错误处理程序可能会为非json请求提供html页面(另一种方法是从自定义错误处理程序返回json或html页面)


如果使用第二种方法,您很可能希望将该逻辑放入自己的中间件类中,并使用不同的方法生成json响应。在这种情况下,请看一下什么是

我发现了一种廉价的方法,通过将此添加到Startup Configure方法来获得我想要的:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        // Simple error page to avoid a repo dependency.
        app.Use(async (context, next) =>
        {
            try
            {
                await next();
            }
            catch (Exception ex)
            {
                if (context.Response.HasStarted)
                {
                    throw;
                }
                context.Response.StatusCode = 500;
                context.Response.ContentType = "application/json";
                var json = JToken.FromObject(ex);
                await context.Response.WriteAsync(json.ToString());
            }
        });
 //Rest of configure method omitted for brevity.
}

Accept:application/json
不幸的是没有。谢谢,我已经编辑了这个问题以显示新的标题。您的代码是否删除了
JsonOutputFormatter
?否,我在对测试控制器get endpoint的有效调用中返回了json。只是不适用于错误消息。这是一个很好的答案。我已经利用了它,它对于我在控制器级别抛出的异常非常有效。然而,在asp核心异常处理中似乎有一个更深层次的问题。我忘了为循环引用对象配置json格式化程序,IActionResult由控制器返回,但在asp核心内,当生成响应时,json格式化程序抛出异常,客户端得到502错误网关响应!最好是获取json序列化异常对象。坏网关在这里毫无意义。你看到这个了吗?解决方法?因此控制器返回一个json结果(还没有异常),当处理该结果时会导致异常。我猜第一种方法不会捕捉到这个,您是否检查过第二种方法是否在这个场景中执行?顺便说一下,当我在内联中间件中手动格式化json时犯了一个愚蠢的错误,我确实看到了502。不知道为什么框架会将它们视为502!我还没有测试场景2,但很快就会测试。真的是502把我吓坏了。如果我们有这样的东西就好了:app.UseJsonExceptionResponses();希望我能在接下来的几天里看看场景2。第二种方法基本上是
app.UseJsonExceptionResponses()
,而不创建扩展方法和中间件类:)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        // Simple error page to avoid a repo dependency.
        app.Use(async (context, next) =>
        {
            try
            {
                await next();
            }
            catch (Exception ex)
            {
                if (context.Response.HasStarted)
                {
                    throw;
                }
                context.Response.StatusCode = 500;
                context.Response.ContentType = "application/json";
                var json = JToken.FromObject(ex);
                await context.Response.WriteAsync(json.ToString());
            }
        });
 //Rest of configure method omitted for brevity.
}