[英]ASP.NET Core 3.1: Web Api: Same Post Method: Multiple types of Json Objects
[英]Multiple types [FromBody] on same method .net core web api
我有一個控制器有一個POST方法,它將接收一個xml字符串,可以是2種類型。 例如:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]firstClass data)
{
if (data != null)...
我希望能夠綁定到同一路徑上的多個類型([HttpPost(“postObj”)])這樣我就可以在http://127.0.0.1:5000/api/postObj上接收到身體中的firstClass xml ,或者身體中的secondClass xml,並相應地采取行動。
我嘗試使用相同的路線制作另一種方法,但不同的類型如:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]secondClass data)
{
if (data != null)...
但正如預期的那樣,我得到“請求匹配的多個操作導致模糊”。
我嘗試讀取正文並進行檢查,然后將xml序列化到相應的對象,但這大大降低了性能。
我期待每秒最多100個請求,使用FromBody的綁定給了我這個,但手動閱讀正文和序列化只給我15個。
我怎樣才能做到這一點?
您無法使用相同路徑定義兩個操作。 操作選擇器不考慮其參數類型。 那么,你為什么不合並這些行動;
public async Task<IActionResult> postObj([FromBody]EntireData data)
{
if (data.FirstClass != null)
{
//Do something
}
if (data.SecondClass != null)
{
//Do something
}
}
public class EntireData
{
public FirstClass firstClass { get; set; }
public SecondClass secondClass { get; set; }
}
正在玩同樣的問題,這是我最終得到的:
我希望有以下API:
PATCH /persons/1
{"name": "Alex"}
PATCH /persons/1
{"age": 33}
我也希望有單獨的控制器操作,例如:
[HttpPatch]
[Route("person/{id:int:min(1)}")]
public void PatchPersonName(int id, [FromBody]PatchPersonName model) {}
[HttpPatch]
[Route("person/{id:int:min(1)}")]
public void PatchPersonAge(int id, [FromBody]PatchPersonAge model) {}
因此,Swashbuckle可以在生成API文檔時使用它們。
更重要的是,我希望內置驗證工作(在任何其他建議的解決方案中都不起作用)。
為了實現這一點,我們將創建自己的操作方法選擇器屬性,該屬性將嘗試反序列化傳入的請求體,如果能夠這樣做,則將選擇操作,否則將檢查下一個操作。
public class PatchForAttribute : ActionMethodSelectorAttribute
{
public Type Type { get; }
public PatchForAttribute(Type type)
{
Type = type;
}
public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
{
routeContext.HttpContext.Request.EnableRewind();
var body = new StreamReader(routeContext.HttpContext.Request.Body).ReadToEnd();
try
{
JsonConvert.DeserializeObject(body, Type, new JsonSerializerSettings { MissingMemberHandling = MissingMemberHandling.Error });
return true;
}
catch (Exception)
{
return false;
}
finally
{
routeContext.HttpContext.Request.Body.Position = 0;
}
}
}
專業人士 :驗證工作正常,不需要第三個動作和/或基礎模型,可以使用swashbuckle
缺點 :對於這個動作,我們正在閱讀和反序體化兩次
注意 :重繞流是很重要的,否則其他任何人都無法讀取身體
我們的控制器現在看起來像這樣:
[HttpPatch]
[Route("person/{id:int:min(1)}")]
[PatchFor(typeof(PatchPersonName))]
public void PatchPersonName(int id, [FromBody]PatchPersonName model) {}
[HttpPatch]
[Route("person/{id:int:min(1)}")]
[PatchFor(typeof(PatchPersonAge))]
public void PatchPersonAge(int id, [FromBody]PatchPersonAge model) {}
可以在此處找到完整的示例代碼
作為免責聲明,我認為這有點像hacky。 我推動將發送給您的對象更改為一個對象,該對象可以表示兩種情況,或者將兩種不同的對象類型發布到兩個不同的URI。
有了這個,只需讓它工作就可以通過以下教程創建自定義IModelBinder: https : //dotnetcoretutorials.com/2016/12/28/custom-model-binders-asp-net-核心/
這里的關鍵是你綁定的模型將是一個基類,它有兩個不同的派生類。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.