我设法使用以下代码使其工作:
.AddNewtonsoftJson(options => {
options.SerializerSettings.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
});
但是,这使得MVC使用Newtonsoft
而不是System.Text.JSON
,它是更快,异步且内置的。
看看System.Text.JSON
中的命名策略选项,我只能找到CamelCase。蛇案有本地支持吗?实现蛇案JSON命名风格的更好方法是什么?
答案 0 :(得分:2)
目前尚不支持蛇案,
但.NET Core 3.0
允许通过继承JsonNamingPolicy
来建立自定义命名策略。
您需要通过蛇形转换实现ConvertName
方法。
(Newtonsoft Json.NET有一个内部StringUtils
类,显示了如何处理此问题。)
下面的POC实现仅将Json.NET的SnakeCaseNamingStrategy
用于蛇格转换(,而整个应用程序都使用System.Text.Json
)。
最好避免仅对蛇格转换依赖Newtonsoft Json.Net,但是在下面的这个LAZY示例中,我不想重新思考/重新发明蛇格转换方法。
这个答案的重点是如何挂钩自定义策略(而不是蛇格转换本身)。 (有很多库和code samples都显示了如何做到这一点。)< / em>
public class SnakeCaseNamingPolicy : JsonNamingPolicy
{
private readonly SnakeCaseNamingStrategy _newtonsoftSnakeCaseNamingStrategy
= new SnakeCaseNamingStrategy();
public static SnakeCaseNamingPolicy Instance { get; } = new SnakeCaseNamingPolicy();
public override string ConvertName(string name)
{
/* A conversion to snake case implementation goes here. */
return _newtonsoftSnakeCaseNamingStrategy.GetPropertyName(name, false);
}
}
在Startup.cs
中,您将应用此自定义SnakeCaseNamingPolicy
。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddJsonOptions(
options => {
options.JsonSerializerOptions.PropertyNamingPolicy =
SnakeCaseNamingPolicy.Instance;
});
}
下面的类的一个实例
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureCelcius { get; set; }
public int TemperatureFahrenheit { get; set; }
[JsonPropertyName("Description")]
public string Summary { get; set; }
}
的Json
表示为:
{ "date" : "2019-10-28T01:00:56.6498885+01:00",
"temperature_celcius" : 48,
"temperature_fahrenheit" : 118,
"Description" : "Cool"
}
请注意,属性Summary
的名称为Description
,
与其System.Text.Json.Serialization.JsonPropertyNameAttribute
匹配。
答案 1 :(得分:1)
我在这里分享@pfx解决方案的完整实现。自定义命名策略(从NewtonSoft复制):
@Module
在简单的示例中使用以下模型:
@Module(includes = XXXModule)
示例用法:
using System.Text;
using System.Text.Json;
namespace Utils
{
public class SnakeCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name) => JsonUtils.ToSnakeCase(name);
}
public class JsonUtils
{
private enum SeparatedCaseState
{
Start,
Lower,
Upper,
NewWord
}
public static string ToSnakeCase(string s) => ToSeparatedCase(s, '_');
private static string ToSeparatedCase(string s, char separator)
{
if (string.IsNullOrEmpty(s))
{
return s;
}
StringBuilder sb = new StringBuilder();
SeparatedCaseState state = SeparatedCaseState.Start;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == ' ')
{
if (state != SeparatedCaseState.Start)
{
state = SeparatedCaseState.NewWord;
}
}
else if (char.IsUpper(s[i]))
{
switch (state)
{
case SeparatedCaseState.Upper:
bool hasNext = (i + 1 < s.Length);
if (i > 0 && hasNext)
{
char nextChar = s[i + 1];
if (!char.IsUpper(nextChar) && nextChar != separator)
{
sb.Append(separator);
}
}
break;
case SeparatedCaseState.Lower:
case SeparatedCaseState.NewWord:
sb.Append(separator);
break;
}
char c;
c = char.ToLowerInvariant(s[i]);
sb.Append(c);
state = SeparatedCaseState.Upper;
}
else if (s[i] == separator)
{
sb.Append(separator);
state = SeparatedCaseState.Start;
}
else
{
if (state == SeparatedCaseState.NewWord)
{
sb.Append(separator);
}
sb.Append(s[i]);
state = SeparatedCaseState.Lower;
}
}
return sb.ToString();
}
}
}
给予 public class TestSerializer
{
public DateTime TimeStamp { get; set; }
public int CPUPower { get; set; }
}
答案 2 :(得分:1)
在这里您可以找到很好的解释以及性能比较。 希望性能比较能够解决您的“ 什么是更好的实现方式”部分的问题。
https://www.michaelrose.dev/system-text-json-snakecase
注意:在Microsoft于 2019年9月前后,这是一个较旧的解决方案 没有开始调查它。现在他们已经在处理它,但是还没有将其解决方案发布到最新版本。但是,您可以访问下面的链接,以查看DotNet官方git repo的代码(可能是潜在的内置解决方案)。
答案 3 :(得分:0)
只需对 pfx 代码进行一些修改,以消除对Newtonsoft Json.Net
的依赖。
String
扩展名键,用于将给定的字符串转换为SnakeCase
。
public static class StringUtils
{
public static string ToSnakeCase(this string str)
{
return string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower();
}
}
然后在我们的SnakeCaseNamingPolicy
中可以做到
public class SnakeCaseNamingPolicy : JsonNamingPolicy
{
public static SnakeCaseNamingPolicy Instance { get; } = new SnakeCaseNamingPolicy();
public override string ConvertName(string name)
{
// Conversion to other naming conventaion goes here. Like SnakeCase, KebabCase etc.
return name.ToSnakeCase();
}
}
最后一步是在Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddJsonOptions(
options => {
options.JsonSerializerOptions.PropertyNamingPolicy =
SnakeCaseNamingPolicy.Instance;
});
}
使用模型:
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureCelcius { get; set; }
public int TemperatureFahrenheit { get; set; }
public string Summary { get; set; }
}
Json
输出:
{
"date": "2019-10-28T08:26:14.878444+05:00",
"temperature_celcius": 4,
"temperature_fahrenheit": 0,
"summary": "Scorching"
}
答案 4 :(得分:0)
有点晚了,但是这个解决方案也将解决像ABCItem或MyCPU这样的情况。 这只是概念,您可以对其进行改进以使其更加通用
using System.Collections.Generic;
namespace Extensions
{
public static class StringExtension
{
public static string ToSnakeCase(this string str)
{
// collect the final result
var snakeCase = new List<char>();
// check and add chars (using for loop for performance)
for (int i = 0; i < str.Length; i++)
{
if (i > 0 && char.IsUpper(str[i]) && !char.IsUpper(str[i + 1]))
{
snakeCase.Add('_');
}
snakeCase.Add(str[i]);
}
// build the new string
return new string(snakeCase.ToArray()).ToLower();
}
}
}
var snakeCase = "CPUMeter".ToSnakeCase();
var snakeCase = "PascalCase".ToSnakeCase();
var snakeCase = "camelCase".ToSnakeCase();
答案 5 :(得分:0)
这是一个带有 SnakeCase
和 KebabCase
NamingPolicy for System.Text.Json
https://github.com/J0rgeSerran0/JsonNamingPolicy
JsonSnakeCaseNamingPolicy
var options = new JsonSerializerOptions() { PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy() };
var person = new Person() { FirstName = "Jorge", Birthday = DateTime.UtcNow, MyJobCity = "Madrid" };
var json = JsonSerializer.Serialize(person, options);
JsonKebabCaseNamingPolicy
var options = new JsonSerializerOptions() { PropertyNamingPolicy = new JsonKebabCaseNamingPolicy() };
var person = new Person() { FirstName = "Jorge", Birthday = DateTime.UtcNow, MyJobCity = "Madrid" };
var json = JsonSerializer.Serialize(person, options);