3

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; }
}
4

1 に答える 1

1

「ApiMember」属性を使用してリクエスト オブジェクトのプロパティを設定しようとしましたか? 特に「ParameterType」プロパティ。

/// <summary>
/// Create and upload a new video.
/// </summary>
[Api("Create and upload a new video.")]
[Route("/videos", "POST", Summary = @"Create and upload a new video.",
    Notes = "Video file / attachment must be uploaded using POST and 'multipart/form-data' encoding.")]
public class CreateVideo : OperationBase<IVideo>
{
    /// <summary>
    /// Gets or sets the video title.
    /// </summary>
    [ApiMember(Name = "Title",
        AllowMultiple = false,
        DataType = "string",
        Description = "Video title. Required, between 8 and 128 characters.",
        IsRequired = true,
        ParameterType = "form")]
    public string Title { get; set; }

    /// <summary>
    /// Gets or sets the video description.
    /// </summary>
    [ApiMember(Name = "Description",
        AllowMultiple = false,
        DataType = "string",
        Description = "Video description.",
        ParameterType = "form")]
    public string Description { get; set; }

    /// <summary>
    /// Gets or sets the publish date.
    /// </summary>
    /// <remarks>
    /// If blank, the video will be published immediately.
    /// </remarks>
    [ApiMember(Name = "PublishDate",
        AllowMultiple = false,
        DataType = "date",
        Description = "Publish date. If blank, the video will be published immediately.",
        ParameterType = "form")]
    public DateTime? PublishDate { get; set; }
}
于 2013-08-30T06:16:48.347 に答える