如何使用RestSharp将对象POST(作为XML)发送到我的ApiController?

时间:2012-08-03 16:32:12

标签: serialization asp.net-web-api restsharp

我有一个实现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的版本有以下不同之处:

  1. 字段的顺序不同
  2. RestSharp不包含额外的命名空间XMLSchema-instance namespace
  3. DataContractSerializer不包含任何空格或换行符(为了便于阅读,我添加了以上内容)
  4. 我很惊讶其中任何一个都有很大不同,但他们确实做到了。另请注意,在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)。

2 个答案:

答案 0 :(得分:2)

我遇到了一些AddBody调用没有正确序列化JSON值的问题,因此可能与您的问题有些相似。您可以尝试:

而不是AddBody
request.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

中序列化的快速概述