MVC控制器:从HTTP正文获取JSON对象?


70

我们有一个MVC(MVC4)应用程序,该应用程序有时可能会收到从第三方发送到我们特定URL(“ http://server.com/events/ ”)的JSON事件。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 2012年

@TheVillageIdiot:将它们作为一个JSON对象分别转储到日志中。这就是为什么我只关心它们作为JSON对象或字符串的原因,而不关心它们里面的内容。
DeepSpace101 2012年

Answers:


145

看来,如果

  • 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,[FromBody]对于复杂的JSON数据类型,您必须在控制器操作中的参数名称旁边添加attrib:

[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中)
Thymine

1
最好使用Model参数,而不要手动读取和反序列化。
afollestad

是的,但这是不可能的,因为它是第三方API。
埃里克·凯利

@afollestad怎么样?你能举个例子吗?这是因为DeepSpace101的答案有效,但似乎需要太多努力。我以为ASP.NET MVC有一些更简单的方法来从ajax调用中获取此值。提前致谢。
Pawan Pillai

您只需将@PawanPillaiInputClass用作Index操作方法的参数。ASP.NET MVC将自动将传入的JSON绑定到模型对象。仅当发送到单个端点的JSON的结构可以更改时,读取输入流才有用。
nmit026

7

采用 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]在控制器中获取数据。

我不在<form> tag视野中写。


3
HTML POST主体中没有任何形式-HTML POST主体为纯json。因此,Request.Form [0] = null(其计数为0)。
DeepSpace101,2012年

1
没有<form>标签没关系-您代码中的HTTP标头是Content-Type: application/x-www-form-urlencoded; charset=UTF-8。检查提琴手的输出。这就是使它看起来像FORM提交的原因。
DeepSpace101,2012年

jQuery使用形式默认发布AJAX内容时编码的数据,这就是为什么在后台获取表格填充

1
它在哪里说jquery正在发布数据?
埃里克·凯利

只要Content-Type:application / x-www-form-urlencoded; 已设置,Request.Form [0]效果很好
AVH

2

我一直试图让我的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; }
        // ...
    }
    
  • 邮递员要求的标头,具体来说, Content-Type

    邮递员头

  • 请求正文中的json

    在此处输入图片说明


1

一旦定义了一个类(MyDTOClass)来指示期望接收的内容,它应该就像...

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

感谢朱莉亚斯:

解析Json .Net Web Api

确保您的请求带有http标头发送:

内容类型:application / json


2
可以在WebAPI中使用,该问题涉及MVC。
Alfredo A.

1
实际上,使用WebAPI还是MVC都没有关系。只要客户端发送符合您的DTO的JSON有效负载,它就可以工作。
xjuice

@xjuice如果使用的是Core(例如MVC 5),则将无法使用。
AaronLS

0

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

这里显示一个例子


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


这里是使用动态对象的实现


4
您可以将JSON字符串作为ActionResult的参数获取-怎么做?这是原始问题,因为我无法获取数据的jsonBody。jsonBody == null即使我将jsonBody定义为stringor Object
DeepSpace101 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.