需求
【需求】客户就要求 API
的返回值属性名必须是 PascalCase
(如UserName
),但是这些 API 需要同时提供给内部系统使用,默认都是 CamelCase
(如 userName
)。
【分析】返回的都是 JSON
格式,只是写入属性名的大小写不一样。
问题
在 ASP.NET Core 3.0
或更高版本中,默认 JSON
格式化程序基于 System.Text.Json
,可以配置 Microsoft.AspNetCore.Mvc.JsonOptions.JsonSerializerOptions
实现自定义功能。
比如,设置返回值属性名是 PascalCase
格式:
1
2
3
4
5
6
|
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddJsonOptions(options =>
options.JsonSerializerOptions.PropertyNamingPolicy = null);
}
|
但是,这种只能实现固定设置,不能满足不同请求返回不同格式的需求。
这时,我们可以利用 Newtonsoft.Json
实现更灵活的配置。
添加 Newtonsoft.Json 支持
引用 nuget
包Microsoft.AspNetCore.Mvc.NewtonsoftJson
,并修改 Startup.cs
,代码如下:
1
2
3
4
5
6
7
8
9
|
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new MyCustomContractResolver();
});
}
|
使用自定义类 MyCustomContractResolver
格式化 JSON
。
MyCustomContractResolver 实现
MyCustomContractResolver
实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class MyCustomContractResolver : DefaultContractResolver
{
private CamelCaseNamingStrategy _camelCase = new CamelCaseNamingStrategy();
public override JsonContract ResolveContract(Type type)
{
return CreateContract(type);
}
protected override string ResolvePropertyName(string propertyName)
{
if (GetFormat() == "json2")
{
return propertyName;
}
return _camelCase.GetPropertyName(propertyName, false);
}
private string GetFormat()
{
Microsoft.Extensions.Primitives.StringValues headerValues;
if (AppContext.Current.Request.Headers.TryGetValue("x-format", out headerValues))
{
return headerValues.FirstOrDefault();
}
return "json";
}
}
|
-
默认的 ResolveContract
缓存了指定类型的格式化设置,以加快运行速度,不能满足不同请求对同一类型执行不同的格式化要求。因此,为演示方便,这里去掉了缓存,也可以实现自定义缓存
-
GetFormat
是判断当前请求格式化方式的自定义方法。为演示方便,这里判断的是 x-format Header
,你也可以改成其他方式,比如根据当前用户凭证进行判断
-
AppContext.Current
是对当前请求的 HttpContext
的封装
结论
尝试发送请求,运行效果如下图:
使用 x-format Header
:

不使用 x-format Header
:

完全满足了要求,只需要客户在每个 API 请求加上 x-format Header
即可。