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