简体   繁体   English

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

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

I have a POST endpoint that takes a URL path param and then the body is a list of submitted DTOs. 我有一个采用URL路径参数的POST端点,然后该正文是已提交DTO的列表。

So right now the request DTO looks something along the lines of: 因此,现在请求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; }
}

And the service method looks something like: 服务方法类似于:

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

If encoded via JSON, the client would have to encode the POST body this way: 如果通过JSON编码,则客户端必须以这种方式编码POST正文:

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

This is redundant, I would like the client to submit the data like this: 这是多余的,我希望客户端提交这样的数据:

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

Which would have been the case if my request DTO was simply List<SomeEntry> 如果我的请求DTO只是List<SomeEntry>会是这种情况

My questions is: is there a way to "flatten" the request this way? 我的问题是:是否可以通过这种方式“平整”请求? Or designate one property of the request as the root of the message body? 还是将请求的一个属性指定为消息正文的根? ie perhaps: 即也许:

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

Is this doable in any way in ServiceStack? 这在ServiceStack中是否可以实现?

I was able to sort of get this to sort of work by subclassing List<T> : 我可以通过将List<T>子类化来解决这个问题:

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

Then you can send a request like this: 然后,您可以发送如下请求:

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

But if you have any choice in the design, I wouldn't recommend this. 但是,如果您在设计中有任何选择,我将不建议这样做。 Here's a couple of reasons to start with: 从以下几个原因开始:

  • I found at least one problem with this at runtime: sending an empty array, eg [ ] in JSON, is resulting in a 400 status code with RequestBindingException 我在运行时发现了至少一个问题:发送一个空数组,例如JSON中的[ ] ,导致带有RequestBindingException400状态代码
  • It's less flexible. 它不太灵活。 What if you do need to add additional top-level properties to the request in the future? 如果将来确实需要向请求中添加其他顶级属性怎么办? You would be stuck with them being path/query params. 您将被路径/查询参数所困扰。 Having a regular class-containing-a-list allows you to add new optional properties at the top level of the request body, with backward compatibility 具有常规的包含列表的类使您可以在请求正文的顶层添加新的可选属性,并且具有向后兼容性

OK I've managed to achieve this. 好的,我已经设法做到这一点。 Not the prettiest solution but will do for now. 不是最漂亮的解决方案,但现在可以使用。

I wrapped the content type filter for JSON: 我包装了JSON的内容类型过滤器:

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

Then the custom deserializer looks like this: 然后,自定义解串器如下所示:

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

_messageBodyPropertyMap is populated after init by scanning the request DTOs and looking for a certain attribute, as in the example in my original question. 初始化后,通过扫描请求DTO并查找特定属性来填充_messageBodyPropertyMap ,如我原始问题中的示例所示。

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

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