亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 ASP.NET Core 中結合 FromBody 和 FromForm

如何在 ASP.NET Core 中結合 FromBody 和 FromForm

C#
胡說叔叔 2021-11-14 15:06:53
我創建了一個新的 ASP.NET Core 2.1 API 項目,帶有一個Datadto 類和這個控制器操作:[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"}'我嘗試了幾種方法,都無濟于事:創建自定義 child BindingSource,但這似乎只是元數據。使用屬性[CompositeBindingSource(...)],但構造函數是私有的,這可能不是預期用途IModelBinder為此創建一個和提供程序,但是 (1) 我可能只希望在特定的控制器操作上使用它,并且 (2) 獲得兩個內部模型綁定器(用于 Body 和 FormCollection)似乎確實需要做很多工作那么,將屬性FromForm和FromBody(或我猜任何其他來源的組合)屬性合二為一的正確方法是什么?澄清這背后的原因,并解釋為什么我的問題不是這個問題的重復:我想知道如何使用相同的 URI/路由來支持兩種不同類型的發送數據。(盡管可能對某些人的口味,包括我自己的口味,不同的路線/uri 可能更合適。)
查看完整描述

3 回答

?
喵喔喔

TA貢獻1735條經驗 獲得超5個贊

您可能能夠通過自定義實現您正在尋找的內容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操作將獲勝,因為它被“認為更好”。


我已經在相當基本的水平上對此進行了測試,它似乎確實可以滿足您的需求??赡苡行┣闆r下它不太合適,所以我鼓勵你玩玩它,看看你可以用它去哪里。我完全希望您可能會發現它完全倒塌的情況,但仍然是一個值得探索的有趣想法。


最后,如果您不喜歡必須使用屬性,可以配置一個約定,例如使用反射來查找具有[FromForm]屬性的操作并自動添加約束。這篇關于該主題的優秀文章中有更多詳細信息。


查看完整回答
反對 回復 2021-11-14
?
呼喚遠方

TA貢獻1856條經驗 獲得超11個贊

你不能。一個動作只能接受一個或另一個。為了解決這個問題,您可以簡單地創建多個操作,一個有[FromBody]一個沒有。它們當然也需要單獨的路由,因為屬性的存在不足以區分重載。但是,您可以將 action 的主體分解為兩個 action 都可以使用的私有方法,至少可以保持 DRY。


查看完整回答
反對 回復 2021-11-14
?
幕布斯7119047

TA貢獻1794條經驗 獲得超8個贊

我喜歡接受的答案中提出的解決方案,甚至使用了一段時間,但現在我們有了這個[Consumes]屬性。


你甚至可以將兩者映射到同一個路由 URL,這是個好消息。


[HttpPost]

[Route("/api/Post")] //same route but different "Consumes"

[Consumes("application/x-www-form-urlencoded")]

public ActionResult Post([FromForm] Data data)

{

    DoStuff();

}


[HttpPost]

[Route("/api/Post")] //same route but different "Consumes"

[Consumes("application/json")]

public ActionResult PostJson([FromBody] Data data)

{

    Post(data); //just call the other action method

}

https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-5.0#define-supported-request-content-types-with-the-consumes-attribute


查看完整回答
反對 回復 2021-11-14
  • 3 回答
  • 0 關注
  • 1586 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號