【发布时间】:2012-08-03 16:32:12
【问题描述】:
我有一个实现 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,尽管我也看到了 Name 成员为 null 的情况,它应该有一个值。
我使用 Fiddler 进行了一些调查,似乎在 RestSharp 生成的 XML 中创建了正确的值 。但是,XML 与 Web 服务器在执行 GET 时发出的格式并不完全相同。差异是微妙的,但似乎在它工作和不工作之间有所不同。 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 的版本有以下区别:
- 字段的顺序不同
- RestSharp 不包含额外的命名空间 XMLSchema-instance 命名空间
- DataContractSerializer 不包含任何空格或换行符(为了便于阅读,我在上面添加了这些)
我很惊讶其中任何一个都会产生很大的不同,但显然它们确实如此。另请注意,在我在 AddBody 调用中添加显式命名空间之前,生成的 XML 中缺少该命名空间(显然),并且传递给我的 ApiController 的示例对象是 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 的构造函数中,通过设置命名空间成员或通过将命名空间传递给添加正文)。在我看来,这门课只不过是个陷阱。
看来我唯一的选择是创建自己的序列化程序类并在内部使用 DataContractSerializer。是这样吗,还是我错过了什么?
(顺便说一句,我可以将请求的 RequestFormat 设置为 JSON,它可以正常工作 - 但我仍然想知道如何使用 XML)。
【问题讨论】:
-
RestSharp 是不是一定要使用?
-
@CuongLe:哈!我最初是使用 DataContractSerializer 开始自己开发的,然后被同事说服使用 RestSharp。我可以切换到另一个解决方案,但我现在已经投入了大量时间来尝试让 RestSharp 工作,以至于我不愿意这样做。正如我在回答中暗示的那样,我最终改用 JSON 而不是 XML,所以这个问题仍然主要是为了他人的利益。
-
@Gary,我认为 JSON 是 RESTSharp 之类的库真正出类拔萃的地方,而且在性能方面您也会获得一点性能提升。
标签: serialization asp.net-web-api restsharp