【问题标题】:Problem with deserializing JSON on datamember "__type"在数据成员“__type”上反序列化 JSON 的问题
【发布时间】:2010-11-06 20:35:00
【问题描述】:

简而言之,我正在尝试反序列化来自 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;
}

【问题讨论】:

    标签: c# visual-studio json serialization


    【解决方案1】:

    首先,请注意,您引用的方法 (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:

    [数据合约]
    公共类 LocationQueryResponse
    {
        [数据成员]
        公共字符串 authenticationResultCode { get;放; }
        [数据成员]
        公共字符串 brandLogoUri { 获取;放; }
        [数据成员]
        公共字符串版权{获取;放; }
        [数据成员]
        公共字符串状态码 { 获取;放; }
        [数据成员]
        公共字符串状态描述 { 获取;放; }
        [数据成员]
        公共字符串 traceId { 获取;放; }
    
        [数据成员]
        公共资源集 [] 资源集 { 获取;放; }
    
        [数据合约]
        公共类资源集
        {
            [数据成员]
            公共 int 估计总计 { 得到;放; }
    
            [数据成员]
            公共资源 [] 资源 { 获取;放; }
    
            [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1", Name="Location")]
            公共类资源
            {
                [数据成员]
                公共字符串 __type { 获取;放; }
    
                [数据成员]
                公共双[] bbox { 得到;放; }
    
                [数据成员]
                公共字符串名称 { 获取;放; }
    
                [数据成员]
                公共点点{得到;放; }
    
                [数据合约]
                公共课点
                {
                    [数据成员]
                    公共字符串类型 { 获取;放; }
    
                    [数据成员]
                    公共字符串 [] 坐标 { 获取;放; }
                }
    
                [数据成员]
                公共地址地址 { 获取;放; }
    
                [数据合约]
                公开课地址
                {
                    [数据成员]
                    公共字符串地址线 { 获取;放; }
                    [数据成员]
                    公共字符串 adminDistrict { 获取;放; }
                    [数据成员]
                    公共字符串 adminDistrict2 { 获取;放; }
                    [数据成员]
                    公共字符串 countryRegion { 获取;放; }
                    [数据成员]
                    公共字符串 formattedAddress { get;放; }
                    [数据成员]
                    公共字符串位置 { 获取;放; }
                    [数据成员]
                    公共字符串邮政编码 { 获取;放; }
                }
    
                [数据成员]
                公共字符串置信度 { 得到;放; }
    
                [数据成员]
                公共字符串实体类型 { 获取;放; }
            }
    
        }
    }
    

    起初,即使我创建了正确的 DataContract,它也不起作用,并且生成了与您提出的相同的异常。经过一番研究,我发现“__type”字段对于DataContractJsonSerializer有特殊的含义,表示对象应该被反序列化的类型。为了完成这项工作,我将 Name 和 Namespace 属性添加到 Resource 类的 DataContract 属性(请检查上面的代码)。

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

    希望这个终于有所帮助。 :)

    【讨论】:

    • 它就像一个魅力,感谢一吨,命名空间实际上修复了它。似乎确实是微软独有的东西,因为我对谷歌和雅虎做了同样的事情!地理编码API,一切正常!谢谢!
    • 谢谢一堆家伙。把我从挫折中解救出来
    • 据我了解,__type 值仅在对象中排在第一位时才重要。如果它有任何其他位置,则不会抛出异常并且解析器不会将其视为特殊值。
    • 你太棒了。谢谢!我不得不更改代码中的一些引用,但与找出问题相比,这很容易。
    猜你喜欢
    • 2020-03-09
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 2021-05-28
    • 1970-01-01
    相关资源
    最近更新 更多