[英]Is it possible to combine [FromRoute] and [FromBody] in ASP.NET Core?
[英]How to combine FromBody and FromForm BindingSource in ASP.NET Core?
我創建了一個新的 ASP.NET Core 2.1 API 項目,帶有一個Data
dto 類和這個控制器操作:
[HttpPost]
public ActionResult<Data> Post([FromForm][FromBody] Data data)
{
return new ActionResult<Data>(data);
}
public class Data
{
public string Id { get; set; }
public string Txt { get; set; }
}
它應該將數據回顯給用戶,沒什么特別的。 但是,這兩個屬性中只有一個有效,具體取決於順序。
以下是測試請求:
curl -X POST http://localhost:5000/api/values \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'id=qwer567&txt=text%20from%20x-www-form-urlencoded'
和
curl -X POST http://localhost:5000/api/values \
-H 'Content-Type: application/json' \
-d '{
"id": "abc123",
"txt": "text from application/json"
}'
我嘗試了幾種方法,都無濟於事:
BindingSource
,但這似乎只是元數據。[CompositeBindingSource(...)]
,但構造函數是私有的,這可能不是預期用途IModelBinder
和提供程序,但是 (1) 我可能只希望在特定的控制器操作上使用它,並且 (2) 獲得兩個內部模型綁定器(用於 Body 和 FormCollection)似乎確實需要做很多工作那么,將FromForm
和FromBody
(或者我猜任何其他來源的組合)屬性合並為一個的正確方法是什么?
澄清這背后的原因,並解釋為什么我的問題不是這個問題的重復:我想知道如何使用相同的 URI/路由來支持兩種不同類型的發送數據。 (盡管可能對某些人的口味,包括我自己的口味,不同的路線/uri 可能更合適。)
您可以使用自定義IActionConstraint
實現您正在尋找的IActionConstraint
:
從概念上講,IActionConstraint 是一種重載形式,但它不是重載具有相同名稱的方法,而是在匹配相同 URL 的操作之間進行重載。
我對此進行了一些嘗試,並提出了以下IActionConstraint
實現:
public class FormContentTypeAttribute : Attribute, IActionConstraint
{
public int Order => 0;
public bool Accept(ActionConstraintContext ctx) =>
ctx.RouteContext.HttpContext.Request.HasFormContentType;
}
如您所見,它非常簡單——它只是檢查傳入的 HTTP 請求是否屬於表單內容類型。 為了使用它,您可以歸因於相關操作。 這是一個完整的示例,其中還包含此答案中建議的想法,但使用您的操作:
[HttpPost]
[FormContentType]
public ActionResult<Data> PostFromForm([FromForm] Data data) =>
DoPost(data);
[HttpPost]
public ActionResult<Data> PostFromBody([FromBody] Data data) =>
DoPost(data);
private ActionResult<Data> DoPost(Data data) =>
new ActionResult<Data>(data);
[FromBody]
在上面是可選的,因為使用了[ApiController]
,但我已經在示例中明確地包含了它。
也來自文檔:
...帶有 IActionConstraint 的動作總是被認為比沒有的動作更好。
這意味着當傳入的請求不是表單內容類型時,我展示的FormContentType
屬性將排除該特定操作,因此使用PostFromBody
。 否則,如果它是表單內容類型,則PostFromForm
操作將獲勝,因為它被“認為更好”。
我已經在相當基本的水平上對此進行了測試,它似乎確實可以滿足您的需求。 可能有些情況下它不太合適,所以我鼓勵你玩玩它,看看你可以用它去哪里。 我完全希望您可能會發現它完全倒塌的情況,但仍然是一個值得探索的有趣想法。
最后,如果您不想使用屬性,可以配置一個約定,例如使用反射來查找具有[FromForm]
屬性的操作並自動添加約束。 這篇關於該主題的優秀文章中有更多詳細信息。
你不能。 一個動作只能接受一個或另一個。 為了解決這個問題,您可以簡單地創建多個動作,一個有[FromBody]
,一個沒有。 它們當然也需要單獨的路由,因為屬性的存在不足以區分重載。 但是,您可以將 action 的主體分解為兩個 action 都可以使用的私有方法,至少可以保持 DRY。
nuget 包 Toycloud.AspNetCore.Mvc.ModelBinding.BodyAndFormBinding 應該適合您的需求
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.