我有一个实现REST API的ASP.NET MVC4网站,我正在从客户端应用程序中使用它。我的ApiController方法以XML格式接收和返回复杂对象。
我最近发现了RestSharp,并且已经开始将我的客户端项目移到那里了。但是,我遇到了真正的问题。它似乎几乎工作 - 它非常接近我几乎可以尝到成功 - 但我无法让它100%工作。
我穿过电线的物体看起来像这样:
// The object I'm passing across the wire
public class Example
{
bool IsActive { get; set; }
string Name { get; set; }
}
我的ApiController方法如下所示:
// My ApiController method
public HttpResponseMessage PostExample(Example example)
{
if (ModelState.IsValid)
{
db.Examples.Add(example);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, example);
return response;
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
当我尝试将对象发布到我的网站时出现问题,如下所示:
var example = new Example () { IsActive = true, Name = "foo" };
var request = new RestSharp.RestRequest("/api/example", RestSharp.Method.POST);
request.AddBody(example, XmlNamespace);
var client = new RestClient();
client.BaseUrl = "foo.com";
var response = client.Execute<Example>(request);
上面的代码确实点击了我的ApiController中的PostExample方法,它有一个Example对象作为参数。 但是 Example对象的属性值与我传递给Execute方法的值不同!在一种情况下,IsActive成员是false而不是true,尽管我也看到了一个名称成员为null的情况,它应该有一个值。
我使用Fiddler进行了一些调查,似乎在RestSharp生成的XML中创建了正确的值 。但是,XML与执行GET时Web服务器发出的格式不完全相同。差异是微妙的,但似乎使它工作和不工作之间的差异。 Web服务器端的框架似乎对这些格式差异敏感,并且因此错误地解释了XML。
这是我从RestSharp获得的XML:
<Example xmlns="http://schemas.datacontract.org/2004/07/ExampleNamespace">
<Name>foo</Name>
<IsActive>true</IsActive>
</Example>
这是我在网络服务器上进行GET时所获得的(或使用DataContractSerializer进行序列化时,我之前正在做的事情):
<Example xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ExampleNamespace">
<IsActive>true</IsActive>
<Name>foo</Name>
</TagDto>
RestSharp版本与DataContractSerializer的版本有以下不同之处:
我很惊讶其中任何一个都有很大不同,但他们确实做到了。另请注意,在AddBody调用中添加显式命名空间之前,生成的XML(显然)中缺少这个,并且传递到我的ApiController的Example对象是null
。
无论如何,我注意到RestSharp允许您覆盖序列化程序,并提供了一种使用.NET XML序列化程序的方法。我尝试使用它(无济于事)。
这是我在调用AddBody之前添加的内容:
request.XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer(XmlNamespace);
..这就是我的结果:
<?xml version="1.0" encoding="utf-8"?>
<Example>
<Name>foo</Name>
<IsActive>true</IsActive>
</Example>
这显然不好,尤其是因为它以XML声明开头,我认为会导致问题。没有办法将其关闭,因为RestSharp派生类没有提供这样做的方法。此外,没有命名空间 - 无论我如何尝试在RestSharp中设置命名空间(在DotNetXmlSerializer的构造函数中,通过设置Namespace成员,或通过传入命名空间),我都无法在输出中出现一个命名空间AddBody)。在我看来,这堂课只不过是一个陷阱。
看起来我唯一的选择是创建自己的序列化程序类并在内部使用DataContractSerializer。是的,或者我错过了什么?
(顺便说一句,我可以将请求的RequestFormat设置为JSON,它只是起作用 - 但我仍然想知道如何使用XML)。
答案 0 :(得分:2)
我遇到了一些AddBody调用没有正确序列化JSON值的问题,因此可能与您的问题有些相似。您可以尝试:
而不是AddBodyrequest.AddParameter("text/xml", xmlAsString, ParameterType.RequestBody);
如果可行,您可以查看将第二个参数更改为xml对象,并查看序列化程序是否符合您的要求。
另一个选项可能是XmlMediaTypeFormatter.ReadFromStreamAsync
没有正确选择合适的序列化程序;你可以尝试覆盖那个功能。
答案 1 :(得分:1)
上面的问题是因为WebAPI正在使用DataContractSerializer(而不是你所追求的XmlSerializer)。要切换它,请修改Global.asax,如下所示。
var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
xml.UseXmlSerializer = true;
但是,我建议您使用RESTSharp格式化程序进行WebAPI(而不是使用.Net格式化程序)。如果您的DTO具有循环引用(.net fx序列化程序不能优雅地处理它),这将特别有用。
在Global.asax中,通过输入
修改格式化程序 GlobalConfiguration.Configuration.Formatters.XmlFormatter = //RestSharp XML serializer here
WebAPI is here and worth a browse
中序列化的快速概述