Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
324 views
in Technique[技术] by (71.8m points)

c# - How to make Json Serialize ignore dictionary keys

I'm trying to serialize a dictionary within a class and the keys inside the CustomAttributes dictionary are getting formatted even though I've provided the ProcessDictionaryKeys parameter as false.

I've added [JsonProperty] as shown below:

[JsonProperty(NamingStrategyType = typeof(SnakeCaseNamingStrategy), NamingStrategyParameters = new object[] { false, false })]
public IDictionary<string, string> CustomAttributes { get; set; }

my CustomAttributes data looks like this:

CustomAttributes = new Dictionary<string, string>()
{
    {"Custom Attribute 1", "1"},
    {"CustomAttribute 2", "2"}
}

and the JSON which is produced looks like:

custom_attributes":{"custom Attribute 1":"1","customAttribute 2":"2"

As you can see, the first letter of each of the dictionary keys are being uncapitalised. How can I stop this from happening?

EDIT: Changing the ProcessDictionaryKeys parameter to true doesn't seem to make any difference.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem doesn't reproduce with just the code in your question as shown in demo fiddle #1 here.

Instead, you must be serializing with some global serializer settings for which JsonSerializerSettings.ContractResolver.NamingStrategy.ProcessDictionaryKeys = true such as CamelCasePropertyNamesContractResolver:

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);

Demo fiddle #2 here.

Assuming that's correct, the reason that [JsonProperty(NamingStrategyType = typeof(SnakeCaseNamingStrategy), NamingStrategyParameters = new object[] { false, false })] does not cause the dictionary keys to be serialized verbatim is that JsonPropertyAttribute.NamingStrategyType only applies to the property name itself (here CustomAttributes) not the property names of property's items. If you wanted to apply a naming strategy to the property's items you would need something like ItemNamingStrategyType -- but JsonPropertyAttribute has no such functionality.

So, what are your options?

  1. You could modify your global naming strategy to serialize dictionary names verbatim as shown in Keep casing when serializing dictionaries.

  2. You could subclass Dictionary<TKey, TValue> and apply [JsonDictionary(NamingStrategyType = typeof(DefaultNamingStrategy))] to it as shown in this answer to Applying JsonDictionary attribute to dictionary:

    [JsonDictionary(NamingStrategyType = typeof(DefaultNamingStrategy))]
    public class VerbatimDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
    }
    

    And then later:

    CustomAttributes = new VerbatimDictionary<string, string>()
    {
        {"Custom Attribute 1", "1"},
        {"CustomAttribute 2", "2"}
    }
    

    Demo fiddle #3 here.

  3. You could introduce a custom JsonConverter that serializes an IDictionary<TKey, TValue> with the default naming strategy. First, define the following converter:

    public class VerbatimDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
    {
        [JsonDictionary(NamingStrategyType = typeof(DefaultNamingStrategy))]
        class VerbatimDictionarySerializationSurrogate : IReadOnlyDictionary<TKey, TValue>
        {
            readonly IDictionary<TKey, TValue> dictionary;
    
            public VerbatimDictionarySerializationSurrogate(IDictionary<TKey, TValue> dictionary) 
            { 
                if (dictionary == null) 
                    throw new ArgumentNullException(nameof(dictionary));
                this.dictionary = dictionary; 
            }
            public bool ContainsKey(TKey key) { return dictionary.ContainsKey(key); }
            public bool TryGetValue(TKey key, out TValue value) { return dictionary.TryGetValue(key, out value); }
            public TValue this[TKey key] { get { return dictionary[key]; } }
            public IEnumerable<TKey> Keys { get { return dictionary.Keys; } }
            public IEnumerable<TValue> Values { get { return dictionary.Values; } }
            public int Count { get { return dictionary.Count; } }
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return dictionary.GetEnumerator(); }
            IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
        }
    
        public override void WriteJson(JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, new VerbatimDictionarySerializationSurrogate(value));
        }
    
        public override bool CanRead { get { return false; } }
    
        public override IDictionary<TKey, TValue> ReadJson(JsonReader reader, Type objectType, IDictionary<TKey, TValue> existingValue, bool hasExistingValue, JsonSerializer serializer) { throw new NotImplementedException(); }
    }
    

    And apply it as follows:

    [JsonConverter(typeof(VerbatimDictionaryConverter<string, string>))]
    public IDictionary<string, string> CustomAttributes { get; set; }       
    

    Demo fiddle #4 here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...