我有一个带有一个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中使用body中的firstClass xml或body中的secondClass xml,并采取相应的行动。
我尝试使用相同的路线制作另一种方法但类型不同,如:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]secondClass data)
{
if (data != null)...
但正如预期的那样,我得到“请求匹配多个操作导致歧义”。
我尝试读取正文并进行检查,然后将xml序列化到相应的对象,但这大大降低了性能。
我期待每秒最多100个请求,使用FromBody的绑定给了我这个,但手动阅读正文和序列化只给我15个。
我怎样才能做到这一点?
答案 0 :(得分:3)
您无法使用相同路线定义两个操作。操作选择器不考虑其参数类型。那么,为什么不合并这些行动;
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; }
}
答案 1 :(得分:0)
作为免责声明,我认为这有点像黑客。我推动将发送给您的对象更改为一个对象,该对象可以表示两种情况,或者将两种不同的对象类型发布到两个不同的URI。
有了这个,只需让它工作的一个选项就是按照本教程创建自定义IModelBinder: https://dotnetcoretutorials.com/2016/12/28/custom-model-binders-asp-net-core/
这里的关键是你绑定的模型将是一个基类,你的两个不同的类派生自它。
答案 2 :(得分:0)
在玩同样的问题时,这就是我的结论:
我希望具有以下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) {}
可以找到完整的示例代码here