visual-studio 在数据成员“__type”上反序列化 JSON 的问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4115037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Problem with deserializing JSON on datamember "__type"
提问by Entice
In short, i'm trying to deserialize a JSON response from the Bing Maps Geocoding REST API,
简而言之,我正在尝试反序列化来自 Bing Maps Geocoding REST API 的 JSON 响应,
I created my Response Class, and now when I'm trying to actually deserialize a response, i'm getting the following error:
我创建了我的响应类,现在当我尝试实际反序列化响应时,我收到以下错误:
Type '{0}' with data contract name '{1}:{2}' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
使用数据协定名称“{1}”键入“{0}”:{2}”不是预期的。考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 knownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。
it's trying to deserialize this line of JSON, and fails:
它试图反序列化这行 JSON,但失败了:
"__type": "Location:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
My response class looks like this
我的响应类看起来像这样
[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; }
}
}
}
}
My method i'm using to deserialize my JSON response:
我用来反序列化我的 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;
}
回答by Florin Dumitrescu
First of all, please note that the method you are quoting ( http://dev.virtualearth.net/REST/v1/Locations?q=Wiertzstraat+43+1047+Brussel&key=BingMapsKey), generates a different response compared to the one you are trying to map with your DataContract class. The response is described here: http://msdn.microsoft.com/en-us/library/ff701711.aspx
首先,请注意您引用的方法(http://dev.virtualearth.net/REST/v1/Locations?q=Wiertzstraat+43+1047+Brussel&key=BingMapsKey)生成的响应与那个不同您正在尝试使用您的 DataContract 类进行映射。此处描述了响应:http: //msdn.microsoft.com/en-us/library/ff701711.aspx
I have created a DataContract for that response:
我为该响应创建了一个 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; }
}
}
}
At first, even if I created a correct DataContract, it did not work and it generated the same exception that you presented. After some research I found that the "__type" field has a special meaning for DataContractJsonSerializer, denoting the type to which the object should be deserialized. In order to make this work I added Name and Namespace attributes to the DataContract attribute of the Resource class (please check code above).
起初,即使我创建了正确的 DataContract,它也不起作用,并且生成了与您呈现的相同的异常。经过一些研究,我发现“__type”字段对 DataContractJsonSerializer 具有特殊含义,表示对象应该反序列化的类型。为了完成这项工作,我将 Name 和 Namespace 属性添加到 Resource 类的 DataContract 属性中(请检查上面的代码)。
I have quite some experience with WCF and JSON and never came across this problem before. It seems to be quite an obscure one and the __type field doesn't seem to be standard compliant, but rather a Microsoft specific feature. Quite annoying is the fact that the __type field seem to only in some specific situations. For example, if in the JSON document you have white space before it, the deserializer would ignore it and not throw any exception. I had such a white space in the documents I have initially used for testing and this why I did not get errors at that point.
我在 WCF 和 JSON 方面有很多经验,以前从未遇到过这个问题。这似乎是一个晦涩难懂的字段,而且 __type 字段似乎不符合标准,而是 Microsoft 的特定功能。相当烦人的是 __type 字段似乎只在某些特定情况下。例如,如果在 JSON 文档中前面有空格,反序列化器将忽略它并且不会抛出任何异常。我最初用于测试的文档中有这样一个空白区域,这就是为什么我当时没有出错的原因。
Hope this one finally helped. :)
希望这个最终有帮助。:)

