.Net Core API控制器接受表格或正文数据

时间:2019-02-26 13:29:57

标签: c# api asp.net-core

我有一个API操作,我希望它接受表单数据或原始JSON。

这是我的职能

    [HttpPost]
    public async Task<IActionResult> ExternalLogin([FromForm]ExternalLoginModel formModel, [FromBody]ExternalLoginModel bodyModel)
    {

所以我希望他们能够以两种不同的方式发送相同的数据,当我尝试使用form-data方法时,出现415错误。当我尝试使用原始JSON时,效果很好。

我希望能够将其保留在一个功能中,但是如果我必须将其分解为两个,就可以。

1 个答案:

答案 0 :(得分:1)

不幸的是,如果主体模型绑定程序无法解析请求主体,它将短路请求,而不是简单地跳过与action参数的绑定。

如果您确实想在一个动作中处理两种内容类型,则可以为主体模型绑定程序实现输入格式化程序,从而绕过此行为。如果请求具有表单内容类型,它可以通过假装绑定成功完成。

格式化程序本身很简单:

/// <summary>
/// This input formatter bypasses the <see cref="BodyModelBinder"/> by returning a null result, when the request has a form content type.
/// When registered, both <see cref="FromBodyAttribute"/> and <see cref="FromFormAttribute"/> can be used in the same method.
/// </summary>
public class BypassFormDataInputFormatter : IInputFormatter
{
    public bool CanRead(InputFormatterContext context)
    {
        return context.HttpContext.Request.HasFormContentType;
    }

    public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
    {
        return InputFormatterResult.SuccessAsync(null);
    }
}

在您的启动类中,需要添加格式化程序:

services.AddMvc(options =>
{
    options.InputFormatters.Add(new BypassFormDataInputFormatter());
});

在执行操作时,您仍然需要检查两个参数中的哪个实际上已填充:

[HttpPost]    
public async Task<IActionResult> ExternalLogin([FromForm] ExternalLoginModel formModel, [FromBody] ExternalLoginModel bodyModel)
{
    ExternalLoginModel model;

    // need to check if it is actually a form content type, as formModel may be bound to an empty instance
    if (Request.HasFormContentType && formModel != null)
    {
        model = formModel;
    }
    else if (bodyModel != null)
    {
        model = bodyModel;
    }

    ...