NET Core v2(2015) MVC: 如何将原始 JSON 绑定到没有类型的字符串?

与关于以前 ASP.NET 版本的 这个老问题类似,我希望将 HTTP POST 的请求体绑定到一个字符串。当 ASP.NET 调用我的控制器方法时,这个方法似乎是绑定的,但是 value是空的:

namespace Demo.Controllers
{


[Route("[controller]")]
public class WebApiDemoController : Controller
{
...


// POST api/values
[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]string value)
{
// expected: value = json string, actual: json = null.
}

我还得去溪流里捞尸体吗?还是这样就行了?在测试上述方法时,我使用了以下 http 头:

Accept: Application/json
Content-Type: Application/json;charset=UTF-8

我在身体里传递以下信息: { "a": 1 }

我不想绑定到一个名为 a. 的字符串变量,我想绑定任何我得到的 JSON,然后我想使用 JSON 内容,任何任意的内容,从我的方法。

如果我理解了文档,那么 [FromBody]属性应该已经做了我想做的事情,但是我猜测 ASP.NET 核心 MVC 绑定机制不会将 json 绑定到“字符串值”,但是也许我可以做一些其他的事情,让我获得同等水平的灵活性。

一个类似的问题 给你给我的想法,也许我应该写 [FromBody] dynamic data而不是使用 [FromBody] string value

更新: 这里有.net 核心6和其他现代.net 核心版本的答案。

90273 次浏览

您需要一个类型来绑定数据。示例:

public class Person
{
public string Name {get; set;}
}

数据 { "Name" : "James"}

如果要接收字符串,则需要将其作为字符串传递。你的 JSON应该附上引号:

'{ "a": 1 }'

下面的代码适用于.net core 1.x,但不适用于.net core 2.x。

正如我所说的,解决方案是使用 [FromBody]dynamic data作为我的参数列表,使用 dynamic而不是 string,我将收到一个 JObject

警告: 如果您的架构要求单个 WebAPI 服务器同样流畅地生成 XML 和 JSON,这取决于内容类型的头条目,这种直接使用 JSON 的策略可能适得其反。(在同一个服务上同时支持 XML 和 JSON 是可能的,只要有足够的工作量,但是你需要把那些在 MVC 资产管道上更进一步的东西移动到你的控制器方法中,这是违背 MVC 的精神的,在那里模型已经被解析了

一旦转换为方法内的字符串,就将传入的 JObject(JSON 的内存数据类型为 Newtonsoft.JSON)转换为字符串。

另一个答案发现的。

示例代码,感谢 Jeson Martajaya:

动态:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]dynamic value)
{
//...
}

使用 JObject 的示例代码:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]Newtonsoft.Json.Linq.JObject value)
{
//...
}

或者,您也可以只接受一个 JObject,如果您确实需要字符串,您甚至可以直接使用 Linq to Json,甚至 ToString()

我看到 Sam 已经因为说了几乎相同的事情而被投票否决了,但是在使用 Postman 进行测试时,我发现如果我将请求主体设置为一个简单的双引号字符串 ASP 用默认的“[ FromBody ] string value”参数绑定它,那么结果会很好。

"just send your string like this without any curly braces"

不确定 application/json 是否应该接受这种格式的数据。希望通过张贴这个有知识的人将管道,并声明这是否有效与否。

我找到的最干净的选项是添加您自己的简单 InputFormatter:

public class RawJsonBodyInputFormatter : InputFormatter
{
public RawJsonBodyInputFormatter()
{
this.SupportedMediaTypes.Add("application/json");
}


public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}


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

在 ConfigureServices 的 Startup.cs 中:

services
.AddMvc(options =>
{
options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
});

这将允许您在控制器中获得原始的 JSON 有效负载:

[HttpPost]
public IActionResult Post([FromBody]string value)
{
// value will be the request json payload
}

以下两个方法在 ASP.NET core 2中用于读取原始 json 字符串。

1)这个性能更好。

    [HttpPost]
public async Task<ActionResult<int>> Process()
{
string jsonString;
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
jsonString = await reader.ReadToEndAsync();
}

2)

    [HttpPost]
public async Task<ActionResult<int>> Process([FromBody]JToken jsonbody)
{
var jsonString = jsonBody.ToString();

基于 Saeb Amini 上面的出色回答,这也将他的解决方案扩展为纯文本。这里唯一的变化是添加了 "text/plain"哑剧类型,并添加了 namespace和所需的 using

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters;


namespace AspExtensions // or whatever
{
// see: https://stackoverflow.com/a/47807117/264031
public class RawStringBodyInputFormatter : InputFormatter
{
public RawStringBodyInputFormatter()
{
this.SupportedMediaTypes.Add("text/plain");
this.SupportedMediaTypes.Add("application/json");
}


public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
using(var reader = new StreamReader(request.Body)) {
string content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}


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

为 ASP.NET Core 3.1 Web API 找到了一个解决方案。

看来如下:

public async Task<IActionResult> PutAsync([FromBody] System.Text.Json.JsonElement entity)
{
// your code here
}

如果你没有放弃自动绑定,这可以直接放在控制器上的 Http 处理程序中:

using StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8);
var value = reader.ReadToEndAsync().GetAwaiter().GetResult();