servicestack,multipartform-data,Rest,servicestack,Multipartform Data" /> servicestack,multipartform-data,Rest,servicestack,Multipartform Data" />

Rest 多部分/表单数据请求中JSON内容的ServiceStack反序列化

Rest 多部分/表单数据请求中JSON内容的ServiceStack反序列化,rest,servicestack,multipartform-data,Rest,servicestack,Multipartform Data,我正在使用ServiceStack创建一个RESTful服务,它应该使用包含多部分/表单数据内容的POST。内容是JSON格式的,但是当我发送帖子时,对象没有被正确反序列化(所有属性都是null/默认值)。如果我尝试将该对象作为常规POST发送(没有多部分/表单数据),那么它的反序列化就很好了 我翻遍了ServiceStack代码,试图找出发生了什么,这是我目前的理解: HttpListenerRequestWrapper::LoadMultiPart()正在加载多部分请求,并将(非文件)部分

我正在使用ServiceStack创建一个RESTful服务,它应该使用包含多部分/表单数据内容的POST。内容是JSON格式的,但是当我发送帖子时,对象没有被正确反序列化(所有属性都是null/默认值)。如果我尝试将该对象作为常规POST发送(没有多部分/表单数据),那么它的反序列化就很好了

我翻遍了ServiceStack代码,试图找出发生了什么,这是我目前的理解:

  • HttpListenerRequestWrapper::LoadMultiPart()正在加载多部分请求,并将(非文件)部分保存到“FormData”,后者将部分名称映射到其内容。但是,由于内容类型没有存储在任何位置,因此它似乎丢失了(在解析各个部分时,它被正确写入HttpMultiPart::元素)
  • 稍后在控制流中,EndpointHandlerBase::DeserializeHttpRequest()调用KeyValueDataContractDeserializer.Instance.Parse(),并使用FormData和要反序列化的类型
  • 如果这是第一次反序列化此类对象,则会为该类型创建StringMapTypeDeserializer并缓存到typeStringMapSerializerMap。对于该类型的每个属性,我们调用JsvReader.GetParseFn()以获取一个ParseStringDelegate来解析该属性,并对该属性进行反序列化
  • 创建/缓存的StringMapTypeDeserializer然后用于使用前面设置的所有“ParseFn”反序列化对象。。。它们都将内容视为JSV格式
我确认JsvReader.ParseFnCache中有很多类型,而JsonReader.ParseFnCache是空的。此外,如果我更改请求以删除所有引号(即将其从JSON转换为JSV格式),它将正确反序列化。一件奇怪的事情是,我的对象的属性之一是一个字典,它可以正确地反序列化,即使它是JSON格式的;我想这只是一个幸运的巧合(?!?)

我对这里发生的事情的理解正确吗?这是ServiceStack中的已知限制吗?缺陷除了将我的对象放入文件并手动调用JsonSerializer.DeserializeFromStream()之外,还有其他方法可以解决这个问题吗

谢谢

太平绅士

此外,为了方便使用,下面是相关的请求和数据对象:

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--

公共类TestObj
{
公共长Id{get;set;}
公共字符串名称{get;set;}
}
[路线(“/Task”,“POST”)]
公共类任务请求:AuthenticatedRequest,IReturn
{
公共TestObj神话{get;set;}
公共字典MyMap{get;set;}
}

您是否尝试过使用“ApiMember”属性设置请求对象的属性?特别是“ParameterType”属性。

//
///创建并上传新视频。
/// 
[Api(“创建并上传新视频”)]
[路线(“/videos”,“POST”,Summary=@“创建并上传新视频。”,
Notes=“视频文件/附件必须使用POST和“多部分/表单数据”编码上传。”)]
公共类CreateVideo:OperationBase
{
/// 
///获取或设置视频标题。
/// 
[ApiMember(Name=“Title”,
AllowMultiple=false,
DataType=“string”,
Description=“视频标题。必填,介于8到128个字符之间。”,
IsRequired=true,
ParameterType=“form”)]
公共字符串标题{get;set;}
/// 
///获取或设置视频描述。
/// 
[ApiMember(Name=“Description”,
AllowMultiple=false,
DataType=“string”,
Description=“视频描述”,
ParameterType=“form”)]
公共字符串说明{get;set;}
/// 
///获取或设置发布日期。
/// 
/// 
///如果为空,视频将立即发布。
/// 
[ApiMember(Name=“PublishDate”,
AllowMultiple=false,
DataType=“日期”,
Description=“发布日期。如果为空,视频将立即发布。”,
ParameterType=“form”)]
publicDateTime?PublishDate{get;set;}
}

我尝试添加这些注释,但我不确定在我的案例中使用什么数据类型;我在网上找了一会儿,但找不到好的例子,它们只是泛型字符串,不是枚举之类的。我尝试了“complex”(用于TestObj)和“container”(用于字典)以及其他各种方法,但似乎没有什么不同。
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; }
}
/// <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; }
}