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

A. *_*yer 5 c# api asp.net-core

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

这是我的功能

    [HttpPost]
    public async Task<IActionResult> ExternalLogin([FromForm]ExternalLoginModel formModel, [FromBody]ExternalLoginModel bodyModel)
    {
Run Code Online (Sandbox Code Playgroud)

所以我希望他们能够以两种不同的方式发送相同的数据,当我使用 form-data 尝试这种方法时,我收到了 415 错误。当我尝试使用原始 JSON 时,它工作正常。

我希望能够将它保留在一个函数中,但如果我必须将它分成两个,那就这样吧。

Red*_*one 5

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

如果你真的想在一个动作中处理这两种内容类型,你可以为身体模型绑定器实现一个输入格式化程序来绕过这种行为。如果请求具有表单内容类型,它可以通过假装绑定成功来实现。

格式化程序本身很简单:

/// <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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

services.AddMvc(options =>
{
    options.InputFormatters.Add(new BypassFormDataInputFormatter());
});
Run Code Online (Sandbox Code Playgroud)

在您的操作中,您仍然需要检查实际填充了两个参数中的哪一个:

[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;
    }

    ...
Run Code Online (Sandbox Code Playgroud)