首页 > 解决方案 > C# ASP.NET 错误响应不使用 GlobalConfiguration.Configuration.Formatters 设置

问题描述

我在用

Global.asax我指定我想使用 SnakeCaseNamingStrategy 进行 JSON 序列化:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        var formatters = GlobalConfiguration.Configuration.Formatters;

        // Remove the xmlformatter
        formatters.Remove(formatters.XmlFormatter);

        // Ignore reference loops
        formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
            = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

        // Use snake_case
        formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver()
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
        };
    }
}

这在返回OK和大多数其他成功指示状态代码(200-300)时效果很好:

[HttpGet, Route("api/Test")]
public IHttpActionResult Test()
{
    return Ok(new { Message = "Hello World!" });
}

回报:

{
    "message": "Hello World!"
}

但是,当返回任何错误代码或异常时,ASP.NET 似乎会忽略任何格式化程序设置:

[HttpGet, Route("api/Test")]
public IHttpActionResult Test()
{
    return BadRequest("Hello World!");
}

回报:

{
    "Message": "Hello World!" // 'Message' is not snake_case
}

[HttpGet, Route("api/Test")]
public IHttpActionResult Test()
{
    var runtimeErroredArray = new int [2];
    runtimeErroredArray[2] = 5; // runtime error
    return Ok();
}

回报:

{
    "Message": "An error has occurred.",
    "ExceptionMessage": "Index was outside the bounds of the array.", // Should be 'exception_message'
    "ExceptionType": "System.IndexOutOfRangeException", // "System.IndexOutOfRangeException" can stay the same obviously, but 'ExceptionType' should be 'exception_type'
    "StackTrace": "---"
}

我不明白为什么会发生这种情况,但我主要想知道如何解决它。

问题:

有没有一种方法可以强制异常消息和错误代码消息遵循GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver我在Global.asax(使用SnakeCaseNamingStrategy)中设置的?

编辑:

我尝试过设置JsonConvert.DefaultSettingsGlobal.asax但这似乎被忽略了,即使Ok现在返回响应也是如此。

新代码Global.asax

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        // Overwrite the default settings
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
        {
            // Ignore reference loops
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            // Use snake_case
            ContractResolver = new DefaultContractResolver()
            {
                NamingStrategy = new SnakeCaseNamingStrategy()
            }
        };
    }
}

return Ok(new { Message = "Hello World!" });(如在第一个示例中)Test现在在行动中返回:

{
    "Message": "Hello World!"
}

JsonConvert.DefaultSettings似乎被 ASP.NET 完全忽略了。

标签: c#asp.netasp.net-web-api

解决方案


经过相当多的研究,我指出了 ASP.NET Mvc 源代码(参见https://github.com/aspnethttps://github.com/ASP-NET-MVC)关于返回成功代码和失败代码的一些差异。

这些差异都有一个重要的相似之处,这让我找到了解决这个问题的方法。

解释

HttpResponseMessage在 ASP.NET Mvc中有 2 种扩展方法用于创建

在查看了这两种方法之后,我认为我没有看到任何可能导致返回错误代码或引发异常序列化错误的东西。但是在查看之后BadRequestErrorMessageResult,我发现CreateErrorResponseBadRequestErrorMessageResult使用HttpError该类将它们的信息传递给序列化程序。

由于HttpError扩展System.Collections.Generic.Dictionary<string,object>序列化程序没有HttpError使用我指定的设置进行序列化,因为在序列化过程中字典的处理方式不同。

TL;博士

每当 ASP.NET Mvc 返回错误时;它将使用HttpError类,这是一个Dictionary<string, object>. 字典有单独的序列化设置。

答案

您必须在序列化设置中指定要解析 Dictionary 键:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // ...

        var formatters = GlobalConfiguration.Configuration.Formatters;

        // Remove the xmlformatter
        formatters.Remove(formatters.XmlFormatter);

        // Ignore reference loops
        formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
            = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

        // Use snake_case
        formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver()
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
            {
                ProcessDictionaryKeys = true // <--- Use SnakeCaseNamingStrategy for Dictionaries (So HttpError's)
            }
        };
    }
}

推荐阅读