2013-09-05 5 views
6

मेरे पास एक सेवा है जो ऑपरेशन कंट्रैक्ट पैरामीटर में नोडा टाइम प्रकार (LocalDate और ZonedDateTime) का उपयोग करती है, लेकिन जब मैं LocalDate(1990,7,31) उदाहरण के लिए भेजने का प्रयास करता हूं तो सर्वर को डिफ़ॉल्ट मान (1970/1/1) के साथ ऑब्जेक्ट प्राप्त होता है। क्लाइंट या सर्वर द्वारा कोई त्रुटि नहीं फेंक दी गई है।डब्ल्यूसीएफ में पैरामीटर के रूप में नोडा टाइम (या किसी तीसरे पक्ष के प्रकार) ऑब्जेक्ट को कैसे पास किया जाए?

पहले यह इसी बीसीएल प्रकारों (DateTimeOffset) के साथ अच्छी तरह से काम करता था। मैं समझता हूं कि नोडा समय के प्रकार डब्ल्यूसीएफ द्वारा "ज्ञात" नहीं हो सकते हैं, लेकिन मुझे नहीं लगता कि मैं उन्हें कैसे जोड़ना चाहता हूं। मैंने this page in the documentation about known types की जांच की, लेकिन यह मदद नहीं करता है।

क्या बीसीएल प्रकार से और गंदे (और संभवतः अपूर्ण) मैन्युअल रूपांतरण/क्रमबद्धता से बचने के लिए ऐसा करने का कोई तरीका है?

धन्यवाद।

+2

जॉन की तरह लगता है कि नोडा में डेटाकंट्रैक्ट विशेषताओं को शामिल नहीं किया गया था। आपको [IDataContractSurrogate इंटरफ़ेस] (http://msdn.microsoft.com/en-us/library/system.runtime.serialization.idatacontractsurrogate.aspx) का उपयोग करने की आवश्यकता हो सकती है – Aron

+1

धन्यवाद अरोन! यह बहुत उपयोगी था। मैं http: //blogs.msdn का उपयोग कर नो (दा) समय में एक सरोगेट बनाने में सक्षम था।com/b/carlosfigueira/archive/2011/09/14/wcf-extensibility-serialization-surrogates.aspx और http://stackoverflow.com/questions/4742225/using-a-datacontractsurrogate-with-wcf-rest –

+0

केवल नोडाटाइम वर्तमान में जेसन.नेट सीरियलाइजेशन का समर्थन करता है, और उसके बाद केवल 'नोडाटाइम। सीरियलाइजेशन। जेसननेट' के माध्यम से जो मुख्य रिलीज में संकलित नहीं है। आपको इसे स्वयं बनाना होगा। मुझे यह सुनकर खुशी हो रही है कि आप इसे डेटाकंट्रैक्ट सरोगेट्स के साथ काम करने में सक्षम थे। मुझे आपका कार्यान्वयन देखने में दिलचस्पी है। इसे कहीं पोस्ट करने के लिए तैयार रहेंगे (गिटहब, गिस्ट, इत्यादि)? –

उत्तर

3

अरोन के सुझाव के लिए धन्यवाद, मैं IDataContractSurrogate के कार्यान्वयन के साथ आने में सक्षम था, जो डब्ल्यूसीएफ (न केवल नोडा टाइम) के माध्यम से गैर बेस प्रकारों की वस्तुओं को पारित करने में बहुत मददगार है।

रुचि रखने वालों के लिए, यहां स्पष्टीकरण के साथ पूरा कोड है, स्थानीयडेट, स्थानीयडेटाइम और जोनडडेट टाइम का समर्थन करना। क्रमशः आवश्यकताओं को पूरा करने के लिए क्रमबद्धता विधि को अनुकूलित किया जा सकता है, उदाहरण के लिए जेसन.नेट सीरियलाइजेशन का उपयोग करना, क्योंकि मेरा सरल कार्यान्वयन युग/कैलेंडर जानकारी को क्रमबद्ध नहीं करेगा।

वैकल्पिक रूप से, मैंने इस गिस्ट पर पूरा कोड पोस्ट किया है: https://gist.github.com/mayerwin/6468178

पहले, सहायक वर्ग/serializing का ख्याल रखता है आधार प्रकार में कनवर्ट:

public static class DatesExtensions { 
    public static DateTime ToDateTime(this LocalDate localDate) { 
     return new DateTime(localDate.Year, localDate.Month, localDate.Day); 
    } 

    public static LocalDate ToLocalDate(this DateTime dateTime) { 
     return new LocalDate(dateTime.Year, dateTime.Month, dateTime.Day); 
    } 

    public static string Serialize(this ZonedDateTime zonedDateTime) { 
     return LocalDateTimePattern.ExtendedIsoPattern.Format(zonedDateTime.LocalDateTime) + "@O=" + OffsetPattern.GeneralInvariantPattern.Format(zonedDateTime.Offset) + "@Z=" + zonedDateTime.Zone.Id; 
    } 

    public static ZonedDateTime DeserializeZonedDateTime(string value) { 
     var match = ZonedDateTimeRegex.Match(value); 
     if (!match.Success) throw new InvalidOperationException("Could not parse " + value); 
     var dtm = LocalDateTimePattern.ExtendedIsoPattern.Parse(match.Groups[1].Value).Value; 
     var offset = OffsetPattern.GeneralInvariantPattern.Parse(match.Groups[2].Value).Value; 
     var tz = DateTimeZoneProviders.Tzdb.GetZoneOrNull(match.Groups[3].Value); 
     return new ZonedDateTime(dtm, tz, offset); 
    } 

    public static readonly Regex ZonedDateTimeRegex = new Regex(@"^(.*)@O=(.*)@Z=(.*)$"); 
} 

फिर एक ReplacementType वर्ग (धारावाहिक केवल दुकान प्रकार करना चाहिए कि WCF serializer से जाना जाता है), जो धारावाहिक डेटा होता है और WCF पर पारित किया जा सकता है:

public class ReplacementType { 
    [DataMember(Name = "Serialized")] 
    public object Serialized { get; set; } 
    [DataMember(Name = "OriginalType")] 
    public string OriginalTypeFullName { get; set; } 
} 

क्रमबद्धता/अक्रमांकन नियम किराए के लिए नियमों को जोड़ने के लिए, Translator सामान्य कक्षाओं में लिपटे रहे हैं (केवल एक किराए की सेवा endpo को सौंपा गया है पूर्णांक तो यह सभी आवश्यक नियमों को शामिल करना चाहिए):

public abstract class Translator { 
    public abstract object Serialize(object obj); 
    public abstract object Deserialize(object obj); 
} 

public class Translator<TOriginal, TSerialized> : Translator { 
    private readonly Func<TOriginal, TSerialized> _Serialize; 

    private readonly Func<TSerialized, TOriginal> _Deserialize; 

    public Translator(Func<TOriginal, TSerialized> serialize, Func<TSerialized, TOriginal> deserialize) { 
     this._Serialize = serialize; 
     this._Deserialize = deserialize; 
    } 

    public override object Serialize(object obj) { 
     return new ReplacementType { Serialized = this._Serialize((TOriginal)obj), OriginalTypeFullName = typeof(TOriginal).FullName }; 
    } 

    public override object Deserialize(object obj) { 
     return this._Deserialize((TSerialized)obj); 
    } 
} 

अंत में सरोगेट वर्ग, प्रत्येक अनुवाद नियम आसानी से स्थिर निर्माता में जोड़ा जा सकता है:

public class CustomSurrogate : IDataContractSurrogate { 
    /// Type.GetType only works for the current assembly or mscorlib.dll 
    private static readonly Dictionary<string, Type> AllLoadedTypesByFullName = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Distinct().GroupBy(t => t.FullName).ToDictionary(t => t.Key, t => t.First()); 

    public static Type GetTypeExt(string typeFullName) { 
     return Type.GetType(typeFullName) ?? AllLoadedTypesByFullName[typeFullName]; 
    } 

    private static readonly Dictionary<Type, Translator> Translators; 
    static CustomSurrogate() { 
     Translators = new Dictionary<Type, Translator> { 
      {typeof(LocalDate), new Translator<LocalDate, DateTime>(serialize: d => d.ToDateTime(), deserialize: d => d.ToLocalDate())}, 
      {typeof(LocalDateTime), new Translator<LocalDateTime, DateTime>(serialize: d => d.ToDateTimeUnspecified(), deserialize: LocalDateTime.FromDateTime)}, 
      {typeof(ZonedDateTime), new Translator<ZonedDateTime, string> (serialize: d => d.Serialize(), deserialize: DatesExtensions.DeserializeZonedDateTime)} 
     }; 
    } 

    public Type GetDataContractType(Type type) { 
     if (Translators.ContainsKey(type)) { 
      type = typeof(ReplacementType); 
     } 
     return type; 
    } 

    public object GetObjectToSerialize(object obj, Type targetType) { 
     Translator translator; 
     if (Translators.TryGetValue(obj.GetType(), out translator)) { 
      return translator.Serialize(obj); 
     } 
     return obj; 
    } 

    public object GetDeserializedObject(object obj, Type targetType) { 
     var replacementType = obj as ReplacementType; 
     if (replacementType != null) { 
      var originalType = GetTypeExt(replacementType.OriginalTypeFullName); 
      return Translators[originalType].Deserialize(replacementType.Serialized); 
     } 
     return obj; 
    } 

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) { 
     throw new NotImplementedException(); 
    } 

    public object GetCustomDataToExport(Type clrType, Type dataContractType) { 
     throw new NotImplementedException(); 
    } 

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes) { 
     throw new NotImplementedException(); 
    } 

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { 
     throw new NotImplementedException(); 
    } 

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) { 
     throw new NotImplementedException(); 
    } 
} 

और अब यह उपयोग करने के लिए, हम को परिभाषित एक सेवा SurrogateService नामित:

[ServiceContract] 
public interface ISurrogateService { 
    [OperationContract] 
    Tuple<LocalDate, LocalDateTime, ZonedDateTime> GetParams(LocalDate localDate, LocalDateTime localDateTime, ZonedDateTime zonedDateTime); 
} 

public class SurrogateService : ISurrogateService { 
    public Tuple<LocalDate, LocalDateTime, ZonedDateTime> GetParams(LocalDate localDate, LocalDateTime localDateTime, ZonedDateTime zonedDateTime) { 
     return Tuple.Create(localDate, localDateTime, zonedDateTime); 
    } 
} 

ग्राहक और एक ही मशीन पर सर्वर के साथ एक पूरी तरह से स्टैंडअलोन आधार पर चलाने के लिए (एक कंसोल अनुप्रयोग में), हम बस n eed एक स्थिर वर्ग के लिए निम्न कोड जोड़ सकते हैं और समारोह Start() कॉल करने के लिए:

public static class SurrogateServiceTest { 
    public static void DefineSurrogate(ServiceEndpoint endPoint, IDataContractSurrogate surrogate) { 
     foreach (var operation in endPoint.Contract.Operations) { 
      var ob = operation.Behaviors.Find<DataContractSerializerOperationBehavior>(); 
      ob.DataContractSurrogate = surrogate; 
     } 
    } 

    public static void Start() { 
     var baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     var host = new ServiceHost(typeof(SurrogateService), new Uri(baseAddress)); 
     var endpoint = host.AddServiceEndpoint(typeof(ISurrogateService), new BasicHttpBinding(), ""); 
     host.Open(); 
     var surrogate = new CustomSurrogate(); 
     DefineSurrogate(endpoint, surrogate); 

     Console.WriteLine("Host opened"); 

     var factory = new ChannelFactory<ISurrogateService>(new BasicHttpBinding(), new EndpointAddress(baseAddress)); 
     DefineSurrogate(factory.Endpoint, surrogate); 
     var client = factory.CreateChannel(); 
     var now = SystemClock.Instance.Now.InUtc(); 
     var p = client.GetParams(localDate: now.Date, localDateTime: now.LocalDateTime, zonedDateTime: now); 

     if (p.Item1 == now.Date && p.Item2 == now.LocalDateTime && p.Item3 == now) { 
      Console.WriteLine("Success"); 
     } 
     else { 
      Console.WriteLine("Failure"); 
     } 
     ((IClientChannel)client).Close(); 
     factory.Close(); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     host.Close(); 
    } 
} 

देखा! :)

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

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