2013-01-04 11 views
7

Ho setacciato la rete per informazioni su questo, ma la maggior parte dei risultati riguarda la creazione di servizi WCF o situazioni in cui il servizio è sotto il vostro controllo.Client WCF come è possibile deserializzare un formato data incompatibile dalla risposta JSON?

Sto costruendo un proxy client WCF per un servizio JSON RESTful che è fuori dal mio controllo. Sto usando il modello base di ServiceContract/DataContract e sto cercando di lasciare che il framework faccia il maggior numero possibile di lavoro.

Principalmente funziona correttamente, ma tutti i campi datetime provenienti da questo servizio esterno sono in un formato particolare, ad es.

{"SomeObject": 
    {"details":"blue and round", "lastmodified":"2013/01/02 23:14:55 +0000"} 
} 

così ottengo un errore:

There was an error deserializing the object of type MyNamespace.SomeObject. DateTime content '2013/01/02 23:14:55 +0000' does not start with '/Date(' and end with ')/' as required for JSON.'.

mio DataContract è:

namespace Marshmallow.WebServices.ServiceModels 
{ 
    [DataContract] 
    public class SomeObject 
    { 
     [DataMember(Name = "details")] 
     public string Details { get; set; } 

     [DataMember(Name = "lastmodified")] 
     public DateTime LastModified { get; set; } 
    } 
} 

mio ServiceContract è:

[ServiceContract] 
public interface ICoolExternalApi 
{ 
    [OperationContract] 
    [WebGet(UriTemplate = "/something.json", 
     ResponseFormat = WebMessageFormat.Json, 
     BodyStyle = WebMessageBodyStyle.Wrapped)] 
    [return: MessageParameter(Name = "SomeObject")] 
    SomeObject GetAccount(); 
} 

Quello che voglio sapere è, dove posso attaccare un po 'di merluzzo e per definire in che modo WCF deve deserializzare il campo lastmodified (creare un oggetto DateTime fuori dalla stringa)?

O meglio ancora, definire come deserializzare tutti i DataTemper DateTime per tutti i miei DataContracts. Non voglio un sacco di codice ripetuto.

Inoltre, non voglio ricorrere a un deserializzatore di terze parti né voglio iniziare a inserire tutto il resto con un metodo di deserializzazione personalizzato, se è evitabile.

+0

Deserializzare su una stringa ha le limitazioni che hai notato. Funzionerà ma è tutt'altro che elegante. Configurare un IDispatchMessageInspector è un po 'più impegnativo, ma dovrebbe essere più pulito. –

+1

Mi sembra di usare un IDispatchMessageInspector non è proprio così elegante. A) Regex è lento e non molto scalabile. B) È un'analisi extra di tutto il corpo di JSON. C) Dovrei convertire le stringhe datetime in "that" format "\/Date (1297293089984-0800) \ /" che verrebbe poi analizzato di nuovo per riempire il DataMember (doppia elaborazione). D) È un hack. Sicuramente ci deve essere un'altra funzionalità WCF che non capisco (OnDeserializing o qualcosa del genere?) Che è stata progettata per affrontare queste situazioni? –

risposta

1

Finora questo è il meglio che hanno creato:

Ho un metodo di stringa di estensione interna:

internal static class DeserializationHelper 
{ 
    internal static DateTime GetDeserializedDateTime(this string @string) 
    { 
     if (string.IsNullOrEmpty(@string)) return default(DateTime); 
     //insert complex custom deserialization logic here 
     return DateTime.Parse(@string); 
    } 

} 

Questa è la configurazione DataMember:

[DataMember(Name = "lastmodified")] 
internal string _LastModified 
{ 
    set { LastModified = value.GetDeserializedDateTime(); } 
    //getter is not needed for receiving data but WCF requires one 
    get { return default(string); } 
} 

public DateTime LastModified { get; private set; } 

Se si desidera utilizzare questo DataContract per inviare dati (rendere questa una proprietà scrivibile), è necessario scrivere un metodo di estensione DateTime (GetSerialized DateString), espandere i setter/getter e introdurre membri privati ​​come intermediari.

Ha un odore di copia e incolla e non sfrutta le caratteristiche della struttura WCF. Cosa farebbe Bill Gates?

2

Due cose mi vengono in mente:

  1. Change LastModified di essere una stringa e quindi convertirlo in un Datetime opporsi da soli. Significherebbe esporre due proprietà per gli stessi dati sul tuo oggetto.
  2. Scrivere un IDispatchMessageInspector per intercettare il messaggio prima della deserializzazione e massaggiare il messaggio non elaborato utilizzando espressioni regolari. Permetterebbe una soluzione unica per tutte le date del tuo servizio.
+0

Grazie per l'input. 1) Finora questo è quello che sto facendo, mantenendo la proprietà della stringa interna. Richiede una codifica aggiuntiva per ogni DataMember DateTime, tuttavia, per me ha un cattivo odore. 2) Mentre funzionava, sembra un trucco e introduce un sovraccarico che comprometterebbe la scalabilità. –

Problemi correlati