Tar*_*rek 5 c# xml .net-core asp.net-core asp.net-core-webapi
我有一个带有POST方法的控制器,它将接收一个xml字符串,该字符串可以是2种类型。例如:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]firstClass data)
{
if (data != null)...
Run Code Online (Sandbox Code Playgroud)
我希望能够在同一路由上绑定到多个类型([HttpPost(“ postObj”)]),以便可以在正文中具有firstClass xml的http://127.0.0.1:5000/api/postObj上接收,或正文中的secondClass xml,并采取相应措施。
我尝试用相同的路线但类型不同的方法制作另一种方法:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]secondClass data)
{
if (data != null)...
Run Code Online (Sandbox Code Playgroud)
但正如预期的那样,我收到“请求匹配多个操作导致歧义”。
我尝试读取正文并进行检查,然后将xml序列化为相应的对象,但这极大地降低了性能。
我期望每秒最多100个请求,并且使用FromBody进行绑定可以为我提供这些信息,但是手动读取正文并进行序列化仅给我约15个请求。
我该如何实现?
正在解决同样的问题,这就是我最终得到的结果:
我希望有以下 API:
PATCH /persons/1
{"name": "Alex"}
PATCH /persons/1
{"age": 33}
Run Code Online (Sandbox Code Playgroud)
我还希望有单独的控制器操作,例如:
[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) {}
Run Code Online (Sandbox Code Playgroud)
因此,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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
优点:验证有效,不需要第三个操作和/或基本模型,可以与 swashbuckle 一起使用
缺点:对于此操作,我们正在读取和反序列化 body 两次
注意:倒带流很重要,否则其他人将无法读取正文
我们的控制器现在看起来像这样:
[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) {}
Run Code Online (Sandbox Code Playgroud)
您不能定义具有相同路线的两个操作。操作选择器不考虑它们的参数类型。那么,为什么不合并这些动作呢?
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; }
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5450 次 |
最近记录: |