multipart/form-data コンテンツを含む POST を消費する ServiceStack を使用して RESTful サービスを作成しています。コンテンツは JSON 形式ですが、POST を送信すると、オブジェクトが正しく逆シリアル化されません (すべてのプロパティが null/既定値です)。そのオブジェクトを通常の POST (multipart/form-data なし) として送信しようとすると、正常に逆シリアル化されます。
何が起こっているのかを把握するために ServiceStack コードを調べてみましたが、これが私の現在の理解です。
- HttpListenerRequestWrapper::LoadMultiPart() は、マルチパート リクエストをロードし、(非ファイル) パーツを「FormData」に保存します。これにより、パーツの名前がそのコンテンツにマップされます。ただし、コンテンツ タイプ (個々のセクションが解析されているときに HttpMultiPart::Element に正しく書き込まれます) はどこにも格納されていないため、失われているようです。
- しばらくして、制御フローで EndpointHandlerBase::DeserializeHttpRequest() が KeyValueDataContractDeserializer.Instance.Parse() を FormData とデシリアライズ先の型で呼び出します。
- その種類のオブジェクトが初めて逆シリアル化される場合は、その型の StringMapTypeDeserializer が作成され、typeStringMapSerializerMap にキャッシュされます。型の各プロパティに対して、 JsvReader.GetParseFn() を呼び出して、そのプロパティを逆シリアル化する解析する ParseStringDelegate を取得します。
- 次に、作成/キャッシュされた StringMapTypeDeserializer を使用して、以前に設定されたすべての「ParseFn」を使用してオブジェクトを逆シリアル化します...これらはすべてコンテンツを JSV 形式として扱います。
JsvReader.ParseFnCache にはたくさんの型が含まれているのに対し、JsonReader.ParseFnCache は空であることを確認しました。また、すべての引用符を削除するように要求を変更すると (つまり、JSON から JSV 形式に変換すると)、正しく逆シリアル化されます。奇妙な点の 1 つは、オブジェクトのプロパティの 1 つがディクショナリであり、それが JSON 形式であっても正しく逆シリアル化されることです。これはたまたまの偶然だと思います(?!?)。
ここで何が起こっているかについての私の理解は正しいですか?これは ServiceStack の既知の制限ですか? バグ?オブジェクトをファイルに入れて手動で JsonSerializer.DeserializeFromStream() を呼び出す以外に回避策はありますか?
ありがとう!
jps
また、参考までに、関連するリクエストとデータ オブジェクトを次に示します。
POST /api/Task HTTP/1.1
Accept: application/json
Content-Type: multipart/form-data; boundary=Boundary_1_1161035867_1375890821794
MIME-Version: 1.0
Host: localhost:12345
Content-Length: 385
--Boundary_1_1161035867_1375890821794
Content-Type: application/json
Content-Disposition: form-data; name="MyMap"
{"myfile.dat":"ImportantFile"}
--Boundary_1_1161035867_1375890821794
Content-Disposition: form-data; name="MyThing"
Content-Type: application/json
{"Id":123,"Name":"myteststring"}
--Boundary_1_1161035867_1375890821794
Content-Type: application/octet-stream
Content-Disposition: form-data; filename="myfile.dat"
mydatagoeshere...
--Boundary_1_1161035867_1375890821794--
.
public class TestObj
{
public long Id { get; set; }
public string Name { get; set; }
}
[Route("/Task", "POST")]
public class TaskRequest : AuthenticatedRequest, IReturn<TaskResponse>
{
public TestObj MyThing { get; set; }
public Dictionary<string, string> MyMap { get; set; }
}