您也许能够通过自定义实现您正在寻找的目标IActionConstraint:
从概念上讲,IActionConstraint 是一种重载形式,但它不是重载具有相同名称的方法,而是在匹配相同 URL 的操作之间重载。
我对此进行了一些尝试并提出了以下建议IActionConstraint
执行:
public class FormContentTypeAttribute : Attribute, IActionConstraint
{
public int Order => 0;
public bool Accept(ActionConstraintContext ctx) =>
ctx.RouteContext.HttpContext.Request.HasFormContentType;
}
正如您所看到的,它非常简单 - 只是检查传入的 HTTP 请求是否属于表单内容类型。为了使用它,您可以归因于相关操作。这是一个完整的示例,其中还包括本文中建议的想法answer,但使用你的行动:
[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 的操作始终被认为比没有 IActionConstraint 的操作更好。
这意味着当传入请求不是表单内容类型时,FormContentType
我显示的属性将排除该特定操作,因此使用PostFromBody
。否则,如果它is表单内容类型的PostFromForm
行动会因为被“认为更好”而获胜。
我已经在相当基本的水平上对此进行了测试,它似乎确实符合您的要求。在某些情况下,它可能不太适合,所以我鼓励您尝试一下它,看看您可以在哪里使用它。我完全希望您可能会发现它完全倒塌的情况,但这仍然是一个值得探索的有趣想法。
最后,如果您不喜欢使用属性,可以配置一个约定,例如使用反射来查找带有 a 的操作[FromForm]
属性并自动添加约束。这篇优秀的文章中有更多细节post关于这个话题。