クライアント アプリケーションから使用している REST API を実装する ASP.NET MVC4 Web サイトがあります。私の 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);
}
}
この問題は、次のようにオブジェクトを Web サイトに POST しようとすると発生します。
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 メンバーが true ではなく false でしたが、値を持つべき 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>
これは、Web サーバーで 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 に渡された 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 で機能させる方法を知りたいと思っています)。