【问题标题】:Issue with Default camelCase serialization of All Caps property names to JSON in ASP.Net core在 ASP.Net 核心中将所有 Caps 属性名称的默认 camelCase 序列化为 JSON 的问题
【发布时间】:2019-02-21 18:18:59
【问题描述】:

我对 .Net Core 的默认序列化 CamelCasing 行为有疑问,希望看看其他人是否遇到同样的问题以及他们使用了哪些解决方法。

像 FOO12 或 FOO1 这样的属性名称被错误地序列化为类似

foO12 或 foO1

事实上,它们可能应该作为 foo12 或 foo1 完成。

我使用了添加以下属性的解决方法,但希望有人可能对此问题有更好的答案:

[JsonProperty(PropertyName = "foo12")]

【问题讨论】:

标签: c# json .net-core asp.net-core-mvc camelcasing


【解决方案1】:

Json.NETCamelCasePropertyNamesContractResolver 使用CamelCaseNamingStrategy 将属性名称转换为驼峰式。在内部,它使用StringUtils.ToCamelCase,它不会将字符转换为小写,以防它后跟数字,请参阅link

CamelCaseNamingStrategy

public class CamelCaseNamingStrategy : NamingStrategy
{
    // ...

    protected override string ResolvePropertyName(string name)
    {
        return StringUtils.ToCamelCase(name);
    }
}

StringUtils

注意第二条if 语句,其中没有检查数字。

internal static class StringUtils
{
    public static string ToCamelCase(string s)
    {
        if (!string.IsNullOrEmpty(s) && char.IsUpper(s[0]))
        {
            char[] array = s.ToCharArray();
            for (int i = 0; i < array.Length && (i != 1 || char.IsUpper(array[i])); i++)
            {
                bool flag = i + 1 < array.Length;
                if ((i > 0 & flag) && !char.IsUpper(array[i + 1])) // << Missing check for a number.
                {
                    break;
                }
                char c = char.ToLower(array[i], CultureInfo.InvariantCulture);
                array[i] = c;
            }
            return new string(array);
        }
        return s;
    }
}

您可以实现一个自定义NamingStrategy来实现这个缺失的检查,如下所示。

class CustomCamelCaseNamingStrategy : CamelCaseNamingStrategy
{
    protected override String ResolvePropertyName(String propertyName)
    {
        return this.toCamelCase(propertyName);
    }

    private string toCamelCase(string s)
    {
        if (!string.IsNullOrEmpty(s) && char.IsUpper(s[0]))
        {
            char[] array = s.ToCharArray();
            for (int i = 0; i < array.Length && (i != 1 || char.IsUpper(array[i])); i++)
            {
                bool flag = i + 1 < array.Length;
                if ((i > 0 & flag) && !char.IsUpper(array[i + 1]) && !char.IsNumber(array[i + 1]))
                {
                    break;
                }
                char c = char.ToLower(array[i], CultureInfo.InvariantCulture);
                array[i] = c;
            }
            return new string(array);
        }
        return s;
    }
}

ConfigureServices 中,您将此自定义NamingStrategy 分配给CamelCasePropertyNamesContractResolver
无需实现完全自定义的ContractResolver
(当使用默认的CamelCaseNamingStrategy 时,CamelCasePropertyNamesContractResolver 将属性ProcessDictionaryKeysOverrideSpecifiedNames 设置为True,所以我们保留这个行为。)

services
    .AddMvc()
    .AddJsonOptions(options => 
        options.SerializerSettings.ContractResolver = 
            new CamelCasePropertyNamesContractResolver() { 
                NamingStrategy = new CustomCamelCaseNamingStrategy() { 
                ProcessDictionaryKeys = true,
                OverrideSpecifiedNames = true 
        }});

【讨论】:

  • 哦,不要更改CamelCasePropertyNamesContractResolver 上的NamingStrategy,它会在所有实例中全局共享合同信息。有关详细信息,请参阅Json.Net: Html Helper Method not regenerating。相反,只需替换 DefaultContractResolver 上的 NamingStrategy
  • @dbc 如果整个应用程序都需要这种序列化,这可能不是问题。对于您指出的情况,我确实理解这一点,因为某些属性被排除在序列化之外,这在该问题中是全局不需要的。
  • 如果应用程序的其他部分之前使用未修改的CamelCasePropertyNamesContractResolver 序列化了某些数据,您可能会被烧毁。在这种情况下,稍后设置的CustomCamelCaseNamingStrategy 显然会被忽略。
  • @dbc 好的,谢谢,我不知道。我将把它留给 OP 来决定是否使用完整的自定义 ContractResolver。序列化的线索保留在自定义NamingStrategy 中。不过谢谢,我学到了一些新东西!
  • 你不需要继承DefaultContractResolver。您可以在常规的旧 DefaultContractResolver 上设置自定义命名策略,例如如JsonSerializerSettingsProvider 所示。实际上,在 Json.NET 9.0.1 中将命名策略从合约解析器中分离出来后,CamelCasePropertyNamesContractResolver 大多是多余的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-13
  • 1970-01-01
相关资源
最近更新 更多