我正在使用
在Global.asax
中,我指定要对我的JSON序列使用SnakeCaseNamingStrategy:
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完全忽略。
答案 0 :(得分:1)
经过大量研究,我指出了ASP.NET Mvc源代码(请参见https://github.com/aspnet和https://github.com/ASP-NET-MVC)在返回成功代码和失败代码方面的一些区别。
这些差异都有一个至关重要的相似性,这使我找到了解决此问题的方法。
在ASP.NET Mvc中,有2种扩展方法可用于创建HttpResponseMessage
查看了这两种方法后,我认为没有发现任何可能导致返回错误代码或引发异常序列化的错误。但是看了BadRequestErrorMessageResult
之后,我发现CreateErrorResponse
和BadRequestErrorMessageResult
使用HttpError
类将其信息传递给序列化器。
由于HttpError
扩展了System.Collections.Generic.Dictionary<string,object>
,因此序列化程序未使用我指定的设置对HttpError
进行序列化,因为在序列化过程中对字典的处理不同。
TL; DR
每当ASP.NET Mvc返回错误时;它将使用HttpError
类,即Dictionary<string, object>
。字典具有单独的序列化设置。
您必须在序列化设置中指定要解析字典关键字:
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)
}
};
}
}