简体   繁体   English

如何将json POST数据作为对象传递给Web API方法?

[英]How to pass json POST data to Web API method as an object?

ASP.NET MVC4 Web API application defines post method to save customer. ASP.NET MVC4 Web API应用程序定义了保存客户的post方法。 Customer is passed in json format in POST request body. 客户在POST请求正文中以json格式传递。 Customer parameter in post method contains null values for properties. post方法中的customer参数包含属性的空值。

How to fix this so that posted data will passed as customer object ? 如何解决这个问题,以便发布的数据作为客户对象传递?

If possible Content-Type: application/x-www-form-urlencoded should used since I dont know how to change it in javascript method which posts form. 如果可能的话Content-Type:application / x-www-form-urlencoded应该使用,因为我不知道如何在发布表单的javascript方法中更改它。

Controller: 控制器:

public class CustomersController : ApiController {

  public object Post([FromBody] Customer customer)
        {
            return Request.CreateResponse(HttpStatusCode.OK,
            new
            {
                customer = customer
            });
        }
    }
}

public class Customer
    {
        public string company_name { get; set; }
        public string contact_name { get; set; }
     }

Request: 请求:

POST http://localhost:52216/api/customers HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

{"contact_name":"sdfsd","company_name":"ssssd"}

EDIT : 31/10/2017 编辑 :31/10/2017

The same code/approach will work for Asp.Net Core 2.0 as well. 相同的代码/方法也适用于Asp.Net Core 2.0 The major difference is, In asp.net core, both web api controllers and Mvc controllers are merged together to single controller model. 主要区别在于,在asp.net核心中,web api控制器和Mvc控制器都合并到单个控制器模型中。 So your return type might be IActionResult or one of it's implementation (Ex : OkObjectResult ) 所以你的返回类型可能是IActionResult或其中一个实现(例如: OkObjectResult


Use 使用

contentType:"application/json"

You need to use JSON.stringify method to convert it to JSON string when you send it, 发送时需要使用JSON.stringify方法将其转换为JSON字符串,

And the model binder will bind the json data to your class object. 模型绑定器将json数据绑定到您的类对象。

The below code will work fine (tested) 以下代码将正常工作(测试)

$(function () {
    var customer = {contact_name :"Scott",company_name:"HP"};
    $.ajax({
        type: "POST",
        data :JSON.stringify(customer),
        url: "api/Customer",
        contentType: "application/json"
    });
});

Result 结果

在此输入图像描述

contentType property tells the server that we are sending the data in JSON format. contentType属性告诉服务器我们正在以JSON格式发送数据。 Since we sent a JSON data structure,model binding will happen properly. 由于我们发送了JSON数据结构,因此模型绑定将正确发生。

If you inspect the ajax request's headers, you can see that the Content-Type value is set as application/json . 如果检查ajax请求的标头,则可以看到Content-Type值设置为application/json

If you do not specify contentType explicitly, It will use the default content type which is application/x-www-form-urlencoded; 如果您没有明确指定contentType,它将使用默认的内容类型,即application/x-www-form-urlencoded;


Edit on Nov 2015 to address other possible issues raised in comments 2015年11月编辑,以解决评论中提出的其他可能问题

Posting a complex object 发布复杂对象

Let's say you have a complex view model class as your web api action method parameter like this 假设你有一个复杂的视图模型类作为你的web api动作方法参数

public class CreateUserViewModel
{
   public int Id {set;get;}
   public string Name {set;get;}  
   public List<TagViewModel> Tags {set;get;}
}
public class TagViewModel
{
  public int Id {set;get;}
  public string Code {set;get;}
}

and your web api end point is like 和你的web api终点就像

public class ProductController : Controller
{
    [HttpPost]
    public CreateUserViewMode Save([FromBody] CreateUserViewModel m)
    {
        // I am just returning the posted model as it is. 
        // You may do other stuff and return different response.
        // Ex : missileService.LaunchMissile(m);
        return m;
    }
}

At the time of this writing, ASP.NET MVC 6 is the latest stable version and in MVC6, Both Web api controllers and MVC controllers are inheriting from Microsoft.AspNet.Mvc.Controller base class. 在撰写本文时,ASP.NET MVC 6是最新的稳定版本,在MVC6中,Web api控制器和MVC控制器都继承自Microsoft.AspNet.Mvc.Controller基类。

To send data to the method from client side, the below code should work fine 要从客户端向方法发送数据,下面的代码应该可以正常工作

//Build an object which matches the structure of our view model class
var model = {
    Name: "Shyju",
    Id: 123,
    Tags: [{ Id: 12, Code: "C" }, { Id: 33, Code: "Swift" }]
};

$.ajax({
    type: "POST",
    data: JSON.stringify(model),
    url: "../product/save",
    contentType: "application/json"
}).done(function(res) {       
    console.log('res', res);
    // Do something with the result :)
});

Model binding works for some properties, but not all ! 模型绑定适用于某些属性,但不是全部! Why ? 为什么?

If you do not decorate the web api method parameter with [FromBody] attribute 如果不使用[FromBody]属性修饰web api方法参数

[HttpPost]
public CreateUserViewModel Save(CreateUserViewModel m)
{
    return m;
}

And send the model(raw javascript object, not in JSON format) without specifying the contentType property value 并且在不指定contentType属性值的情况下发送模型(原始javascript对象,而不是JSON格式)

$.ajax({
    type: "POST",
    data: model,
    url: "../product/save"
}).done(function (res) {
     console.log('res', res);
});

Model binding will work for the flat properties on the model, not the properties where the type is complex/another type. 模型绑定适用于模型上的平面属性,而不适用于类型复杂/其他类型的属性。 In our case, Id and Name properties will be properly bound to the parameter m , But the Tags property will be an empty list. 在我们的例子中, IdName属性将正确绑定到参数m ,但Tags属性将是一个空列表。

The same problem will occur if you are using the short version, $.post which will use the default Content-Type when sending the request. 如果您使用的是简短版本$.post ,在发送请求时将使用默认的Content-Type,则会出现同样的问题。

$.post("../product/save", model, function (res) {
    //res contains the markup returned by the partial view
    console.log('res', res);
});

Working with POST in webapi can be tricky! 在webapi中使用POST可能很棘手! Would like to add to the already correct answer.. 想补充已经正确的答案..

Will focus specifically on POST as dealing with GET is trivial. 将专注于POST,因为处理GET是微不足道的。 I don't think many would be searching around for resolving an issue with GET with webapis. 我不认为很多人会用webapis解决GET问题。 Anyways.. 无论如何..

If your question is - In MVC Web Api, how to- - Use custom action method names other than the generic HTTP verbs? 如果您的问题是 - 在MVC Web Api中,如何 - 使用除通用HTTP谓词之外的自定义操作方法名称? - Perform multiple posts? - 执行多个帖子? - Post multiple simple types? - 发布多个简单类型? - Post complex types via jQuery? - 通过jQuery发布复杂类型?

Then the following solutions may help: 那么以下解决方案可能有所帮助

First, to use Custom Action Methods in Web API, add a web api route as: 首先,要在Web API中使用自定义操作方法,请将web api路由添加为:

public static void Register(HttpConfiguration config)
{
    config.Routes.MapHttpRoute(
        name: "ActionApi",
        routeTemplate: "api/{controller}/{action}");
}

And then you may create action methods like: 然后你可以创建动作方法,如:

[HttpPost]
public string TestMethod([FromBody]string value)
{
    return "Hello from http post web api controller: " + value;
}

Now, fire the following jQuery from your browser console 现在,从浏览器控制台激发以下jQuery

$.ajax({
    type: 'POST',
    url: 'http://localhost:33649/api/TestApi/TestMethod',
    data: {'':'hello'},
    contentType: 'application/x-www-form-urlencoded',
    dataType: 'json',
    success: function(data){ console.log(data) }
});

Second, to perform multiple posts , It is simple, create multiple action methods and decorate with the [HttpPost] attrib. 第二,要执行多个帖子 ,很简单,创建多个动作方法并用[HttpPost] attrib进行装饰。 Use the [ActionName("MyAction")] to assign custom names, etc. Will come to jQuery in the fourth point below 使用[ActionName(“MyAction”)]分配自定义名称等。将在下面的第四点讨论jQuery

Third, First of all, posting multiple SIMPLE types in a single action is not possible. 第三,首先,不可能在单个动作中发布多个SIMPLE类型。 Moreover, there is a special format to post even a single simple type (apart from passing the parameter in the query string or REST style). 此外,有一种特殊的格式可以发布一个简单的类型 (除了在查询字符串或REST样式中传递参数)。 This was the point that had me banging my head with Rest Clients (like Fiddler and Chrome's Advanced REST client extension) and hunting around the web for almost 5 hours when eventually, the following URL proved to be of help. 这就是让我与Rest Clients(如Fiddler和Chrome的高级REST客户端扩展)一起敲打头脑并在网上狩猎近5个小时的时间点,最终,以下网址被证明是有帮助的。 Will quote the relevant content for the link might turn dead! 会引用该链接的相关内容可能会变死!

Content-Type: application/x-www-form-urlencoded
in the request header and add a = before the JSON statement:
={"Name":"Turbo Tina","Email":"na@Turbo.Tina"}

PS: Noticed the peculiar syntax ? PS:注意到特殊的语法

http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api

Anyways, let us get over that story. 无论如何,让我们克服那个故事。 Moving on: 继续:

Fourth, posting complex types via jQuery, ofcourse, $.ajax() is going to promptly come in the role: 第四,通过jQuery,ofcourse,$ .ajax() 发布复杂类型将立即发挥作用:

Let us say the action method accepts a Person object which has an id and a name. 我们假设action方法接受一个具有id和name的Person对象。 So, from javascript: 所以,从javascript:

var person = { PersonId:1, Name:"James" }
$.ajax({
    type: 'POST',
    url: 'http://mydomain/api/TestApi/TestMethod',
    data: JSON.stringify(person),
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function(data){ console.log(data) }
});

And the action will look like: 行动将如下所示:

[HttpPost]
public string TestMethod(Person person)
{
    return "Hello from http post web api controller: " + person.Name;
}

All of the above, worked for me!! 以上所有,为我工作!! Cheers! 干杯!

I've just been playing with this and discovered a rather odd result. 我刚刚玩这个并发现了一个相当奇怪的结果。 Say you have public properties on your class in C# like this: 假设您在C#中拥有公共属性,如下所示:

public class Customer
{
    public string contact_name;
    public string company_name;
}

then you must do the JSON.stringify trick as suggested by Shyju and call it like this: 然后你必须按照Shyju的建议做JSON.stringify技巧,并像这样调用它:

var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
    type: "POST",
    data :JSON.stringify(customer),
    url: "api/Customer",
    contentType: "application/json"
});

However, if you define getters and setters on your class like this: 但是,如果您在类上定义getter和setter,如下所示:

public class Customer
{
    public string contact_name { get; set; }
    public string company_name { get; set; }
}

then you can call it much more simply: 然后你可以更简单地调用它:

$.ajax({
    type: "POST",
    data :customer,
    url: "api/Customer"
});

This uses the HTTP header: 这使用HTTP标头:

Content-Type:application/x-www-form-urlencoded

I'm not quite sure what's happening here but it looks like a bug (feature?) in the framework. 我不太确定这里发生了什么,但它看起来像框架中的一个错误(功能?)。 Presumably the different binding methods are calling different "adapters", and while the adapter for application/json one works with public properties, the one for form encoded data doesn't. 据推测,不同的绑定方法调用不同的“适配器”,而应用程序/ json的适配器使用公共属性,而表单编码数据的适配器则不能。

I have no idea which would be considered best practice though. 我不知道哪个被认为是最好的做法。

Use the JSON.stringify() to get the string in JSON format, ensure that while making the AJAX call you pass below mentioned attributes: 使用JSON.stringify()以JSON格式获取字符串,确保在进行AJAX调用时传递下面提到的属性:

  • contentType: 'application/json' contentType:'application / json'
  • dataType: 'json' dataType:'json'

Below is the give jquery code to make ajax post call to asp.net web api: 下面是给jQuery的代码来调用asp.net web api的ajax:

 var product = JSON.stringify({ productGroup: "Fablet", productId: 1, productName: "Lumia 1525 64 GB", sellingPrice: 700 }); $.ajax({ URL: 'http://localhost/api/Products', type: 'POST', contentType: 'application/json', dataType: 'json', data: product, success: function (data, status, xhr) { alert('Success!'); }, error: function (xhr, status, error) { alert('Update Error occurred - ' + error); } }); 

Make sure that your WebAPI service is expecting a strongly typed object with a structure that matches the JSON that you are passing. 确保您的WebAPI服务期望一个强类型对象,其结构与您传递的JSON相匹配。 And make sure that you stringify the JSON that you are POSTing. 并确保您对要发布的JSON进行字符串化。

Here is my JavaScript (using AngluarJS): 这是我的JavaScript(使用AngluarJS):

$scope.updateUserActivity = function (_objuserActivity) {
        $http
        ({
            method: 'post',
            url: 'your url here',
            headers: { 'Content-Type': 'application/json'},
            data: JSON.stringify(_objuserActivity)
        })
        .then(function (response)
        {
            alert("success");
        })
        .catch(function (response)
        {
            alert("failure");
        })
        .finally(function ()
        {
        });

And here is my WebAPI Controller: 这是我的WebAPI控制器:

[HttpPost]
[AcceptVerbs("POST")]
public string POSTMe([FromBody]Models.UserActivity _activity)
{
    return "hello";
}

Following code to return data in the json format ,instead of the xml -Web API 2 :- 以下代码以json格式返回数据,而不是xml -Web API 2: -

Put following line in the Global.asax file 将以下行放在Global.asax文件中

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
@model MVCClient.Models.ProductDetails

@{
    ViewBag.Title = "ProductDetails";
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript">

    $(document).ready(function () {
        $("#Save").click(function () {
            var ProductDetails = new Object();
            ProductDetails.ProductName =  $("#txt_productName").val();
            ProductDetails.ProductDetail = $("#txt_desc").val();
            ProductDetails.Price= $("#txt_price").val();
            $.ajax({
                url: "http://localhost:24481/api/Product/addProduct",
                type: "Post",
                dataType:'JSON',
                data:ProductDetails, 

                success: function (data) {
                    alert('Updated Successfully');
                    //window.location.href = "../Index";
                },
                error: function (msg) { alert(msg); }
            });
        });
    });
    </script>
<h2>ProductDetails</h2>

<form id="form1" method="post">
    <fieldset>
        <legend>ProductDetails</legend>


        <div class="editor-label">
            @Html.LabelFor(model => model.ProductName)
        </div>
        <div class="editor-field">

            <input id="txt_productName" type="text" name="fname">
            @Html.ValidationMessageFor(model => model.ProductName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductDetail)
        </div>
        <div class="editor-field">

            <input id="txt_desc" type="text" name="fname">
            @Html.ValidationMessageFor(model => model.ProductDetail)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">

            <input id="txt_price" type="text" name="fname">
            @Html.ValidationMessageFor(model => model.Price)
        </div>



        <p>
            <input id="Save" type="button" value="Create" />
        </p>
    </fieldset>

</form>
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>

</form>



@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Microsoft gave a good example of doing this: 微软给出了一个很好的例子:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1 https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-1

First validate the request 首先验证请求

if (ModelState.IsValid)

and than use the serialized data. 而不是使用序列化数据。

Content = new StringContent(update.Status)

Here 'Status' is a field in the complex type. 这里的“状态”是复杂类型中的一个字段。 Serializing is done by .NET, no need to worry about that. 序列化由.NET完成,无需担心。

1)In your client side you can send you http.post request in string like below 1)在您的客户端,您可以发送http.post请求,如下所示

var IndexInfo = JSON.stringify(this.scope.IndexTree);
this.$http.post('../../../api/EvaluationProcess/InsertEvaluationProcessInputType', "'" + IndexInfo + "'" ).then((response: any) => {}

2)Then in your web api controller you can deserialize it 2)然后在您的web api控制器中,您可以反序列化它

public ApiResponce InsertEvaluationProcessInputType([FromBody]string IndexInfo)
    {
var des = (ApiReceivedListOfObjects<TempDistributedIndex>)Newtonsoft.Json.JsonConvert.DeserializeObject(DecryptedProcessInfo, typeof(ApiReceivedListOfObjects<TempDistributedIndex>));}

3)Your ApiReceivedListOfObjects class should be like below 3)您的ApiReceivedListOfObjects类应如下所示

public class ApiReceivedListOfObjects<T>
    {
        public List<T> element { get; set; }

    }

4)make sure that your serialized string (IndexInfo here) becomes like below structure before JsonConvert.DeserializeObject command in step 2 4)确保您的序列化字符串(此处为IndexInfo)在步骤2中的JsonConvert.DeserializeObject命令之前变为下面的结构

var resp = @"
    {
        ""element"": [
        {
            ""A"": ""A Jones"",
            ""B"": ""500015763""
        },
        {
            ""A"": ""B Smith"",
            ""B"": ""504986213""
        },
        {
            ""A"": ""C Brown"",
            ""B"": ""509034361""
        }
        ]
    }";

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM