【问题标题】:Change the JSON serialization settings of a single ASP.NET Core controller更改单个 ASP.NET Core 控制器的 JSON 序列化设置
【发布时间】:2018-10-02 09:51:14
【问题描述】:

我有两个控制器控制器: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-core json.net asp.net-core-mvc


    【解决方案1】:

    ASP.NET Core 3.0+

    您可以通过Action FilterOutput Formatter 的组合来实现此目的。

    3.0+ 的情况看起来有些不同,其中 3.0+ 的默认 JSON 格式化程序基于 System.Text.Json。在撰写本文时,这些don't have built-in support for a snake-case naming strategy

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

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

    [SnakeCase]
    public class ControllerB : Controller { }
    

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

    【讨论】:

      【解决方案2】:

      最终创建了我在端点上使用的这个方法:

      {           
          // needed to get the same date and property formatting 
          // as the Search Service:
          var settings = new JsonSerializerSettings
          {
              ContractResolver = new DefaultContractResolver()
              {
                  NamingStrategy = new SnakeCaseNamingStrategy()
              },
              DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffZ"
          };
      
          return Json(result, settings);
      }
      

      【讨论】:

        【解决方案3】:

        不需要操作过滤器等​​。只需在控制器中覆盖 Json() 即可。

        public class MyController : Controller
        {
            public override JsonResult Json(object data)
            {
                return base.Json(data, new JsonSerializerSettings {
                    // set whataever default options you want
                });
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2022-06-30
          • 1970-01-01
          • 1970-01-01
          • 2020-11-18
          • 2017-12-03
          • 2019-10-01
          • 2022-02-18
          • 2020-03-25
          • 1970-01-01
          相关资源
          最近更新 更多