2012-02-13 10 views
8

के भीतर Deserializing DateTime मुझे System.Runtime.Serialization.Json.DataContractJsonSerializer कक्षा का उपयोग करके List<object> में स्थित डेटटाइम उदाहरणों को deserialize करने में समस्या हो रही है। मुझे मूल प्रकार में वापस deserialize करने के लिए डेटटाइम नहीं मिल रहा है। DataContractJsonSerializer हमेशा "/Date(1329159196126-0500)/" प्रारूप के साथ एक स्ट्रिंग प्रकार में deserializes। यदि मैं दृढ़ता से टाइप किए गए List<DateTime> का उपयोग करके इसे चलाता हूं तो यह क्रमबद्ध और deserialize करेगा, हालांकि, मैं एक सरल सूची या object की सरणी के भीतर सामना करने के लिए सीरियलाइज़र को पहचानने और सही तरीके से deserialize करने के लिए रास्ता तलाश रहा हूं।DataContractJsonSerializer - सूची <object>

ध्यान दें कि डेटटाइम प्राइमेटिव्स और तारों के अलावा एकमात्र प्रकार है जो इस सूची में कभी भी शामिल होगा। यहां कोड स्निपेट है जिसका मैं परीक्षण करने के लिए उपयोग कर रहा हूं।

var list = new List<object> { 27, "foo bar", 12.34m, true, DateTime.Now }; 
var serializer = new DataContractJsonSerializer(typeof (List<object>)); 
using (MemoryStream ms = new MemoryStream()) 
{ 
    serializer.WriteObject(ms, list); 
    ms.Position = 0; 
    var deserializedList = serializer.ReadObject(ms) as List<object>; 
} 

उत्तर

7

यह बहुत ही अजीब तरह लगता है व्यवहार, मेरा अनुमान है कि यह डेटटाइम से उत्पन्न होता है जो कि जेएस में पुन: स्थापित नहीं होता है पर। हालांकि, आप serialization/deserialization प्रक्रिया को संशोधित करने के लिए अपना खुद का IDataContractSurrogate रोल कर सकते हैं।

जब आप इस के लिए serializer बनाने यह अपने नमूना कोड को संशोधित का उपयोग करें:

var serializer = new DataContractJsonSerializer(typeof(List<object>), null, int.MaxValue, false, new DateTimeDataContractSurrogate(), true); 

तो इस वर्ग को जोड़ने: .नेट फ्रेमवर्क संस्करण में

public class DateTimeDataContractSurrogate : IDataContractSurrogate 
    { 
     private static readonly Regex dateRegex = new Regex(@"/Date\((\d+)([-+])(\d+)\)/"); 
     private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 

     public object GetCustomDataToExport(Type clrType, Type dataContractType) 
     { 
      // not used 
      return null; 
     } 

     public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) 
     { 
      // not used 
      return null; 
     } 

     public Type GetDataContractType(Type type) 
     { 
      // not used 
      return type; 
     } 

     public object GetDeserializedObject(object obj, Type targetType) 
     { 
      // for debugging 
      //Console.WriteLine("GetDeserializedObject: obj = {0} ({1}), targetType = {2}", obj, obj.GetType(), targetType); 

      // only act on List<object> types 
      if (obj.GetType() == typeof(List<object>)) 
      { 
       var objList = (List<object>)obj; 

       List<object> copyList = new List<object>(); // a list to copy values into. this will be the list returned. 
       foreach (var item in objList) 
       { 
        string s = item as string; 
        if (s != null) 
        { 
         // check if we match the DateTime format 
         Match match = dateRegex.Match(s); 
         if (match.Success) 
         { 
          // try to parse the string into a long. then create a datetime and convert to local time. 
          long msFromEpoch; 
          if (long.TryParse(match.Groups[1].Value, out msFromEpoch)) 
          { 
           TimeSpan fromEpoch = TimeSpan.FromMilliseconds(msFromEpoch); 
           copyList.Add(TimeZoneInfo.ConvertTimeFromUtc(epoch.Add(fromEpoch), TimeZoneInfo.Local)); 
           continue; 
          } 
         } 
        } 

        copyList.Add(item); // add unmodified 
       } 

       return copyList; 
      } 

      return obj; 
     } 

     public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes) 
     { 
      // not used 
     } 

     public object GetObjectToSerialize(object obj, Type targetType) 
     { 
      // for debugging 
      //Console.WriteLine("GetObjectToSerialize: obj = {0} ({1}), targetType = {2}", obj, obj.GetType(), targetType); 
      return obj; 
     } 

     public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) 
     { 
      // not used 
      return null; 
     } 

     public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit) 
     { 
      // not used 
      return typeDeclaration; 
     } 
    } 
+1

यह अनिवार्य रूप से समाधान है जिसे मैंने कार्यान्वित किया है। धन्यवाद। –

+0

1 9 70 से पहले की तारीखों का समर्थन करने के लिए आपका रेगेक्स '/ Date \ ((-?\ d +) ([- +]) (\ - +]) (\ d +) \) /) ' –

4

तो DataContractJsonSerializer एक चाहिए नहीं है, यहाँ एक समाधान Json.Net का उपयोग कर रहा है।

var list = new List<object> { 27, "foo bar", 12.34m, true, DateTime.Now }; 

string json = JsonConvert.SerializeObject(list); 
var orgObj=JsonConvert.DeserializeObject<List<object>>(json); 

यह JSON स्ट्रिंग है

[27,"foo bar",12.34,true,"\/Date(1329161615596+0200)\/"] 

और लौट आए प्रकार long, string, double, bool और DateTime

3

हैं आप क्रमबद्धता से पहले एक स्ट्रिंग के लिए DateTime.Now परिवर्तित कर सकते हैं और
इसे वापस दिनांक में परिवर्तित करें deserialization के बाद ime

द्वारा स्ट्रिंग के लिए रूपांतरण:

string dateAsString = Convert.ToString(DateTime.Now); 

रूपांतरण वापस दिनांक समय के लिए अक्रमांकन के बाद:

DateTime dateTime = Convert.ToDateTime(deserializedList[4]); 

तो पूरे कोड होगा जैसे:

string dateAsString = Convert.ToString(DateTime.Now); 
    var list = new object[] { 27, "foo bar", 12.34m, true, dateAsString }; 

    var serializer = new DataContractJsonSerializer(typeof (List<object>)); 

    using (MemoryStream ms = new MemoryStream()) 
    { 
    serializer.WriteObject(ms, list); 
    ms.Position = 0; 
    var deserializedList = serializer.ReadObject(ms) as List<object>; 
    DateTime dateTime = Convert.ToDateTime(deserializedList[4]); 
    } 
30

4,5 DataContractJsonSerializer एक है DataContractJsonSerializerSettings ऑब्जेक्ट को स्वीकार करने वाला कन्स्ट्रक्टर जिसका उपयोग DateTimeFormat:

var ser = new DataContractJsonSerializer(typeof(CreateOmsEntryCommand), 
       new DataContractJsonSerializerSettings 
       { 
        DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ") 
       }); 
सेट करने के लिए किया जा सकता है
+2

क्रमबद्धता के संदर्भ में, ऐसा लगता है कि 'दिनांक समय' यूटीसी में पहले स्थान पर नहीं है: इसमें मूल्य होंगे स्थानीय समय का, लेकिन 'जेड' यूटीसी का प्रतिनिधित्व करता है (इसलिए पढ़ने की तरफ गलत व्याख्या करें)। 'Yyyy-MM-dd'T'HH: mm: ssK' का उपयोग करना शायद बेहतर है। – Bruno

+1

मैं सहमत हूं, 'yyyy-MM-dd'T'HH: mm: ssK' या 'yyyy-MM-dd'T'HH: mm: sszzz' का उपयोग करें। 'Yyyy-MM-dd'T'HH: mm: ssZ' का उपयोग न करें। –