ASP.NET Core MVC:如何将原始JSON绑定到没有类型的字符串?

War*_* P 46 c# asp.net-mvc asp.net-web-api asp.net-core-mvc

类似这种关于ASP.NET之前老版本的问题,我希望得到一个HTTP POST请求体被绑定到一个字符串.value当ASP.NET调用我的控制器方法时,似乎该方法绑定,但是为null:

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

我还需要从溪流中抓住身体吗?或者这应该工作吗?在测试上述方法时,我使用了以下http标头:

Accept: Application/json
Content-Type: Application/json;charset=UTF-8
Run Code Online (Sandbox Code Playgroud)

我在身体中传递以下内容: { "a": 1 }

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

如果我理解了文档,该[FromBody]属性应该已经完成​​了我想要的,但我猜测ASP.NET核心MVC绑定机制不会将json绑定到"字符串值",但也许我可以做其他事情让我获得同等程度的灵活性.

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

更新:在执行此操作之前应该考虑这种技巧,因为如果您希望.net核心框架为您处理JSON和XML编码,那么您刚刚杀死了该功能.某些类型的REST服务器可以并且通常具有支持XML和JSON内容类型的要求,至少我遇到过具有标准文档的内容类型.

War*_* P 37

以下工作在.net core 1.x中,但不在.net core 2.x中.

正如我评论的那样,解决方案是使用[FromBody]dynamic data我的参数列表,dynamic而不是使用string,我会收到一个JObject.

警告:如果您的体系结构要求单个WebApi服务器在生成XML和JSON方面同样流畅,则根据内容类型标头条目,这种直接JSON消费策略可能适得其反.(通过足够的工作可以支持同一服务上的XML和JSON,但是你接下来的东西是MVC资产管道的进一步向下移动到你的控制器方法,这反映了MVC的精神,当POCO已经解析时,模型会出现在你身上.)

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

这里找到其他答案.

示例代码,感谢Jeson Martajaya:

动态:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]dynamic value)
{
   //...
}
Run Code Online (Sandbox Code Playgroud)

使用JObject的示例代码:

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

  • @WarrenP for .NetCore 3.0+ 您将需要显式引用 Microsoft.AspNetCore.Mvc.NewtonsoftJson 包,然后在启动中激活它: services.AddMvc().AddNewtonsoftJson() (2认同)

Sae*_*ini 36

我发现最干净的选择是添加自己的简单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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在ConfigureServices中的Startup.cs中:

services
    .AddMvc(options =>
    {
        options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
    });
Run Code Online (Sandbox Code Playgroud)

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

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

  • 那真是太美了.好一个.谢谢. (6认同)
  • 这个答案更好,因为它确实需要字符串(换句话说,在您决定自己完成之前,它不会将字符串解析为JSON) (5认同)

小智 17

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

看起来如下:

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


Xav*_*ohn 13

以下两种方法适用于 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();
        }
Run Code Online (Sandbox Code Playgroud)

2)

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


Fab*_*lai 6

或者,您也可以只接受a JObject,即使ToString()您确实需要字符串,也可以直接使用Linq to Json ot 。

  • 有时您不想要验证,而是想要灵活的自动查询功能。同样,如果目的地接受任何内容(您正在写入NoSQL文档数据库),则C#模型类是一个限制,而不是功能。 (3认同)
  • @WarrenP 我绝对是对象数据库项目的先驱,C# 模型类绝对是一个功能。如果您没有定义模型,无论是 C# 类、swagger 定义还是其他什么,当您无法再可靠地索引数据时,您最终会陷入痛苦的境地。对象数据库**不是**无模式,它们是松散模式。如果您没有更严格的结构(例如正确进行版本控制的 C# 类),那么您确实面临着即将发生的内爆。 (2认同)