首页 > 解决方案 > 更改单个 ASP.NET Core 控制器的 JSON 序列化设置

问题描述

我有两个控制器控制器:ControllerAControllerB. 每个控制器的基类是Controller.

需要以ControllerA默认格式(camelCase)返回 JSON。ControllerB需要以不同的 JSON 格式返回数据:snake_case 。

如何在 ASP.NET Core 3.x 和 2.1 中实现这一点?

我试过了startup

services
    .AddMvc()
    .AddJsonOptions(options =>
    {
        options.SerializerSettings.Converters.Add(new StringEnumConverter());
        options.SerializerSettings.ContractResolver = new DefaultContractResolver()
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
        };
    })
    .AddControllersAsServices();

但这将改变所有控制器的序列化,而不仅仅是ControllerB. 如何为 1 个控制器配置或注释此功能?

标签: c#asp.net-core.net-corejson.netasp.net-core-mvc

解决方案


ASP.NET Core 3.0+

您可以结合使用Action FilterOutput Formatter来实现这一点。

3.0+ 的情况看起来有些不同,其中 3.0+ 的默认 JSON 格式化程序基于System.Text.Json. 在撰写本文时,它们没有对蛇形命名策略的内置支持

但是,如果您使用 3.0+ 的 Json.NET(详细信息在docs中),则SnakeCaseAttribute上面的方法仍然可行,但需要进行一些更改:

  1. JsonOutputFormatter现在是NewtonsoftJsonOutputFormatter
  2. 构造NewtonsoftJsonOutputFormatter函数需要一个参数MvcOptions

这是代码:

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));
        }
    }
}

ASP.NET 核心 2.x

您可以结合使用Action FilterOutput Formatter来实现这一点。下面是动作过滤器的示例:

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,代码在相应的操作之后运行,并首先检查结果是否为 an ObjectResult(这也适用于OkObjectResult由于继承)。如果它是一个ObjectResult,过滤器只需添加一个自定义版本的 a JsonOutputFormatter,它将使用 序列化属性SnakeCaseNamingStrategy。构造函数中的第二个参数JsonOutputFormatter是从 DI 容器中检索的。

要使用此过滤器,只需将其应用于相关控制器:

[SnakeCase]
public class ControllerB : Controller { }

注意:例如,您可能希望在某个地方提前创建JsonOutputFormatter/ NewtonsoftJsonOutputFormatter- 我在示例中没有走那么远,因为这是手头问题的次要问题。


推荐阅读