3

クライアント アプリケーションから使用している 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 のバージョンと次の違いがあります。

  1. フィールドの順序が異なります
  2. RestSharp には、追加の名前空間 XMLSchema-instance 名前空間は含まれていません
  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 で機能させる方法を知りたいと思っています)。

4

2 に答える 2

2

AddBody 呼び出しが JSON 値を適切にシリアル化しないという問題がいくつかあったため、問題に類似点がある可能性があります。AddBody の代わりに、次を試すことができます。

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

それが機能する場合は、2 番目のパラメーターを xml オブジェクトに変更する方法を調べて、シリアライザーが意図したとおりに動作するかどうかを確認できます。

もう 1 つのオプションはXmlMediaTypeFormatter.ReadFromStreamAsync、適切なシリアライザーを適切に取得していない可能性があります。その関数をオーバーライドしてみることができます。

于 2012-08-14T09:58:12.047 に答える
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 でのシリアライゼーションの簡単な概要はこちらで参照する価値があります

于 2012-08-15T13:59:58.060 に答える