尝试创建Web API服务,以允许我的网站通过javascript访问外部XML Feed(避免相同的原始策略问题)。这些feed返回原始XML,如下所示(使用Fiddler捕获):
请求:
GET http://wxdata.weather.com/wxdata/search/search?where=london HTTP/1.1
Host: wxdata.weather.com
Connection: Keep-Alive
响应:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml;charset=UTF-8
X-Varnish: 3773154810
X-Cache-Hits: 0
Cache-Control: max-age=55
Date: Wed, 27 Nov 2013 19:52:24 GMT
Content-Length: 504
Connection: keep-alive
<search ver="3.0">
<loc id="UKXX0085" type="1">London, GLA, United Kingdom</loc><loc id="USAL2905" type="1">London, AL</loc><loc id="USAR0340" type="1">London, AR</loc><loc id="USCA9301" type="1">London, CA</loc><loc id="USIN2109" type="1">London, IN</loc><loc id="USKY1090" type="1">London, KY</loc><loc id="USMI2014" type="1">London, MI</loc><loc id="USMN2182" type="1">London, MN</loc><loc id="USMO2769" type="1">London, MO</loc><loc id="USOH0520" type="1">London, OH</loc>
</search>
我希望使用Web API的内容协商功能。但是,根据响应的原始XML提要,我不确定控制器应该返回哪种类型。
public class SearchController : ApiController
{
public string Get(string location)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://wxdata.weather.com");
HttpResponseMessage resp = client.GetAsync(String.Format("wxdata/search/search?where={0}", location)).Result;
resp.EnsureSuccessStatusCode();
// Need help here
}
}
我尝试了几种变体(通过ReadAsStringAsync的字符串,通过LoadXml的XmlDocument,通过JsonConvert.SerializeXmlNode的字符串等)。到目前为止,我尝试过的方法都不适用于Accept:application / xml和Accept:application / json请求。一种接受类型起作用,而另一种接受类型产生异常或未按请求格式化的结果。
我是Web API的新手。我见过的所有内容似乎都建议将数据转换为适当的CLR类型,然后内容协商应该处理其余的事情。只是不确定如何处理这个原始XML提要。我希望控制器根据请求返回正确的JSON或正确的XML(基本上是从原始源传递原始XML)。
有什么建议吗?
答案 0 :(得分:2)
好吧,因为这个问题是Tumbleweed,我会发布我自己发现的答案......
我发现this(以及其他)帮助了.NET XML序列化/反序列化的基础。我尝试使用xsd.exe
,但结果令人失望。但是从这个基础开始,我为XML feed创建了一个CLR类型:
[XmlRoot("search")]
public class SearchTag
{
[XmlAttribute("ver")]
public string ver { get; set; }
[XmlElement("loc")]
public SearchLocTag[] loc { get; set; }
}
public class SearchLocTag
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("type")]
public string type { get; set; }
[XmlText]
public string text { get; set; }
}
默认的序列化程序XMLMediaTypeFormatter使用(DataContractSerializer)对标记名称和插入的不需要的XmlSerializerNamespaces信息做了不合需要的事情。但是我找到了this并创建了一个自定义的XmlObjectSerializer:
public class SearchSerializer : XmlObjectSerializer
{
XmlSerializer serializer;
public SearchSerializer()
{
this.serializer = new XmlSerializer(typeof(SearchTag));
}
public override void WriteObject(XmlDictionaryWriter writer, object graph)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer.Serialize(writer, graph, ns);
}
public override bool IsStartObject(XmlDictionaryReader reader)
{
throw new NotImplementedException();
}
public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
{
throw new NotImplementedException();
}
public override void WriteEndObject(XmlDictionaryWriter writer)
{
throw new NotImplementedException();
}
public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
{
throw new NotImplementedException();
}
public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
{
throw new NotImplementedException();
}
}
然后将其添加到Global.asax.cs:
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SetSerializer<SearchTag>(new SearchSerializer());
然后控制器变成了:
public class SearchController : ApiController
{
public HttpResponseMessage Get(string location)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://wxdata.weather.com");
HttpResponseMessage response = client.GetAsync(String.Format("wxdata/search/search?where={0}", location)).Result;
response.EnsureSuccessStatusCode();
var stream = response.Content.ReadAsStreamAsync().Result;
var serializer = new XmlSerializer(typeof(SearchTag));
using (var reader = new XmlTextReader(stream))
{
if (serializer.CanDeserialize(reader))
{
var xmlData = (SearchTag)serializer.Deserialize(reader);
return Request.CreateResponse<SearchTag>(HttpStatusCode.OK, xmlData);
}
else
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
}
}
}
生成的application / xml消息:
请求
GET http://localhost:53047/twc/search/london HTTP/1.1
User-Agent: Fiddler
Accept: application/xml
Host: localhost:53047
响应
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcQ2xheXRvblxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEzXFByb2plY3RzXFR3Y0FwaVx0d2Ncc2VhcmNoXGxvbmRvbg==?=
X-Powered-By: ASP.NET
Date: Wed, 04 Dec 2013 21:42:46 GMT
Content-Length: 484
<search ver="3.0"><loc id="UKXX0085" type="1">London, GLA, United Kingdom</loc><loc id="USAL2905" type="1">London, AL</loc><loc id="USAR0340" type="1">London, AR</loc><loc id="USCA9301" type="1">London, CA</loc><loc id="USIN2109" type="1">London, IN</loc><loc id="USKY1090" type="1">London, KY</loc><loc id="USMI2014" type="1">London, MI</loc><loc id="USMN2182" type="1">London, MN</loc><loc id="USMO2769" type="1">London, MO</loc><loc id="USOH0520" type="1">London, OH</loc></search>
生成的application / json消息:
请求
GET http://localhost:53047/twc/search/london HTTP/1.1
User-Agent: Fiddler
Accept: application/json
Host: localhost:53047
响应
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcQ2xheXRvblxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEzXFByb2plY3RzXFR3Y0FwaVx0d2Ncc2VhcmNoXGxvbmRvbg==?=
X-Powered-By: ASP.NET
Date: Wed, 04 Dec 2013 21:43:18 GMT
Content-Length: 528
{"ver":"3.0","loc":[{"id":"UKXX0085","type":"1","text":"London, GLA, United Kingdom"},{"id":"USAL2905","type":"1","text":"London, AL"},{"id":"USAR0340","type":"1","text":"London, AR"},{"id":"USCA9301","type":"1","text":"London, CA"},{"id":"USIN2109","type":"1","text":"London, IN"},{"id":"USKY1090","type":"1","text":"London, KY"},{"id":"USMI2014","type":"1","text":"London, MI"},{"id":"USMN2182","type":"1","text":"London, MN"},{"id":"USMO2769","type":"1","text":"London, MO"},{"id":"USOH0520","type":"1","text":"London, OH"}]}
这正是我追求的目标。