2015-07-09 6 views
8

के साथ मॉडल को परिवर्तित नहीं कर सकता है मेरे पास सी # एमवीसी एप्लिकेशन है जो डेटा को XML दस्तावेज़ में JSON स्ट्रिंग्स और MySQL डीबी टेबल्स में संग्रहीत करता है।Newtonsoft.JSON TypeConverter विशेषता

हाल ही में मैं MySQL डाटाबेस क्षेत्रों, में दुकान JSON तार करने के लिए आवश्यकता Newtonsoft.Json के माध्यम से सी # वस्तुओं में परिवर्तित किया प्राप्त हुआ है, तो मैं एक TypeConverter लागू करने के लिए कस्टम सी # मॉडल में JSON तार कन्वर्ट करने के लिए फैसला किया।

दुर्भाग्य से मैं निम्न आदेश कहीं भी मेरी समाधान में मेरी JSON तार deserialize करने के लिए उपयोग नहीं कर सकते जब TypeConverter विशेषता मेरी सी # मॉडल में जोड़ा जाता है:

JsonConvert.DeserializeObject<Foo>(json); 

निकाला जा रहा है विशेषता को हल मुद्दा हालांकि यह मेरे से बचाता है MySQL डीबी फ़ील्ड को कस्टम सी # ऑब्जेक्ट्स में कनवर्ट करने से।

यहाँ TypeConverter गुण के साथ मेरी सी # मॉडल जोड़ा है:

using Newtonsoft.Json; 
using System; 
using System.ComponentModel; 

    public class FooConverter : TypeConverter 
    { 
     public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType) 
     { 
      if (sourceType == typeof(string)) 
      { 
       return true; 
      } 
      return base.CanConvertFrom(context, sourceType); 
     } 
     public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
     { 
      if (value is string) 
      { 
       string s = value.ToString().Replace("\\",""); 
       Foo f = JsonConvert.DeserializeObject<Foo>(s); 
       return f; 
      } 
      return base.ConvertFrom(context, culture, value); 
     } 
    } 
} 

जैसे ही मैं फू के लिए विशेषता जोड़ने के रूप में:

using System.ComponentModel; 

[TypeConverter(typeof(FooConverter))] 
public class Foo 
{ 
    public bool a { get; set; } 
    public bool b { get; set; } 
    public bool c { get; set; } 
    public Foo(){} 
} 

यहाँ मेरी TypeConverter कक्षा है कक्षा मुझे निम्न त्रुटि प्राप्त होती है:

वर्तमान JSON ऑब्जेक्ट को deserialize नहीं कर सकता (उदा। {"name": "value"}) 'Models.Foo' टाइप करें क्योंकि टाइप को JSON स्ट्रिंग मान को सही ढंग से deserialize करने की आवश्यकता होती है।

इस त्रुटि को ठीक करने के लिए या तो एक JSON स्ट्रिंग मान को बदलने के लिए या JSON deserialized प्रकार बदलने के लिए इतना है कि यह एक सामान्य नेट प्रकार है (उदाहरण के लिए नहीं, नहीं एक सरणी की तरह एक संग्रह प्रकार पूर्णांक की तरह एक आदिम प्रकार या सूची) जिसे JSON ऑब्जेक्ट से deserialized किया जा सकता है। JsonObjectAttribute को किसी JSON ऑब्जेक्ट से deserialize करने के लिए मजबूर करने के लिए भी जोड़ा जा सकता है।

मैं निम्न स्ट्रिंग (जो TypeConverter गुण जोड़े बिना पूरी तरह से काम करता है) का उपयोग कर रहा:

"{\"Foo\":{\"a\":true,\"b\":false,\"c\":false}}" 
नहीं

यकीन है कि यहाँ क्या किसी भी विचार हो रहा है,?

बहुत धन्यवाद !!!

अद्यतन

मुझे पता चला है है कि मैं भी MVC एपीआई नियंत्रकों पर कार्रवाई है कि एक संपत्ति के रूप में या नियंत्रकों पर टेस्ट कक्षा फू के साथ स्वीकार करते हैं कि एक वस्तु के रूप फू स्वीकार के साथ समस्या है जब टाइप कनवर्टर विशेषता फ़ू क्लास में जोड़ा गया है।

public class TestController : ApiController 
{ 
    [AcceptVerbs("POST", "GET")] 
    public void PostTestClass(TestClass t) 
    { 
     // Returns null when TypeConverter attribute is added to the Foo Class 
     return t.Foo; 
    } 
    AcceptVerbs("POST", "GET")] 
    public void PostFooObj(Foo f) 
    { 
     // Returns null when TypeConverter attribute is added to the Foo Class 
     return f; 
    } 
} 

TypeConverter वेबएपीआई मॉडल बंधन अधिभावी समस्याएं उत्पन्न कर सकता है और अशक्त लौटाता है जब या तो कार्रवाई ऊपर निम्नलिखित संरचना के साथ AJAX के माध्यम से JSON प्राप्त करता है:

यहाँ एक परीक्षण नियंत्रक जो मुद्दे हैं का एक उदाहरण है:

// eg. PostTestClass(TestClass T) 
{'Foo': {'a': false,'b': true,'c': false}}; 

// eg. PostFooObj(Foo f) 
{'a': false,'b': true,'c': false} 

जब TypeConverter गुण फू क्लास, FooConverter TypeConverter वर्ग पर निम्न विधि में जोड़ा जाता है जैसे ही मार्ग पाया जाता है कहा जाता है:

public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
     { 
      return true; 
     } 
     return base.CanConvertFrom(context, sourceType); 
    } 

FooConverter TypeController पर कनवर्टफ्रॉम विधि को एपीकंट्रोलर की कार्रवाई द्वारा नहीं कहा जाता है, जो इस मुद्दे का कारण हो सकता है।

फिर यह एक समान स्थिति है, जहां नियंत्रक क्रिया टाइपकॉन्टर विशेषता के बिना ठीक काम करेगी।

किसी और मदद की बहुत सराहना की !!

बहुत धन्यवाद।

+0

क्या आपके JSON स्ट्रिंग को आपने जो दिखाया है उस पर तय किया गया है \ "{\" Foo \ ": ...}" '? – kaveman

+0

हाँ आप सही हैं JSON मेरे परीक्षण समाधान में नहीं बदलता है। मैं जो बदल रहा हूं वह टाइपकॉन्टर विशेषता जोड़ रहा/हटा रहा है। धन्यवाद – Steve

+2

मैं उत्सुक हूं यदि आप किसी JSON संरचना का उपयोग '" {\ "a \": true, \ "b \": false, \ "c \": false} "के समान ही कर सकते हैं। रैपिंग के बिना '{{" Foo \ ": ...}" ऑब्जेक्ट। यह JSON सीधे 'JsonConvert.DeserializeObject (जेसन) ' – kaveman

उत्तर

13

यहां कुछ चीजें चल रही हैं। सबसे पहले, एक प्रारंभिक मुद्दा: कोई TypeConverter भी साथ लागू, आपके JSON अपनी कक्षा Foo के अनुरूप नहीं है, यह कुछ कंटेनर वर्ग है कि एक Foo प्रॉपर्टी वाला से मेल खाती है, उदाहरण के लिए:

public class TestClass 
{ 
    public Foo Foo { get; set; } 
} 

अर्थात अपने JSON स्ट्रिंग को देखते हुए निम्नलिखित काम करेंगे नहीं:

var json = "{\"Foo\":{\"a\":true,\"b\":false,\"c\":false}}"; 
var foo = JsonConvert.DeserializeObject<Foo>(json); 

लेकिन निम्नलिखित इच्छा:

var test = JsonConvert.DeserializeObject<TestClass>(json); 

मुझे लगता है यह केवल प्रश्न में एक गलती है, तो मैं मान लेंगे आप के लिए देख रहे एक वर्ग deserialize एक संपत्ति Foo है।

मुख्य समस्या यह है कि आप देख रहे हैं कि Json.NET एक TypeConverter अगर एक एक वर्ग JSON स्ट्रिंग को धारावाहिक जा करने के लिए कन्वर्ट करने के लिए मौजूद है इस्तेमाल करने की कोशिश करेंगे। docs से:

Primitive Types

.Net: TypeConverter (convertible to String)
JSON: String

लेकिन अपने JSON में, Foo JSON स्ट्रिंग नहीं है, यह एक JSON वस्तु है, इस प्रकार अक्रमांकन एक बार प्रकार कनवर्टर लागू किया जाता है विफल रहता है। एक एम्बेडेड स्ट्रिंग इस तरह दिखेगी:

{"Foo":"{\"a\":true,\"b\":false,\"c\":false}"} 

ध्यान दें कि सभी उद्धरण कैसे बच गए हैं। और यहां तक ​​कि यदि आपने Foo ऑब्जेक्ट्स से मिलान करने के लिए अपना JSON प्रारूप बदल दिया है, तो भी आपका deserialization TypeConverter और Json.NET एक दूसरे को कॉल करने का प्रयास करेगा।

इस प्रकार है कि आप क्या करने की जरूरत है Json.NET द्वारा TypeConverter की अक्षम उपयोग और विश्व स्तर पर वापस आ क्रमबद्धता डिफ़ॉल्ट जबकि अन्य सभी स्थितियों में TypeConverter के उपयोग को बनाए रखना है।

public class NoTypeConverterJsonConverter<T> : JsonConverter 
{ 
    static readonly IContractResolver resolver = new NoTypeConverterContractResolver(); 

    class NoTypeConverterContractResolver : DefaultContractResolver 
    { 
     protected override JsonContract CreateContract(Type objectType) 
     { 
      if (typeof(T).IsAssignableFrom(objectType)) 
      { 
       var contract = this.CreateObjectContract(objectType); 
       contract.Converter = null; // Also null out the converter to prevent infinite recursion. 
       return contract; 
      } 
      return base.CreateContract(objectType); 
     } 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(T).IsAssignableFrom(objectType); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Deserialize(reader, objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Serialize(writer, value); 
    } 
} 

और यह पसंद का उपयोग करें:: यह थोड़ा मुश्किल के बाद से कोई Json.NET attribute आप प्रकार कन्वर्टर्स के उपयोग को अक्षम करने के लिए आवेदन कर सकते हैं आप एक विशेष अनुबंध रिसोल्वर के साथ साथ एक विशेष JsonConverter जरूरत है यह का उपयोग करने के लिए है, बजाय

[TypeConverter(typeof(FooConverter))] 
[JsonConverter(typeof(NoTypeConverterJsonConverter<Foo>))] 
public class Foo 
{ 
    public bool a { get; set; } 
    public bool b { get; set; } 
    public bool c { get; set; } 
    public Foo() { } 
} 

public class FooConverter : TypeConverter 
{ 
    public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
     { 
      return true; 
     } 
     return base.CanConvertFrom(context, sourceType); 
    } 
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
    { 
     if (value is string) 
     { 
      string s = value.ToString(); 
      //s = s.Replace("\\", ""); 
      Foo f = JsonConvert.DeserializeObject<Foo>(s); 
      return f; 
     } 
     return base.ConvertFrom(context, culture, value); 
    } 
} 

उदाहरण fiddle

अंततः, आपको अपने प्रकार के कनवर्टर में ConvertTo विधि को भी लागू करना चाहिए, How to: Implement a Type Converter देखें।

+0

शानदार का उपयोग करके deserialized किया जा सकता है, मेरे मुद्दे को हल करने के लिए एक आकर्षण की तरह काम किया। आप सही हैं मैंने प्रश्न में जेएसओएन के साथ एक प्रश्न बना दिया है जबकि एसओ प्रश्न उदाहरणों के लिए कोड स्वरूपित किया गया है - मैं एक संपत्ति के रूप में फू के साथ कक्षा और कभी-कभी पूरी फू क्लास के रूप में एक वर्ग को deserializing कर रहा हूँ। दुर्भाग्यवश मुझे पता चला है कि मुझे ** एमवीसी एपीआई कंट्रोलर ** पर कार्रवाई के साथ भी समस्याएं हैं जो फू के साथ ** टेस्ट क्लास को एक संपत्ति के रूप में स्वीकार करते हैं ** या उन नियंत्रकों पर जो ** ऑब्जेक्ट के रूप में फू स्वीकार करते हैं ** जब ** टाइप कनवर्टर विशेषता ** फू क्लास में जोड़ा गया है। मैं जल्द ही एक उदाहरण पेश करूंगा, बहुत धन्यवाद @ डीबीसी – Steve

+2

यदि यह उत्तर है, तो कृपया इस तरह चिह्नित करने पर विचार करें। – theMayer

+0

@theMayer: क्या मुझे अपना अपडेट एक नए प्रश्न के रूप में पोस्ट करना चाहिए और इसे पूरा करने के रूप में चिह्नित करना चाहिए? धन्यवाद – Steve

संबंधित मुद्दे