2013-01-04 20 views
7

Przeszukałem sieć, aby uzyskać informacje na ten temat, ale większość wyników dotyczy tworzenia usług WCF lub sytuacji, w których usługa jest pod Twoją kontrolą.Klient WCF w jaki sposób można deserializować niezgodny format daty z odpowiedzi JSON?

Buduję proxy klienta WCF dla usługi RESTful JSON, która jest poza moją kontrolą. Korzystam z podstawowego wzorca ServiceContract/DataContract i próbuję pozwolić ramie wykonać jak najwięcej pracy, jak to możliwe.

Przeważnie działa to dobrze, ale wszystkie pola datetime pochodzące z tej usługi zewnętrznej są w określonym formacie, np.

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

Więc pojawia się błąd:

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.'.

Moja DataContract brzmi:

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

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

Moja ServiceContract brzmi:

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

Co chcę wiedzieć, gdzie mogę wbić trochę dorsza e, aby zdefiniować, w jaki sposób WCF powinno deserializować ostatnio zmodyfikowane pole (uczynić obiekt DateTime poza ciągiem znaków)?

Albo jeszcze lepiej, zdefiniuj sposób deserializacji wszystkich modułów DataTime DataMembers dla wszystkich moich umów danych. Nie chcę wielu powtarzających się kodów.

Nie chcę też uciekać się do jakiegoś zewnętrznego deserializera, ani nie chcę zaczynać od umieszczania wszystkiego przez niestandardową metodę deserializacji, jeśli można tego uniknąć.

+0

Deserializacja na łańcuch ma swoje ograniczenia, które zauważyliście. To zadziała, ale daleko mu do elegancji. Konfigurowanie IDispatchMessageInspector to trochę więcej wysiłku, ale powinno być czystsze. –

+1

Mam ochotę używać IDispatchMessageInspector nie jest tak elegancko. A) Regex jest powolny i niezbyt skalowalny. B) Jest to dodatkowa analiza całego ciała JSONA. C) Musiałbym zamienić łańcuchy datetime na "ten" format "\/Date (1297293089984-0800) \ /", który następnie zostałby ponownie przeanalizowany w celu uzupełnienia danych DataMember (podwójne przetwarzanie). D) To jest hack. Z pewnością musi istnieć inna funkcja WCF, której nie rozumiem (OnDeserializing czy coś takiego?), Która ma na celu radzenie sobie z takimi sytuacjami? –

Odpowiedz

1

Jak dotąd jest to najlepszy I mają pochodzić z:

Mam metody wewnętrznych ciąg rozszerzenia:

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); 
    } 

} 

Jest to konfiguracja 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; } 

Jeśli chcesz użyć tej DataContract do wysyłania danych (uczyń to właściwość do zapisu), musisz napisać metodę rozszerzenia DateTime (GetSerialized DateString), rozwiń setery/pobierające i wprowadź prywatnych członków jako pośredników.

Pachnie cięciem i wklejaniem i nie korzysta z żadnych funkcji frameworka WCF. Co zrobi Bill Gates?

2

dwie rzeczy mogę myśleć:

  1. Zmień LastModified być ciągiem, a następnie przekształcić go w obiekt DateTime siebie. Oznaczałoby to wystawienie dwóch właściwości dla tych samych danych na twoim obiekcie.
  2. Napisz IDispatchMessageInspector, aby przechwycić wiadomość przed wystąpieniem deserializacji i masuj nieprzetworzoną wiadomość za pomocą wyrażeń regularnych. Umożliwiłoby to rozwiązanie jednego zatrzymania dla wszystkich dat w twojej usłudze.
+0

Dzięki za twój wkład. 1) Do tej pory robię to, zachowując wewnętrzną właściwość string. Wymaga to jednak dodatkowego kodowania dla każdego DateTime DataMember, więc pachnie to bardzo źle. 2) 2) Gdyby to działało, to wygląda jak włamanie i wprowadza narzut, który zagroziłby skalowalności. –