在数据成员“__type"上反序列化 JSON 的问题; [英] Problem with deserializing JSON on datamember "__type"

查看:16
本文介绍了在数据成员“__type"上反序列化 JSON 的问题;的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之,我正在尝试反序列化来自 Bing Maps Geocoding REST API 的 JSON 响应,

In short, i'm trying to deserialize a JSON response from the Bing Maps Geocoding REST API,

我创建了我的响应类,现在当我尝试实际反序列化响应时,我收到以下错误:

I created my Response Class, and now when I'm trying to actually deserialize a response, i'm getting the following error:

类型{0}"和数据协定名称{1}:{2}"不是预期的.考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 knownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中.

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.

它试图反序列化这行 JSON,但失败了:

it's trying to deserialize this line of JSON, and fails:

"__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; }
                }

            }
        }

    }

我用来反序列化我的 JSON 响应的方法:

My method i'm using to deserialize my JSON response:

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

推荐答案

首先请注意你引用的方法( http://dev.virtualearth.net/REST/v1/Locations?q=Wiertzstraat+43+1047+Brussel&key=BingMapsKey ),生成与您尝试使用 DataContract 类映射的响应不同的响应.此处描述了响应:http://msdn.microsoft.com/en-us/library/ff701711.aspx

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

我为该响应创建了一个 DataContract:

I have created a DataContract for that response:

[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 属性添加到 Resource 类的 DataContract 属性中(请检查上面的代码).

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

我在 WCF 和 JSON 方面有相当多的经验,以前从未遇到过这个问题.这似乎是一个晦涩难懂的字段,而且 __type 字段似乎不符合标准,而是 Microsoft 的特定功能.相当烦人的是 __type 字段似乎只在某些特定情况下.例如,如果在 JSON 文档中前面有空格,反序列化器将忽略它并且不会抛出任何异常.我最初用于测试的文档中有这样一个空白区域,这就是为什么我当时没有出现错误的原因.

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.

希望这个最终有帮助.:)

Hope this one finally helped. :)

这篇关于在数据成员“__type"上反序列化 JSON 的问题;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆