繁体   English   中英

ServiceStack:我可以“拼合”帖子主体的结构吗?

[英]ServiceStack: Can I “Flatten” the structure of the post body?

我有一个采用URL路径参数的POST端点,然后该正文是已提交DTO的列表。

因此,现在请求DTO看起来类似于:

[Route("/prefix/{Param1}", "POST")]
public class SomeRequest
{
    public string          Param1  { get; set; }
    public List<SomeEntry> Entries { get; set; }
}

public class SomeEntry
{
    public int    ID    { get; set; }
    public int    Type  { get; set; }
    public string Value { get; set; }
}

服务方法类似于:

public class SomeService : Service
{
    public SomeResponse Post(SomeRequest request)
    {
    }
}

如果通过JSON编码,则客户端必须以这种方式编码POST正文:

{
    "Entries":
    [
        {
            "id":    1
            "type":  42
            "value": "Y"
        },
        ...
    ]
}

这是多余的,我希望客户端提交这样的数据:

[
    {
        "id":    1
        "type":  42
        "value": "Y"
    },
    ...
]

如果我的请求DTO只是List<SomeEntry>会是这种情况

我的问题是:是否可以通过这种方式“平整”请求? 还是将请求的一个属性指定为消息正文的根? 即也许:

[Route("/prefix/{Param1}", "POST")]
public class SomeRequest
{
    public string          Param1  { get; set; }
    [MessageBody]
    public List<SomeEntry> Entries { get; set; }
}

这在ServiceStack中是否可以实现?

我可以通过将List<T>子类化来解决这个问题:

[Route("/prefix/{Param1}", "POST")]
public class SomeRequest : List<SomeEntry>
{
    public string          Param1  { get; set; }
}

然后,您可以发送如下请求:

POST /prefix/someParameterValue
Content-Type: application/json
[ { "ID": 1, "Type": 2, "Value": "X" }, ... ]

但是,如果您在设计中有任何选择,我将不建议这样做。 从以下几个原因开始:

  • 我在运行时发现了至少一个问题:发送一个空数组,例如JSON中的[ ] ,导致带有RequestBindingException400状态代码
  • 它不太灵活。 如果将来确实需要向请求中添加其他顶级属性怎么办? 您将被路径/查询参数所困扰。 具有常规的包含列表的类使您可以在请求正文的顶层添加新的可选属性,并且具有向后兼容性

好的,我已经设法做到这一点。 不是最漂亮的解决方案,但现在可以使用。

我包装了JSON的内容类型过滤器:

var serz   = ContentTypeFilters.GetResponseSerializer("application/json");
var deserz = ContentTypeFilters.GetStreamDeserializer("application/json");
ContentTypeFilters.Register("application/json", serz, (type, stream) => MessageBodyPropertyFilter(type, stream, deserz));

然后,自定义解串器如下所示:

private object MessageBodyPropertyFilter(Type type, Stream stream, StreamDeserializerDelegate original)
{
    PropertyInfo prop;
    if (_messageBodyPropertyMap.TryGetValue(type, out prop))
    {
        var requestDto = type.CreateInstance();
        prop.SetValue(requestDto, original(prop.PropertyType, stream), null);
        return requestDto;
    }
    else
    {
        return original(type, stream);
    }
}

初始化后,通过扫描请求DTO并查找特定属性来填充_messageBodyPropertyMap ,如我原始问题中的示例所示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM