如何使用 WCF DataContracts 自动反序列化 Yahoo GeoPlanet REST XML
我是 WCF 新手。我能够成功地为 GeoNames 服务创建一个客户端,但现在我尝试为 Yahoo GeoPlanet 做同样的事情,我似乎无法将 XML 反序列化为我的 DataContract 类型。这样做的正确方法是什么?以下是我正在处理的内容:
示例 REST 响应:
<places xmlns="http://where.yahooapis.com/v1/schema.rng"
xmlns:yahoo="http://www.yahooapis.com/v1/base.rng"
yahoo:start="0" yahoo:count="247" yahoo:total="247">
<place yahoo:uri="http://where.yahooapis.com/v1/place/23424966"
xml:lang="en-US">
<woeid>23424966</woeid>
<placeTypeName code="12">Country</placeTypeName>
<name>Sao Tome and Principe</name>
</place>
<place yahoo:uri="http://where.yahooapis.com/v1/place/23424824"
xml:lang="en-US">
<woeid>23424824</woeid>
<placeTypeName code="12">Country</placeTypeName>
<name>Ghana</name>
</place>
...
</places>
合约接口和合约接口客户端:
[ServiceContract]
public interface IConsumeGeoPlanet
{
[OperationContract]
[WebGet(
UriTemplate = "countries?appid={appId}",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare
)]
GeoPlanetResults<GeoPlanetPlace> Countries(string appId);
}
public sealed class GeoPlanetConsumer : ClientBase<IConsumeGeoPlanet>
{
public GeoPlanetResults<GeoPlanetPlace> Countries(string appId)
{
return Channel.Countries(appId);
}
}
反序列化类型:
[DataContract(Name = "places",
Namespace = "http://where.yahooapis.com/v1/schema.rng")]
public sealed class GeoPlanetResults<T> : IEnumerable<T>
{
public List<T> Items { get; set; }
public IEnumerator<T> GetEnumerator()
{
return Items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[DataContract]
public class GeoPlanetPlace
{
[DataMember(Name = "woeid")]
public int WoeId { get; set; }
[DataMember(Name = "placeTypeName")]
public string Type { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
}
我知道这是错误的。在我的 geonames 客户端中,我的 GeoNamesResults 类有一个没有属性的 [DataContract]
属性,以及 上的
属性。但这对 GeoPlanet 不起作用,我不断收到反序列化异常。我可以让 [DataMember(Name = "geonames")]
属性ItemsCountries(appId)
方法无异常地执行的唯一方法是将名称和命名空间放入 DataContract 属性中。但是,当我这样做时,我不知道如何将结果反序列化到 Items 集合中(它为空)。
我应该怎么办?
I am new to WCF. I was able to successfully create a client for the GeoNames service, but now that I am trying to do the same for Yahoo GeoPlanet, I can't seem to get the XML to deserialize into my DataContract types. What is the right way to do this? Here is what I am working with:
Sample REST response:
<places xmlns="http://where.yahooapis.com/v1/schema.rng"
xmlns:yahoo="http://www.yahooapis.com/v1/base.rng"
yahoo:start="0" yahoo:count="247" yahoo:total="247">
<place yahoo:uri="http://where.yahooapis.com/v1/place/23424966"
xml:lang="en-US">
<woeid>23424966</woeid>
<placeTypeName code="12">Country</placeTypeName>
<name>Sao Tome and Principe</name>
</place>
<place yahoo:uri="http://where.yahooapis.com/v1/place/23424824"
xml:lang="en-US">
<woeid>23424824</woeid>
<placeTypeName code="12">Country</placeTypeName>
<name>Ghana</name>
</place>
...
</places>
Contract Interface & Client:
[ServiceContract]
public interface IConsumeGeoPlanet
{
[OperationContract]
[WebGet(
UriTemplate = "countries?appid={appId}",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare
)]
GeoPlanetResults<GeoPlanetPlace> Countries(string appId);
}
public sealed class GeoPlanetConsumer : ClientBase<IConsumeGeoPlanet>
{
public GeoPlanetResults<GeoPlanetPlace> Countries(string appId)
{
return Channel.Countries(appId);
}
}
Deserialization Types:
[DataContract(Name = "places",
Namespace = "http://where.yahooapis.com/v1/schema.rng")]
public sealed class GeoPlanetResults<T> : IEnumerable<T>
{
public List<T> Items { get; set; }
public IEnumerator<T> GetEnumerator()
{
return Items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[DataContract]
public class GeoPlanetPlace
{
[DataMember(Name = "woeid")]
public int WoeId { get; set; }
[DataMember(Name = "placeTypeName")]
public string Type { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
}
I know this is wrong. In my geonames client, my GeoNamesResults class has a [DataContract]
attribute with no properties, and a [DataMember(Name = "geonames")]
attribute on the Items
property. This doesn't work for GeoPlanet though, I kept getting deserialization exceptions. The only way I could get the Countries(appId)
method to execute without exceptions was by putting the Name and Namespace in the DataContract attribute. However when I do this, I have no idea how to get the results deserialized into the Items collection (it is null).
What should I do?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
DataContractSerializer
不支持完整的 XML 规范,仅支持其中的一个子集。它不支持的是属性,这些属性在您展示的示例响应中广泛使用。在这种情况下,您需要使用XmlSerializer
,并相应地定义类型(使用System.Xml.Serialization
中的属性,而不是>系统.运行时.序列化
)。下面的代码显示了如何检索您发布的示例 XML。The
DataContractSerializer
doesn't support the full XML specification, only a subset of it. On thing it doesn't support is attributes, which are used extensively in the sample response you showed. In this case, you'll need to use theXmlSerializer
, and define the types accordingly (using the attributes inSystem.Xml.Serialization
, instead of the ones onSystem.Runtime.Serialization
). The code below shows how to retrieve the sample XML you posted.