【问题标题】:MVC controller : get JSON object from HTTP body?MVC 控制器:从 HTTP 主体获取 JSON 对象?
【发布时间】:2012-10-24 01:37:23
【问题描述】:

我们有一个 MVC (MVC4) 应用程序,它有时可能会收到一个 JSON 事件从第 3 方发布到我们的特定 URL(“http://server.com/events/”)。 JSON 事件在 HTTP POST 的正文中,并且正文是严格的 JSON(Content-Type: application/json - 不是在某些字符串字段中带有 JSON 的表单发布)。

如何在控制器主体中接收 JSON 主体?我尝试了以下但没有得到任何东西

[编辑]:当我说 什么都没有得到时,我的意思是 jsonBody 始终为 null,无论我将其定义为 Object 还是 string .

[HttpPost]
// this maps to http://server.com/events/
// why is jsonBody always null ?!
public ActionResult Index(int? id, string jsonBody)
{
    // Do stuff here
}

请注意,如果我使用强类型输入参数声明方法,MVC 会执行整个解析和过滤,即

// this tested to work, jsonBody has valid json data 
// that I can deserialize using JSON.net
public ActionResult Index(int? id, ClassType847 jsonBody) { ... }

但是,我们得到的 JSON 非常多样化,因此我们不想为每个 JSON 变体定义(和维护)数百个不同的类。

我正在通过以下 curl 命令(此处使用 JSON 的一种变体)对此进行测试

curl -i -H "Host: localhost" -H "Content-Type: application/json" -X POST http://localhost/events/ -d '{ "created": 1326853478, "data": { "object": { "num_of_errors": 123, "fail_count": 3 }}}

【问题讨论】:

  • 那么你将如何使用 if/else 解析数百种不同的 JSON 变体?
  • @TheVillageIdiot:它们每个都作为一个 JSON 对象转储到日志中。所以这就是为什么我只关心它们作为 JSON 对象或字符串 - 不关心它们里面的内容。

标签: asp.net-mvc json post


【解决方案1】:

如果

  • Content-Type: application/json
  • 如果 POST 主体未紧密绑定到控制器的输入对象类

然后 MVC 并没有真正将 POST 主体绑定到任何特定的类。您也不能只获取 POST 正文作为 ActionResult 的参数(在另一个答案中建议)。很公平。您需要自己从请求流中获取并处理它。

[HttpPost]
public ActionResult Index(int? id)
{
    Stream req = Request.InputStream;
    req.Seek(0, System.IO.SeekOrigin.Begin);
    string json = new StreamReader(req).ReadToEnd();

    InputClass input = null;
    try
    {
        // assuming JSON.net/Newtonsoft library from http://json.codeplex.com/
        input = JsonConvert.DeserializeObject<InputClass>(json)
    }

    catch (Exception ex)
    {
        // Try and handle malformed POST body
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    //do stuff

}

更新:

对于 Asp.Net Core,对于复杂的 JSON 数据类型,您必须在控制器操作中的参数名称旁边添加 [FromBody] 属性:

[HttpPost]
public ActionResult JsonAction([FromBody]Customer c)

另外,如果你想以字符串的形式访问请求体来自己解析它,你应该使用Request.Body而不是Request.InputStream

Stream req = Request.Body;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();

【讨论】:

  • 注意,如果你关闭 StreamReader,它会默认关闭流,所以如果你有其他东西在读取流,请确保使用 leaveOpen: false 的重载(我忘记了是否读取流- 一次在 MVC 中与否,我知道它在 WebAPI 中)
  • 最好使用模型参数,而不是手动读取和反序列化。
  • 是的,但这是不可能的,因为它是第 3 方 API。
  • @afollestad 怎么样?你能举个例子吗?这是因为 DeepSpace101 的答案是有效的,但看起来太费劲了。我认为 ASP.NET MVC 有一些更简单的方法可以从 ajax 调用中获取这个值。提前致谢。
  • @PawanPillai 您只需使用 InputClass 作为 Index 操作方法的参数。 ASP.NET MVC 会自动将传入的 JSON 绑定到模型对象。仅当发送到单个端点的 JSON 的结构可以更改时,读取输入流才有用。
【解决方案2】:

使用Request.Form 获取数据

控制器:

    [HttpPost]
    public ActionResult Index(int? id)
    {
        string jsonData= Request.Form[0]; // The data from the POST
    }

我写这个试试

查看:

<input type="button" value="post" id="btnPost" />

<script type="text/javascript">
    $(function () {
        var test = {
            number: 456,
            name: "Ryu"
        }
        $("#btnPost").click(function () {
            $.post('@Url.Action("Index", "Home")', JSON.stringify(test));
        });
    });
</script>

在控制器中写入Request.Form[0]Request.Params[0]即可获取数据。

我不会在视图中写&lt;form&gt; tag

【讨论】:

  • HTML POST 正文中没有表单 - HTML POST 的正文是纯 json。所以 Request.Form[0] = null (计数为 0)。
  • 没有&lt;form&gt; 标记无关紧要 - 您代码中的 HTTP 标头是 Content-Type: application/x-www-form-urlencoded; charset=UTF-8。检查提琴手的输出。这就是它看起来像 FORM 提交的原因。
  • jQuery 在发布 AJAX 内容时默认使用表单编码数据,这就是后端填充表单的原因
  • jquery 在哪里发布数据?
  • 只要Content-Type: application/x-www-form-urlencoded;已设置,Request.Form[0] 效果很好
【解决方案3】:

我一直在尝试让我的 ASP.NET MVC 控制器解析我使用 Postman 提交给它的一些模型。

我需要以下内容才能让它工作:

  • 控制器动作

    [HttpPost]
    [PermitAllUsers]
    [Route("Models")]
    public JsonResult InsertOrUpdateModels(Model entities)
    {
        // ...
        return Json(response, JsonRequestBehavior.AllowGet);
    }
    
  • 模型类

    public class Model
    {
        public string Test { get; set; }
        // ...
    }
    
  • Postman 请求的标头,具体来说,Content-Type

  • 请求正文中的json

【讨论】:

    【解决方案4】:

    一旦你定义了一个类 (MyDTOClass) 来表明你希望收到什么,它应该像...

    public ActionResult Post([FromBody]MyDTOClass inputData){
     ... do something with input data ...
    }
    

    感谢朱莉娅:

    Parsing Json .Net Web Api

    确保您的请求使用 http 标头发送:

    内容类型:application/json

    【讨论】:

    • 这可以在 WebAPI 中使用,问题是指 MVC。
    • 使用 WebAPI 或 MVC 实际上并不重要。只要客户端发送符合您的 DTO 的 JSON 有效负载,这将起作用。
    • @xjuice 如果您使用的是 Core,但例如 MVC 5,这将不起作用。
    【解决方案5】:

    您可以将 json 字符串作为ActionResult 的参数,然后使用JSON.Net 对其进行序列化

    HERE 正在展示一个示例


    为了以序列化形式接收它作为控制器操作的参数,您必须编写自定义模型绑定器或操作过滤器(OnActionExecuting),以便将 json 字符串序列化为您喜欢的模型并可用在控制器主体内使用。


    HERE是一个使用动态对象的实现

    【讨论】:

    • 您可以将 json 字符串作为 ActionResult 的参数 - 如何? 这是最初的问题,因为我无法使用 jsonBody数据。 jsonBody == null 即使我将 jsonBody 定义为 stringObject
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 2017-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多