Asp.net mvc MVC控制器:从HTTP主体获取JSON对象?

Asp.net mvc MVC控制器:从HTTP主体获取JSON对象?,asp.net-mvc,json,post,Asp.net Mvc,Json,Post,我们有一个MVC(MVC4)应用程序,它有时可能会将JSON事件从第三方发布到我们的特定URL(“”)。JSON事件位于HTTP POST的正文中,正文严格地说是JSON(内容类型:application/JSON-不是在某些字符串字段中带有JSON的表单POST) 如何在控制器的主体内接收JSON主体?我尝试了以下方法,但没有得到任何结果 [编辑]:当我说没有得到任何东西时,我的意思是jsonBody总是空的,不管我是将它定义为对象还是字符串 [HttpPost] // this maps t

我们有一个MVC(MVC4)应用程序,它有时可能会将JSON事件从第三方发布到我们的特定URL(“”)。JSON事件位于HTTP POST的正文中,正文严格地说是JSON(
内容类型:application/JSON
-不是在某些字符串字段中带有JSON的表单POST)

如何在控制器的主体内接收JSON主体?我尝试了以下方法,但没有得到任何结果

[编辑]:当我说没有得到任何东西时,我的意思是jsonBody总是空的,不管我是将它定义为
对象还是
字符串

[HttpPost]
// this maps to http://server.com/events/
// why is jsonBody always null ?!
public ActionResult Index(int? id, string jsonBody)
{
    // Do stuff here
}
请注意,我知道如果我给declare方法一个强类型的输入参数,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变体)


使用
Request.Form
获取数据

控制器:

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

我写这篇文章是为了尝试

视图:


$(函数(){
var测试={
电话:456,
姓名:“Ryu”
}
$(“#btnPost”)。单击(函数(){
$.post('@Url.Action(“Index”,“Home”)”,JSON.stringify(test));
});
});
并写入
Request。表单[0]
Request。控制器中的参数[0]
可以获取数据


我不会在视图中写入
标记。

您可以将json字符串作为
操作结果的参数,然后使用

现举一个例子


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


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

  • 内容类型:应用程序/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

}
此外,如果您希望以字符串形式访问请求正文以自己对其进行解析,则应使用
request.body
而不是
request.InputStream

Stream req = Request.Body;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
一旦您定义了一个类(MyDTOClass)来指示您希望接收的内容,它就应该像

public ActionResult Post([FromBody]MyDTOClass inputData){
 ... do something with input data ...
}
Thx致朱利亚斯:

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


内容类型:application/json

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

我需要以下几点才能让它工作:

  • 控制器动作

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

    public class Model
    {
        public string Test { get; set; }
        // ...
    }
    
  • 邮递员请求的标题,特别是,
    内容类型

  • 请求体中的json


那么,您将如何使用if/else解析数百种不同的JSON变体?@TheVillageIdiot:它们作为一个JSON对象转储到日志中。这就是为什么我只关心它们作为JSON对象或字符串的原因,而不关心它们内部的内容。您可以将JSON字符串作为ActionResult的参数来获取-如何?这是最初的问题,因为我无法获取带有数据的jsonBody。jsonBody==null,即使我将jsonBody定义为
string
Object
!HTML帖子正文中没有表单——HTML帖子的正文是纯json。因此Request.Form[0]=null(其计数为0)。没有
标记并不重要-代码中的HTTP头是
内容类型:application/x-www-Form-urlencoded;字符集=UTF-8
。检查fiddler中的输出。这就是它看起来像表单提交的原因。jQuery在发布AJAX内容时默认使用表单编码的数据,这就是为什么后端会填充表单,它说jQuery在哪里发布数据?只要内容类型:application/x-www-FORM-urlencoded;已设置,请求。表单[0]非常有效注意,如果关闭StreamReader,默认情况下它将关闭流,因此如果您还有其他内容正在读取流,请确保将重载与
leaveOpen:false
(我忘了流是否在MVC中读取过一次,我知道它在WebAPI中)最好使用模型参数,而不是手动读取和反序列化。是的,但这是不可能的,因为它是一个第三方API。@afollestad如何?你能举个例子吗。这是因为DeepSpace101的答案是可行的,但看起来太费劲了。我认为ASP.NETMVC有一些更简单的方法可以从ajax调用中获得这个值。提前感谢。@PawanPillai您只需使用
InputClass
作为索引操作方法的参数。ASP.NET MVC将自动将传入的JSON绑定到模型obect。只有当发送到单个端点的JSON结构发生变化时,读取输入流才有用。这在WebAPI中是可行的,问题是MVC。实际上,无论您使用的是WebAPI还是MVC。只要客户端发送一个符合yout DTO的JSON负载,这就可以工作。@xjuice如果您使用的是Core,但例如MVC 5,这就不起作用。
public ActionResult Post([FromBody]MyDTOClass inputData){
 ... do something with input data ...
}
[HttpPost]
[PermitAllUsers]
[Route("Models")]
public JsonResult InsertOrUpdateModels(Model entities)
{
    // ...
    return Json(response, JsonRequestBehavior.AllowGet);
}
public class Model
{
    public string Test { get; set; }
    // ...
}