c# - 同一方法.net core web api上的多种类型[FromBody]

标签 c# xml asp.net-core .net-core asp.net-core-webapi

我有一个带有一个 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/

相关文章:

c# - 什么是 vNext 控制台应用程序?

c# - 为什么 WebClient (System.Net) 从 URL 获取两次?

c# - 如何从 C# 代码调用 Google Geocoding 服务

java - 使用castor将xml转换为java对象

java - 在 java 中,commons-Digester 如何处理输入的 XML 文件?

xml - XSLT - 使用 XPath 计算子元素的数量

c# - Asp.net 核心返回 View 或 Json/XML 的最干净的方法

c# - ASP.NET MVC 验证在加载页面后显示错误

c# - WPF MenuItem 子项未显示

css - 使用 Bootstrap 4 时,如何在大屏幕尺寸下定位(向下对齐)我的页脚?