问题反序列化JSON的数据成员" __类型" [英] Problem with deserializing JSON on datamember "__type"

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

问题描述

在短,我想要序列化从Bing地图地理编码REST API,

JSON响应

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

输入{0}的数据协定名称{1}:{2}预计不会。考虑使用DataContractResolver或者添加静态已知到已知类型的列表中的任何类型的不 - 例如,通过使用KnownTypeAttribute属性或通过将其添加到已知类型传递给DataContractSerializer列表

这是尝试反序列化这一行的JSON,并失败:

 __类型:位置:http:\\ / \\ / schemas.microsoft.com \\ /搜索\\ /本地\\ / WS \\ /休息\\ / V1,

我的回答类看起来像这样

  [DataContract]
        公共类GeoResponse
        {
            [数据成员(NAME =状态说明)]
            公共字符串状态说明{搞定;组; }
            [数据成员(NAME =状态code)]
            公共字符串状态code {搞定;组; }
            [数据成员(NAME =resourceSets)]
            公众的ResourceSet [] {resourceSets获得;组; }            [DataContract]
            公共类的ResourceSet
            {
                [数据成员(NAME =__type,IsRequired = FALSE)]
                公共字符串类型{搞定;组; }                [数据成员(NAME =estimatedTotal)]
                公共字符串EstimatedTotal {搞定;组; }                [数据成员(NAME =资源)]
                公开名单<资源与GT;资源{搞定;组; }                [DataContract]
                公共类资源
                {
                    [数据成员(名称=名称)]
                    公共字符串名称{;组; }                    [数据成员(名称为点)]
                    公共点对点{搞定;组; }                    [DataContract]
                    公共类点
                    {
                        [数据成员(名称=类型)]
                        公共字符串类型{搞定;组; }                        [数据成员(NAME =坐标)]
                        公共字符串[] {坐标获取;组; }
                    }                    [数据成员(NAME =地址)]
                    公共广播地址{搞定;组; }                    [DataContract]
                    公共类地址
                    {
                        [数据成员(NAME =addressLine)]
                        公共字符串AddressLine {搞定;组; }                        [数据成员(NAME =COUNTRYREGION)]
                        公共字符串COUNTRYREGION {搞定;组; }                        [数据成员(NAME =formattedAddress)]
                        公共字符串FormattedAddress {搞定;组; }                        [数据成员(名称=本地)]
                        公共字符串局部性{搞定;组; }                        [数据成员(NAME =邮政code)]
                        公共字符串邮政code {搞定;组; }
                    }                    [数据成员(名称为信心)]
                    公共字符串信心{搞定;组; }                    [数据成员(NAME =的EntityType)]
                    公共字符串的EntityType {搞定;组; }
                }            }
        }    }

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

 私有静态GeoResponse CallGeoWS(字符串地址)
{
    字符串的URL =的String.Format(
            http://dev.virtualearth.net/REST/v1/Locations?q={0}&key={1},
            HttpUtility.UrlEn code(地址),bingkey
            );
    VAR请求=(HttpWebRequest的)HttpWebRequest.Create(URL);
    request.Headers.Add(HTT prequestHeader.AcceptEncoding,gzip的,放气);
    request.AutomaticDecom pression = DECOM pressionMethods.GZip | DECOM pressionMethods.Deflate;
    DataContractJsonSerializer序列化=新DataContractJsonSerializer(typeof运算(GeoResponse));
    VAR解析度=(GeoResponse)serializer.ReadObject(request.GetResponse()GetResponseStream());
    返回水库;
}


解决方案

首先,请注意方法,则需要引用(<一个href=\"http://dev.virtualearth.net/REST/v1/Locations?q=Wiertzstraat+43+1047+Brussel&key=BingMapsKey\">http://dev.virtualearth.net/REST/v1/Locations?q=Wiertzstraat+43+1047+Brussel&key=BingMapsKey ),产生相对于你想与你的DataContract类映射一个不同的反应。响应被描述如下:<一href=\"http://msdn.microsoft.com/en-us/library/ff701711.aspx\">http://msdn.microsoft.com/en-us/library/ff701711.aspx

我创建了一个DataContract为回应:

 [DataContract]
公共类LocationQueryResponse
{
    [数据成员]
    公共字符串authenticationResult code {搞定;组; }
    [数据成员]
    公共字符串brandLogoUri {搞定;组; }
    [数据成员]
    公共字符串版权{搞定;组; }
    [数据成员]
    公共字符串状态code {搞定;组; }
    [数据成员]
    公共字符串状态说明{搞定;组; }
    [数据成员]
    公共字符串traceId {搞定;组; }    [数据成员]
    公众的ResourceSet [] {resourceSets获得;组; }    [DataContract]
    公共类的ResourceSet
    {
        [数据成员]
        公众诠释estimatedTotal {搞定;组; }        [数据成员]
        公共资源[] {资源获取;组; }        [DataContract(命名空间=htt​​p://schemas.microsoft.com/search/local/ws/rest/v1,名称=位置)
        公共类资源
        {
            [数据成员]
            公共字符串__type {搞定;组; }            [数据成员]
            市民双[] {BBOX获得;组; }            [数据成员]
            公共字符串名称{;组; }            [数据成员]
            公共点对点{搞定;组; }            [DataContract]
            公共类点
            {
                [数据成员]
                公共字符串类型{搞定;组; }                [数据成员]
                公共字符串[] {坐标获取;组; }
            }            [数据成员]
            公共广播地址{搞定;组; }            [DataContract]
            公共类地址
            {
                [数据成员]
                公共字符串addressLine {搞定;组; }
                [数据成员]
                公共字符串adminDistrict {搞定;组; }
                [数据成员]
                公共字符串adminDistrict2 {搞定;组; }
                [数据成员]
                公共字符串COUNTRYREGION {搞定;组; }
                [数据成员]
                公共字符串formattedAddress {搞定;组; }
                [数据成员]
                公共字符串局部性{搞定;组; }
                [数据成员]
                公共字符串邮政code {搞定;组; }
            }            [数据成员]
            公共字符串的信心{搞定;组; }            [数据成员]
            公共字符串的EntityType {搞定;组; }
        }    }
}

起初,即使我创建了一个正确的DataContract,它不工作,它产生你presented相同的异常。经过一番研究,我发现,__type字段有DataContractJsonSerializer特殊的意义,表示要将对象应进行反序列化的类型。为了使这项工作,我添加名称和命名空间属性的资源类的属性DataContract(请检查code以上)。

我有一个WCF和JSON颇有些经验和过这个问题之前从来没有来。这似乎是一个相当不起眼的一个和__type领域似乎并不成为符合标准,而是一个微软特定的功能。很烦人的事实是,在__type字段在某些特定的情况下似乎只。例如,如果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:

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.

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

            }
        }

    }

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

解决方案

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

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

    }
}

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

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

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

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