2010-11-06 5 views
9

Короче говоря, я пытаюсь десериализации JSON ответ от API Bing Maps геокодирования REST,Проблема с десериализации JSON на DataMember «__type»

я создал свой класс ответа, и теперь, когда я пытаюсь на самом деле десериализовать ответ, я получаю следующую ошибку:

Тип '{0}' с именем контракта данных '{1}: {2}' не ожидается. Подумайте об использовании DataContractResolver или добавьте любые типы, не известные статически в список известных типов - например, с помощью атрибута KnownTypeAttribute или путем добавления их в список известных типов, переданных DataContractSerializer.

он пытается десериализациями этой строки JSON, и не:

"__type": "Location:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1", 

Моего класс ответ выглядит следующим образом

 [DataContract] 
     public class GeoResponse 
     { 
      [DataMember(Name = "statusDescription")] 
      public string StatusDescription { get; set; } 
      [DataMember(Name = "statusCode")] 
      public string StatusCode { get; set; } 
      [DataMember(Name = "resourceSets")] 
      public ResourceSet[] resourceSets { get; set; } 

      [DataContract] 
      public class ResourceSet 
      { 


       [DataMember(Name = "__type", IsRequired=false)] 
       public string type { get; set; } 

       [DataMember(Name = "estimatedTotal")] 
       public string EstimatedTotal { get; set; } 

       [DataMember(Name = "resources")] 
       public List<Resources> resources { get; set; } 

       [DataContract] 
       public class Resources 
       { 
        [DataMember(Name = "name")] 
        public string Name { get; set; } 

        [DataMember(Name = "point")] 
        public Point point { get; set; } 

        [DataContract] 
        public class Point 
        { 
         [DataMember(Name = "type")] 
         public string Type { get; set; } 

         [DataMember(Name = "coordinates")] 
         public string[] Coordinates { get; set; } 
        } 

        [DataMember(Name = "address")] 
        public Address address { get; set; } 

        [DataContract] 
        public class Address 
        { 
         [DataMember(Name = "addressLine")] 
         public string AddressLine { get; set; } 

         [DataMember(Name = "countryRegion")] 
         public string CountryRegion { get; set; } 

         [DataMember(Name = "formattedAddress")] 
         public string FormattedAddress { get; set; } 

         [DataMember(Name = "locality")] 
         public string Locality { get; set; } 

         [DataMember(Name = "postalCode")] 
         public string PostalCode { get; set; } 
        } 

        [DataMember(Name = "confidence")] 
        public string Confidence { get; set; } 

        [DataMember(Name = "entityType")] 
        public string EntityType { get; set; } 
       } 

      } 
     } 

    } 

Моего метод я использую для десериализации моего ответа JSON:

private static GeoResponse CallGeoWS(string address) 
{ 
    string url = string.Format(
      "http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1}", 
      HttpUtility.UrlEncode(address), bingkey 
      ); 
    var request = (HttpWebRequest)HttpWebRequest.Create(url); 
    request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); 
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; 
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(GeoResponse));    
    var res = (GeoResponse)serializer.ReadObject(request.GetResponse().GetResponseStream()); 
    return res; 
} 

ответ

20

Прежде всего, обратите внимание, что метод, который вы цитируете (http://dev.virtualearth.net/REST/v1/Locations?q=Wiertzstraat+43+1047+Brussel&key=BingMapsKey), генерирует другой ответ по сравнению с тем, который вы пытаетесь сопоставить с классом DataContract. Ответ описан здесь: http://msdn.microsoft.com/en-us/library/ff701711.aspx

Я создал DataContract для этого ответа:

[DataContract] 
public class LocationQueryResponse 
{ 
    [DataMember] 
    public string authenticationResultCode { get; set; } 
    [DataMember] 
    public string brandLogoUri { get; set; } 
    [DataMember] 
    public string copyright { get; set; } 
    [DataMember] 
    public string statusCode { get; set; } 
    [DataMember] 
    public string statusDescription { get; set; } 
    [DataMember] 
    public string traceId { get; set; } 

    [DataMember] 
    public ResourceSet[] resourceSets { get; set; } 

    [DataContract] 
    public class ResourceSet 
    { 
     [DataMember] 
     public int estimatedTotal { get; set; } 

     [DataMember] 
     public Resource[] resources { get; set; } 

     [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1", Name="Location")] 
     public class Resource 
     { 
      [DataMember] 
      public string __type { get; set; } 

      [DataMember] 
      public double[] bbox { get; set; } 

      [DataMember] 
      public string name { get; set; } 

      [DataMember] 
      public Point point { get; set; } 

      [DataContract] 
      public class Point 
      { 
       [DataMember] 
       public string type { get; set; } 

       [DataMember] 
       public string[] coordinates { get; set; } 
      } 

      [DataMember] 
      public Address address { get; set; } 

      [DataContract] 
      public class Address 
      { 
       [DataMember] 
       public string addressLine { get; set; } 
       [DataMember] 
       public string adminDistrict { get; set; } 
       [DataMember] 
       public string adminDistrict2 { get; set; } 
       [DataMember] 
       public string countryRegion { get; set; } 
       [DataMember] 
       public string formattedAddress { get; set; } 
       [DataMember] 
       public string locality { get; set; } 
       [DataMember] 
       public string postalCode { get; set; } 
      } 

      [DataMember] 
      public string confidence { get; set; } 

      [DataMember] 
      public string entityType { get; set; } 
     } 

    } 
} 

На первой, даже если я создал правильный DataContract, он не работал, и это произвело такое же исключение, что вам представил. После некоторого исследования я обнаружил, что поле «__type» имеет особое значение для DataContractJsonSerializer, обозначая тип, к которому объект должен быть десериализован. Чтобы выполнить эту работу, я добавил атрибуты Name и Namespace в атрибут DataContract класса Resource (проверьте код выше).

У меня есть некоторый опыт работы с WCF и JSON, и я никогда раньше не сталкивался с этой проблемой. Это кажется довольно неясным, и поле __type не похоже на стандартную совместимость, а скорее на специфическую особенность Microsoft. Весьма раздражает тот факт, что поле __type похоже только в некоторых конкретных ситуациях. Например, если в документе JSON у вас есть пробел перед этим, десериализатор будет игнорировать его и не вызывать никаких исключений. У меня было такое пустое пространство в документах, которые я первоначально использовал для тестирования, и поэтому я не получал ошибок в этой точке.

Надеюсь, что этот наконец помог. :)

+0

Он работал как шарм, благодаря тонне, пространство имен фактически фиксировало его. Кажется, что-то уникальное для Microsoft действительно, потому что я сделал то же самое с Google, и Yahoo! API геокодирования и все работает! благодаря! – Entice

+0

Добро пожаловать! Рад, что смог помочь. –

+0

полезно для меня тоже ... миллион спасибо! –