我有一个Web Api项目的配置如下:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
不过,我希望字典键的大小写保持不变。Newtonsoft.Json
中是否有任何属性可以用于类,以表示我希望在序列化期间保持大小写不变?
public class SomeViewModel
{
public Dictionary<string, string> Data { get; set; }
}
没有属性可以实现这一点,但您可以通过自定义解析器来实现。
我看到你已经在使用CamelCasePropertyNamesContractResolver
了。如果从中派生一个新的解析器类并重写CreateDictionaryContract()
方法,则可以提供一个不更改键名的替代DictionaryKeyResolver
函数。
这是您需要的代码:
class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);
contract.DictionaryKeyResolver = propertyName => propertyName;
return contract;
}
}
演示:
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo
{
AnIntegerProperty = 42,
HTMLString = "<html></html>",
Dictionary = new Dictionary<string, string>
{
{ "WHIZbang", "1" },
{ "FOO", "2" },
{ "Bar", "3" },
}
};
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(foo, settings);
Console.WriteLine(json);
}
}
class Foo
{
public int AnIntegerProperty { get; set; }
public string HTMLString { get; set; }
public Dictionary<string, string> Dictionary { get; set; }
}
这是上面的输出。请注意,所有类属性名称都是大小写的,但字典键保留了原来的大小写。
{
"anIntegerProperty": 42,
"htmlString": "<html></html>",
"dictionary": {
"WHIZbang": "1",
"FOO": "2",
"Bar": "3"
}
}
NamingStrategy
类层次结构来处理这类问题。它提取了从约定解析器到一个单独的轻量级类的属性名称算法重映射的逻辑,该类允许控制是否重映射字典键、显式指定的属性名称和扩展数据名称(在10.0.1中(。
通过使用DefaultContractResolver
并将NamingStrategy
设置为CamelCaseNamingStrategy
的实例,您可以通过在JsonSerializerSettings.ContractResolver
:中设置属性名和未修改的字典键来生成JSON
var resolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
{
ProcessDictionaryKeys = false,
OverrideSpecifiedNames = true
}
};
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = resolver;
注:
CamelCasePropertyNamesContractResolver
的当前实现还指定具有明确指定的属性名称的.Net成员(例如,已设置JsonPropertyAttribute.PropertyName
的成员(应重新映射其名称:public CamelCasePropertyNamesContractResolver() { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; }
上述
resolver
保留了这种行为。如果您不希望这样,请设置OverrideSpecifiedNames = false
。Json.NET有几个内置的命名策略,包括:
CamelCaseNamingStrategy
。一种骆驼大小写命名策略,包含以前嵌入CamelCasePropertyNamesContractResolver
中的名称重映射逻辑- CCD_ 16。一种蛇壳命名策略
DefaultNamingStrategy
。默认命名策略。属性名称和字典键保持不变
或者,您可以通过从抽象基类
NamingStrategy
继承来创建自己的基类。虽然也可以修改
CamelCasePropertyNamesContractResolver
实例的NamingStrategy
,但由于后者在每种类型的所有实例中全局共享契约信息,因此如果应用程序尝试使用多个CamelCasePropertyNamesContractResolver
实例,这可能会导致意外的副作用。DefaultContractResolver
不存在这样的问题,因此在需要定制外壳逻辑时使用更安全。
这是一个非常好的答案。但为什么不直接覆盖ResolveDictionaryKey
呢?
class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver
{
#region Overrides of DefaultContractResolver
protected override string ResolveDictionaryKey(string dictionaryKey)
{
return dictionaryKey;
}
#endregion
}
选择的答案是完美的,但我想当我输入这个时,合同解析程序必须更改为这样的内容,因为DictionaryKeyResolver已经不存在了:(
public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);
contract.PropertyNameResolver = propertyName => propertyName;
return contract;
}
}