我有一个带有一个 POST 方法的 Controller ,它将接收一个可以是 2 种类型的 xml 字符串。例如:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]firstClass data)
{
if (data != null)...
我希望能够绑定(bind)到同一路由上的多个类型 ([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 进行绑定(bind)给了我这个,但是手动读取正文和序列化只给了我大约 15 个。
我怎样才能做到这一点?
最佳答案
正在玩同样的问题,这是我最终得到的:
我希望有以下 API:
PATCH /persons/1
{"name": "Alex"}
PATCH /persons/1
{"age": 33}
我还希望有单独的 Controller 操作,例如:
[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) {}
因此它们可以在生成 API 文档时被 Swashbuckle 使用。
更重要的是我希望内置验证工作(这在任何其他建议的解决方案中都不起作用)。
为了实现这一点,我们将创建我们自己的操作方法选择器属性,它将尝试反序列化传入的请求主体,如果它能够这样做,那么将选择操作,否则将检查下一个操作。
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;
}
}
}
优点:验证有效,不需要第三个 Action 和/或基础模型,可以与 swashbuckle 一起使用
缺点:对于此操作,我们需要两次读取和反序列化正文
注意:倒回流很重要,否则其他人将无法阅读正文
我们的 Controller 现在看起来像这样:
[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) {}
可以找到完整的示例代码 here
关于c# - 同一方法.net core web api上的多种类型[FromBody],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48082324/