c# - 在数据成员 "__type"上反序列化 JSON 时出现问题

标签 c# visual-studio json serialization

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

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

不应使用数据协定名称“{1}:{2}”键入“{0}”。考虑使用 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;
}

最佳答案

首先,请注意您引用的方法 ( 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 属性添加到 Resource 类的 DataContract 属性中(请检查上面的代码)。

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

希望这篇文章最终有所帮助。 :)

关于c# - 在数据成员 "__type"上反序列化 JSON 时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4115037/

相关文章:

c# - 如何从类(class)内部向 BackgroundWorker 报告进度?

c++ - Visual C++ 2008 - 无法命中断点

visual-studio - 使用TFS从VS中删除断点后剩余的断点

javascript - 将新对象添加到传入的 json 字符串

c# - 持久登录 Microsoft-Graph c# SDK

c# - 使用 UnityContainer 进行动态 IOC 映射 - 如何实现?

c# - 在 C# 中使用查询数据类型

c# - SVCUtil 或 WSDL 批处理

java - 从 YouTube API 解析 JSON

javascript - 如何使用 JavaScript 将数据从 HTML 表单发送到 Google 电子表格?