2012-08-03 74 views
3

我有一個ASP.NET MVC4網站實現一個REST API,我從客戶端應用程序中使用它。我的ApiController方法接收和返回複雜的對象,如XML。如何使用RestSharp POST(作爲XML)對象到我的ApiController?

我最近發現了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); 

上面的代碼確實打擊了PostExample方法我在我的ApiController中,它有一個Example對象作爲參數。 但是 Example對象的屬性值不同於我傳遞給Execute方法的值!在一個案例中,IsActive成員是錯誤的,而不是真實的,儘管我還看到一個名稱成員爲null的情況,它應該有一個值。

我使用Fiddler做了一些調查,看起來正確值是在RestSharp生成的XML中創建的。但是,XML的格式與Web服務器在執行GET時發出的格式不完全相同。差異是微妙的,但似乎使它的工作和不工作的區別。 Web服務器端的框架似乎對這些格式差異很敏感,並且導致錯誤解釋XML。

這裏的XML我從RestSharp得到:

<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的實例命名空間
  3. 的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的構造函數中,通過設置命名空間成員,或通過將名稱空間傳遞給AddBody)。在我看來,這門課不過是一個陷阱。

它看起來像我唯一的選擇是創建我自己的串行器類,並在內部使用DataContractSerializer。那是對的,還是我錯過了什麼? (順便說一下,我可以將請求的RequestFormat設置爲JSON,它只是起作用 - 但我仍然想知道如何使用XML進行操作)。

+0

它是一個必須爲你使用RestSharp修改格式化? – 2012-08-16 11:44:59

+0

@CongLe:哈!我最初使用DataContractSerializer開始自己編寫,然後被同事說服使用RestSharp。我可以切換到另一種解決方案,但我現在花了很多時間試圖讓RestSharp工作,我不願意這樣做。正如我在答覆中暗示的那樣,我最終轉而使用JSON而不是XML,所以這個問題仍然主要是爲了其他人的利益。 – 2012-08-16 12:35:22

+0

@Gary,我認爲JSON就是像RESTSharp這樣的庫,它的性能也非常出色,你在性能方面也會獲得小的性能提升。 – leon 2012-08-20 08:21:35

回答

1

上面的問題是因爲WebAPI使用DataContractSerializer(而不是XmlSerializer)。要切換這個,請按如下所示修改Global.asax。

var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter; 
xml.UseXmlSerializer = true; 

不過,我建議你使用(而不是使用.net格式化),用於在的WebAPI格式化RESTSharp。如果你是DTO的循環引用(.net fx序列化程序不能很好地處理它),這是特別有用的。

在Global.asax中,通過在

GlobalConfiguration.Configuration.Formatters.XmlFormatter = //RestSharp XML serializer here

把序列化的快速概覽中的WebAPI is here and worth a browse

2

我有AddBody調用沒有正確序列化JSON值的一些問題,所以可能有一些類似於你的問題。相反AddBody的,你可以嘗試:

request.AddParameter("text/xml", xmlAsString, ParameterType.RequestBody); 

如果這樣的作品,你可以看看,看看有關更改第二個參數是XML對象,看看串行你想要做什麼。

其他選項可能是XmlMediaTypeFormatter.ReadFromStreamAsync沒有正確拾取適當的串行器;您可以嘗試覆蓋該功能。