更改单个 ASP.NET Core 控制器的 JSON 序列化设置
Posted
技术标签:
【中文标题】更改单个 ASP.NET Core 控制器的 JSON 序列化设置【英文标题】:Change the JSON serialization settings of a single ASP.NET Core controller 【发布时间】:2018-10-02 09:51:14 【问题描述】:我有两个控制器控制器:ControllerA
和 ControllerB
。每个控制器的基类是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 个控制器配置或注释此功能?
【问题讨论】:
【参考方案1】:ASP.NET Core 3.0+
您可以通过Action Filter 和Output 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
仍然可行,但需要进行一些更改:
JsonOutputFormatter
现在是 NewtonsoftJsonOutputFormatter
。
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 Filter 和Output 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
);
【讨论】:
以上是关于更改单个 ASP.NET Core 控制器的 JSON 序列化设置的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 依赖注入单个聚合类而不是多个单独的构造函数注入
如何更改 ASP.NET Core API 中的默认控制器和操作?
在控制器中更改 ASP.NET Core 2.0 标识连接字符串