c# - C# ASP.NET 错误响应不使用 GlobalConfiguration.Configuration.Formatters 设置
问题描述
我在用
- .NET 框架 4.6.1
- Microsoft.AspNet.WebApi 5.2.4
- ASP.NET 使用 Newtonsoft.Json 11.0.2
在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.DefaultSettings
,Global.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 完全忽略了。
解决方案
经过相当多的研究,我指出了 ASP.NET Mvc 源代码(参见https://github.com/aspnet和https://github.com/ASP-NET-MVC)关于返回成功代码和失败代码的一些差异。
这些差异都有一个重要的相似之处,这让我找到了解决这个问题的方法。
解释
HttpResponseMessage
在 ASP.NET Mvc中有 2 种扩展方法用于创建
在查看了这两种方法之后,我认为我没有看到任何可能导致返回错误代码或引发异常序列化错误的东西。但是在查看之后BadRequestErrorMessageResult
,我发现CreateErrorResponse
并BadRequestErrorMessageResult
使用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)
}
};
}
}
推荐阅读
- python - Cookiecutter-bonobo 初始化失败
- apache-flex - SDK Flex 3.4.0.9271A,Adobe Flex 122MB
- c# - 无法从 autobuggi.models.carcategory 转换为 autobuggi.repository.autobuggi.carcategory
- c# - 我是否需要使用 EntityFramework 更新一对多关系中的两个实体?
- ruby-on-rails - Postgres unique contraint ignores null values but Rails passes
- zipkin - 在 Zipkin 中命名一个外部依赖项以绘制它
- android - Android Profiling 对所选进程不可用,但已启用高级分析
- javascript - SAILS JS 中的自反关联是如何工作的?
- python - 为什么 df.sample 和 df.apply 在这种情况下工作方式不同?
- android - Windows 10 与 Android 外围设备配对