ASP.NET Core 3.1 Web Api HttpPost Action参数无法接收axios application/json HttpPost传递数据

ASP.NET Core 3.1 Web Api HttpPost Action parameter can't receive axios application/json HttpPost passing data

我以前用Controller代替ApiController,今天我试着用ApiController,发现下面的问题。

ASP.NET Core Web Api HttpPost Action 参数无法接收axios application/json post 传递数据

asp.net核心api代码

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> Post(string json)
    {
        return this.Ok();
    }
}

前端

var json = '{"json_data":"{\"value\":\"hello world\"}';
axios.post('Test', {"json": json})
    .then(function (response) {
        console.log(response);
    })
    .catch(function (error) {
        console.log(error);
    });   

实际要求

Accept:application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Content-Type: application/json;charset=UTF-8
Request Payload : 
{"json_data":"{\"value\":\"hello world\"}

实际操作json参数数据为null 预期接收数据:{"json_data":"{\"value\":\"hello world\"}


更新

我尝试了下面的代码,我得到了 rawValue value = {"json_data":"{\"value\":\"hello world\"} 但是 json value = null

[HttpPost]
public async Task<IActionResult> Post(string json)
{
    using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
    {
        string rawValue = await reader.ReadToEndAsync();
    }
}

更新:

Demo Source Code Link

我终于用[FromBody]System.Text.Json.JsonElement解决了问题

[HttpPost]
[Route("TestUsingFromBodyAttribute")]
public object TestUsingFromBodyAttribute([FromBody] System.Text.Json.JsonElement content)
{
    return content;
}

因为axios默认Content-Type: application/x-www-form-urlencoded 它需要更新 Content-Type': 'application/json,否则系统将显示 415 unsupported media type

然后就不能使用string类型,否则系统会显示400 bad request

因为 asp.net 核心检查 Content-Type': 'application/json 并使用 [FromBody] 将自动转换为 json 对象 (System.Text.Json.JsonElement),所以这就是它不能的原因使用字符串类型。

如果不想编辑 axios 默认值 Content-Type: application/x-www-form-urlencoded,则必须设置 reqeust data is object not string

阅读 :


早期回答:

现在我用Request.Body不是Action Parameter来解决这个问题,但我仍然不知道为什么它不能。

[HttpPost]
public async Task<IActionResult> Post()
{
    string json = null;
    using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
    {
        json = await reader.ReadToEndAsync();
    }
    //..etc
}

您应该使用 FromBodyAttribute 进行正确映射。

public async Task Post(string json)

如果您想使用数据从前端发出 HTTP 请求并将其绑定到 字符串类型 ACTION参数正确,你可以尝试实现和使用自定义的纯文本输入格式器。

public class TextPlainInputFormatter : TextInputFormatter
{
    public TextPlainInputFormatter()
    {
        SupportedMediaTypes.Add("text/plain");
        SupportedEncodings.Add(UTF8EncodingWithoutBOM);
        SupportedEncodings.Add(UTF16EncodingLittleEndian);
    }

    protected override bool CanReadType(Type type)
    {
        return type == typeof(string);
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        string data = null;
        using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
        {
            data = await streamReader.ReadToEndAsync();
        }
        return InputFormatterResult.Success(data);
    }
}

配置和添加自定义格式化程序支持

services.AddControllers(opt => opt.InputFormatters.Insert(0, new TextPlainInputFormatter()));

前端代码

const headers = {
    'Content-Type': 'text/plain'
};

var json = '{"json_data":"{\"value\":\"hello world\"}';

axios.post('test', json, { headers: headers })
    .then(function (response) {
        //...

测试结果