शब्दकोशों को क्रमबद्ध करते समय आवरण रखें


92

मेरे पास एक वेब एपी परियोजना इस तरह विन्यस्त है:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

हालाँकि, मैं चाहता हूं कि शब्दकोश कुंजियाँ अपरिवर्तित रहें। क्या कोई विशेषता है Newtonsoft.Jsonकि मैं एक वर्ग का उपयोग यह दर्शाने के लिए कर सकता हूं कि मैं चाहता हूं कि धारावाहिककरण के दौरान मैं अपरिवर्तित रहूं?

public class SomeViewModel
{
    public Dictionary<string, string> Data { get; set; }    
}

1
क्या आपने डिफ़ॉल्ट रिज़ॉल्वर की कोशिश की है?
— मत्ती

1
@ मैट्टू नहीं, मैंने नहीं; क्या आप एक उदाहरण से समझा सकते हैं कि कोड कैसा दिखेगा? ध्यान दें, मैं अभी भी अपने सभी वेब एपीआई अनुरोधों के लिए कैमल केस क्रमांकन चाहता हूं, मैं सिर्फ एक वर्ग के लिए कस्टम क्रमांकन चाहता हूं (या शायद किसी शब्दकोश कुंजी के लिए)।
— zafeiris.m

जवाबों:


132

ऐसा करने के लिए कोई विशेषता नहीं है, लेकिन आप इसे रिज़ॉल्वर को अनुकूलित करके कर सकते हैं।

मैं देख रहा हूं कि आप पहले से ही एक का उपयोग कर रहे हैं 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"
  }
}

2
FYI करें, PropertyNameResolver अब अप्रचलित है। ऐसा लगता है कि contract.DictionaryKeyResolver = key => key;ठीक काम करता है।
— जॉन गीज़ेन

1
यह अभी भी गुमनाम प्रकारों के साथ बहुत प्रासंगिक है, खासकर जब हम ऊंट संरचना के अधिकांश के लिए आवरण चाहते हैं, लेकिन नहीं चाहते हैं कि शब्दकोशों के अंदर कुंजी ऊंट हो।
— क्रिस शॉलर

क्रिस के साथ बिल्कुल सहमत हैं। मुझे अपने जावास्क्रिप्ट में केवल हुप्स से गुजरने के लिए मजबूर किया गया है क्योंकि मैं शब्दकोशों को ऊंट होने से रोक नहीं सकता। पता चला है कि कोड की एक पंक्ति इस समस्या को हल करेगी (और मेरे जावास्क्रिप्ट को बहुत सरल बना देगी)!
— स्टीफन चुंग

@BrianRogers महान काम करता है! हालाँकि, क्या आप जानते हैं कि DictionaryKeyResolverअगर मेरी डिक्शनरी में कुछ प्रॉपर्टी एट्रीब्यूट है तो क्या मैं इसका इस्तेमाल कर सकता हूं ?
— मुगैन

@ मेरे सिर के ऊपर से नहीं हटे। मैं एक नया प्रश्न पूछना चाहूंगा। यदि आपको संदर्भ प्रदान करने की आवश्यकता है तो आप इस प्रश्न को वापस लिंक कर सकते हैं।
— ब्रायन रोजर्स

67

NamingStrategyइस प्रकार के मुद्दे को संभालने के लिए Json.NET 9.0.1 ने वर्ग पदानुक्रम की शुरुआत की । यह अनुबंध के रिज़ॉल्वर से एक अलग, हल्के वर्ग के लिए संपत्ति के नामों के एल्गोरिदम के रीमैपिंग के लिए तर्क को निकालता है जो शब्दकोश कुंजी , स्पष्ट रूप से निर्दिष्ट संपत्ति के नाम , और विस्तार डेटा नाम ( 10.0.1 में ) के नियंत्रण के लिए अनुमति देता है ।

आप का उपयोग करके DefaultContractResolverऔर NamingStrategyउदाहरण के लिए सेटिंग करके CamelCaseNamingStrategyJSON को ऊंट-आवरण वाली संपत्ति के नाम और इसके द्वारा अयोग्य शब्दकोश कुंजी के साथ उत्पन्न कर सकते हैं JsonSerializerSettings.ContractResolver:

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 में कई अंतर्निहित नाम रणनीति शामिल हैं:

    1. CamelCaseNamingStrategy। एक ऊंट मामले का नामकरण रणनीति जिसमें नाम-रीमैपिंग तर्क शामिल है जो पूर्व में अंतर्निहित है CamelCasePropertyNamesContractResolver।
    2. SnakeCaseNamingStrategy। एक सांप का मामला नामकरण की रणनीति।
    3. DefaultNamingStrategy। डिफ़ॉल्ट नामकरण की रणनीति। संपत्ति के नाम और शब्दकोश कुंजी अपरिवर्तित हैं।

    या, आप मूल आधार वर्ग से विरासत में अपना खुद का बना सकते हैं NamingStrategy।

  • हालांकि, इसके NamingStrategyउदाहरण को संशोधित करना भी संभव है CamelCasePropertyNamesContractResolver, क्योंकि बाद के शेयर प्रत्येक प्रकार के सभी उदाहरणों में वैश्विक रूप से जानकारी अनुबंधित करते हैं , इससे अनपेक्षित दुष्परिणाम हो सकते हैं यदि आपका एप्लिकेशन कई उदाहरणों का उपयोग करने का प्रयास करता है CamelCasePropertyNamesContractResolver। ऐसी कोई समस्या मौजूद नहीं है DefaultContractResolver, इसलिए आवरण तर्क के किसी भी अनुकूलन की आवश्यकता होने पर इसका उपयोग करना अधिक सुरक्षित है।


यह समाधान एक संपत्ति की तरह काम नहीं कर रहा है public Dictionary<string, Dictionary<string, string>> Values { get; set; }। यह अभी भी भीतर शब्दकोश कुंजी के लिए camelCase करता है।
— हिक्कलन

@ हिक्कलान - जब मैं आपकी सटीक समस्या को पुन: पेश नहीं कर सका, तो मैं कई उदाहरणों का उपयोग करते समय एक समस्या खोजने में सक्षम था CamelCasePropertyNamesContractResolver। NamingStrategyपहले के लिए मूल रूप से दूसरे द्वारा उत्पन्न अनुबंधों को प्रभावित करेगा। यही कारण है कि हो सकता है हो सकता है कि आप क्या देख रहे हैं। इसके बजाय नई सिफारिश का प्रयास करें और मुझे बताएं कि क्या आपकी समस्या को ठीक करता है।
— dbc

1
क्या कोई लचीला है NamingStrategy, ताकि यह ऊंट मामले और पास्कल मामले को पार्स करने में सक्षम हो?
— शिम्मी वेइटहंडलर

@dbc प्रारंभिक कोड नमूने में, क्या configमाना जाता है?
— रयान लुनडी

@RyanLundy - मैंने इसे प्रारंभिक प्रश्न से कॉपी किया था, जिसमें निम्न पंक्ति कोड दिखाई देती थी config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();:। यह MVC 4 वेब API प्रतीत होता है HttpConfiguration, देखें कि MVC 4 वेब एपीआई में Json.NET के लिए कस्टम JsonSerializerSettings कैसे सेट करें? ।
— dbc

12

यह बहुत अच्छा जवाब है। लेकिन सिर्फ ओवरराइड क्यों नहीं ResolveDictionaryKey?

class CamelCaseExceptDictionaryResolver : CamelCasePropertyNamesContractResolver
    {
        #region Overrides of DefaultContractResolver

        protected override string ResolveDictionaryKey(string dictionaryKey)
        {
            return dictionaryKey;
        }

        #endregion
    }

बहुत चर्चित। साझा करने के लिए Thx।
— अबू अब्दुल्ला

1

चयनित उत्तर सही है, लेकिन मुझे लगता है कि जब तक मैं इसे टाइप कर रहा हूं, तब तक अनुबंध रिज़ॉल्वर को कुछ इस तरह बदलना होगा क्योंकि DictionaryKeyResolver अब मौजूद नहीं है :)

public class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
    {
        protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
        {
            JsonDictionaryContract contract = base.CreateDictionaryContract(objectType);
            contract.PropertyNameResolver = propertyName => propertyName;
            return contract;
        }
    }

4
वास्तव में उल्टा सच है। आप Json.Net के पुराने संस्करण का उपयोग कर रहे होंगे। 7.0.1 संस्करणDictionaryKeyResolver में जोड़ा गया था , और अप्रचलित चिह्नित किया गया था। PropertyNameResolver
— ब्रायन रोजर्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.