更改单个ASP.NET Core控制器的JSON序列化设置
我有两个控制器控制器:ControllerA
和ControllerB
.每个控制器的基类为Controller
.
I'm having two controller controllers: ControllerA
and ControllerB
. The base class of each controller is Controller
.
ControllerA
需要以默认格式(camelCase)返回JSON. ControllerB
需要以不同的JSON格式返回数据:snake_case.
The ControllerA
needs to return JSON in the default format (camelCase). The ControllerB
needs to return data in a different JSON format: snake_case.
如何在ASP.NET Core 3.x和2.1中实现呢?
How can I implement this in ASP.NET Core 3.x and 2.1?
我已经尝试过startup
:
services
.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new StringEnumConverter());
options.SerializerSettings.ContractResolver = new DefaultContractResolver()
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
})
.AddControllersAsServices();
但这将更改所有控制器的序列化,而不仅仅是ControllerB
.如何为1个控制器配置或注释此功能?
But this will change the serialization for all controllers, not just for ControllerB
. How can I configure or annotate this feature for 1 controller?
您可以结合使用输出格式化程序.这是操作过滤器"外观的示例:
You can achieve this with a combination of an Action Filter and an Output Formatter. Here's an example of what the Action Filter might look like:
public class SnakeCaseAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext ctx)
{
if (ctx.Result is ObjectResult objectResult)
{
objectResult.Formatters.Add(new JsonOutputFormatter(
new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
},
ctx.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>()));
}
}
}
使用OnActionExecuted
,代码将在相应的操作之后运行,并首先检查结果是否为ObjectResult
(由于继承,该结果也适用于OkObjectResult
).如果它是ObjectResult
,则过滤器仅添加
Using OnActionExecuted
, the code runs after the corresponding action and first checks to see if the result is an ObjectResult
(which also applies to OkObjectResult
thanks to inheritance). If it is an ObjectResult
, the filter simply adds a customised version of a JsonOutputFormatter
that will serialise the properties using SnakeCaseNamingStrategy
. The second parameter in the JsonOutputFormatter
constructor is retrieved from the DI container.
要使用此过滤器,只需将其应用于相关的控制器:
In order to use this filter, just apply it to the relevant controller:
[SnakeCase]
public class ControllerB : Controller { }
ASP.NET Core 3.0+的更新
3.0+的情况看起来有些不同,其中3.0+的默认JSON格式器基于System.Text.Json
.在撰写本文时,这些对蛇形命名策略没有内置支持.
Update for ASP.NET Core 3.0+
Things look a little different for 3.0+, where the default JSON-formatters for 3.0+ are based on System.Text.Json
. At the time of writing, these don't have built-in support for a snake-case naming strategy.
但是,如果您将Json.NET与3.0+一起使用(有关详细信息,请参见
However, if you're using Json.NET with 3.0+ (details in the docs), the SnakeCaseAttribute
from above is still viable, with a couple of changes:
-
JsonOutputFormatter
现在是NewtonsoftJsonOutputFormatter
. -
NewtonsoftJsonOutputFormatter
构造函数需要参数MvcOptions
.
-
JsonOutputFormatter
is nowNewtonsoftJsonOutputFormatter
. - The
NewtonsoftJsonOutputFormatter
constructor requires an argument ofMvcOptions
.
代码如下:
public class SnakeCaseAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext ctx)
{
if (ctx.Result is ObjectResult objectResult)
{
objectResult.Formatters.Add(new NewtonsoftJsonOutputFormatter(
new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
},
ctx.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>(),
ctx.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>().Value));
}
}
}
注意:例如,您可能想在某个地方提前创建JsonOutputFormatter
/NewtonsoftJsonOutputFormatter
-在本示例中,我没有走那么远,因为这是手头问题的次要问题.
Note: You might want to create the JsonOutputFormatter
/NewtonsoftJsonOutputFormatter
ahead of time somewhere, for example - I've not gone that far in the example as that's secondary to the question at hand.