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

IT技术 javascript asp.net-mvc json asp.net-mvc-4 asp.net-web-api
2021-01-15 03:55:34

ASP.NET MVC4 Web API 应用程序定义了 post 方法来保存客户。客户在 POST 请求正文中以 json 格式传递。post 方法中的客户参数包含属性的空值。

如何解决这个问题,以便发布的数据将作为客户对象传递?

如果可能,应该使用 Content-Type: application/x-www-form-urlencoded ,因为我不知道如何在发布表单的 javascript 方法中更改它。

控制器:

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; }
     }

要求:

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"}
6个回答

编辑:31/10/2017

相同的代码/方法也适用于Asp.Net Core 2.0主要区别在于,在 asp.net core 中,web api 控制器和 Mvc 控制器合并在一起为单个控制器模型。所以,你的返回类型可能是IActionResult或它的实现之一(例如:OkObjectResult


利用

contentType:"application/json"

JSON.stringify发送时需要使用方法将其转换为JSON字符串,

模型绑定器会将 json 数据绑定到您的类对象。

下面的代码可以正常工作(已测试)

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

结果

在此处输入图片说明

contentType属性告诉服务器我们正在以 JSON 格式发送数据。由于我们发送了一个 JSON 数据结构,模型绑定将正确发生。

如果您检查 ajax 请求的标头,您可以看到该Content-Type值设置为application/json

如果您没有明确指定 contentType,它将使用默认的内容类型,即 application/x-www-form-urlencoded;


2015 年 11 月编辑以解决评论中提出的其他可能问题

发布一个复杂的对象

假设您有一个复杂的视图模型类作为您的 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;}
}

你的 web api 端点就像

public class ProductController : Controller
{
    [HttpPost]
    public CreateUserViewModel 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;
    }
}

在撰写本文时,ASP.NET MVC 6 是最新的稳定版本,在 MVC6 中,Web api 控制器和 MVC 控制器都继承自基Microsoft.AspNet.Mvc.Controller类。

要将数据从客户端发送到方法,下面的代码应该可以正常工作

//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 :)
});

模型绑定适用于某些属性,但不是全部!为什么 ?

如果没有用[FromBody]属性修饰web api方法参数

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

并发送模型(原始 javascript 对象,不是 JSON 格式)而不指定 contentType 属性值

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

模型绑定将适用于模型上的平面属性,而不是类型为复杂/其他类型的属性。在我们的例子中,IdName属性将正确绑定到的参数m,但Tags物业将是一个空列表。

如果您使用的是短版本,则会出现同样的问题,$.post它会在发送请求时使用默认的 Content-Type。

$.post("../product/save", model, function (res) {
    //res contains the markup returned by the partial view
    console.log('res', res);
});
不知道我做了什么,但我今天早上回来了,又坐了同一条船。对象在控制器中为空。我们又来了,哈哈
2021-03-14 03:55:34
确保在使用 fiddler 时内容类型写为“Content-Type: application/json”。干杯!
2021-03-16 03:55:34
请记住,如果您执行此操作(更改 Content-Type 标头)并且您正在发出 CORS 请求,则 jQuery 将开始在您的 POST 之前添加预检 OPTIONS 请求,服务器必须处理该请求。
2021-03-19 03:55:34
由于复杂类型的问题,我认为只指定 'contentType: 'application/json;' 是一种习惯 和 json 字符串化 js 对象,然后就不需要使用 [FromBody] 属性。
2021-03-19 03:55:34
你简直解决了我一天的工作!!!这个小函数“JSON.stringify(data)”成功了!
2021-04-10 03:55:34

在 webapi 中使用 POST 可能很棘手!想添加到已经正确的答案..

将特别关注 POST,因为处理 GET 是微不足道的。我不认为很多人会四处寻找解决 GET 与 webapis 的问题。无论如何..

如果您的问题是 - 在 MVC Web Api 中,如何 - - 使用通用 HTTP 动词以外的自定义操作方法名称?- 执行多个帖子?- 发布多个简单类型?- 通过 jQuery 发布复杂类型?

那么以下解决方案可能会有所帮助:

首先,要在 Web API 中使用自定义操作方法,请添加一个 Web API 路由:

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

然后你可以创建动作方法,如:

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

现在,从浏览器控制台启动以下 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) }
});

二、执行多个post,很简单,创建多个action方法,并用[HttpPost]属性进行装饰。使用[ActionName("MyAction")]来分配自定义名称等。下面第四点会来jQuery

第三,首先,在单个操作中发布多个SIMPLE类型是不可能的。此外,还有一种特殊格式可以发布甚至单个简单类型(除了在查询字符串或 REST 样式中传递参数)。这就是让我用 Rest Clients(如 Fiddler 和 Chrome 的高级 REST 客户端扩展)和在网上搜索近 5 个小时的重点,最终,以下 URL 被证明是有帮助的。将引用相关内容的链接可能会死!

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:注意到特殊的语法了吗?

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

不管怎样,让我们​​把那个故事过去。继续:

第四,通过 jQuery发布复杂类型,当然, $.ajax() 将立即发挥作用:

假设 action 方法接受一个具有 id 和名称的 Person 对象。所以,从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) }
});

操作将如下所示:

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

以上所有,对我有用!!干杯!

我似乎每隔几个月就会遇到这个问题,大部分时间我最终都会解决它,但这次我放弃了。上面的提示都没有为我解决这个问题,所以我决定把它作为一种方法。如果做对这么难,为什么还要麻烦呢?无论如何这只是一种方便 - 只需将内容作为字符串并使用 newtonsoft 对其进行转换。完毕。在尝试了大约一个小时以“简单”的方式解决它之后,大概花了 30 秒的时间来解决它“困难”的方式。我对这种方法并不狂热,但它是否存在根本问题?
2021-03-31 03:55:34
想补充一个观察。有时,在传递复杂类型(例如:DTO)时,WebAPI 端的模型绑定失败 (null) 的原因是模型中的一个或多个属性将不兼容(或无法解析)。例如。Guid 属性被分配了无效的 GUID。在这种情况下,请尝试对所有对象属性使用默认/空值,然后重试。
2021-04-05 03:55:34
PS:在 WebApi2 中,我们现在可以使用 Route Decorators。所以这个问题主要是解决了。 asp.net/web-api/overview/web-api-routing-and-actions/...
2021-04-08 03:55:34

我刚刚玩这个并发现了一个相当奇怪的结果。假设你的类在 C# 中有公共属性,如下所示:

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

那么你必须按照 Shyju 的建议执行 JSON.stringify 技巧并像这样调用它:

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

但是,如果您像这样在类上定义 getter 和 setter:

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

那么你可以更简单地称呼它:

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

这使用 HTTP 标头:

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

我不太确定这里发生了什么,但它看起来像是框架中的一个错误(功能?)。据推测,不同的绑定方法正在调用不同的“适配器”,虽然 application/json 的适配器使用公共属性,但表单编码数据的适配器却没有。

我不知道哪个会被认为是最佳实践。

这是因为代码只查找属性。由于使用公共字段不是最佳实践,MS 团队决定不允许最佳实践场景,恕我直言,这是一个很好的理由。
2021-03-12 03:55:34
这很真实,也很奇怪。只有字段的普通类不会绑定到表单帖子,但属性会。BTW:仍然没有解释为什么会这样......?我只能猜测内部逻辑只会将 JSON 数据绑定到字段,并将表单 post 数据绑定到属性,仅此而已......?
2021-04-05 03:55:34
属性与字段是其不同的原因。属性是最佳实践。你在第一个例子中所说的属性实际上是字段。当您在它们上放置 get/set 时,它们就会有一个自动创建的支持字段,使它们成为属性。
2021-04-07 03:55:34

使用JSON.stringify()获取 JSON 格式的字符串,确保在进行 AJAX 调用时传递以下提到的属性:

  • 内容类型:'应用程序/json'

下面是给 ajax post 调用 asp.net web api 的给 jquery 代码:

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',
    data: product,
    success: function (data, status, xhr) {
        alert('Success!');
    },
    error: function (xhr, status, error) {
        alert('Update Error occurred - ' + error);
    }
});

不需要数据类型。
2021-03-25 03:55:34

确保您的 WebAPI 服务需要一个结构与您传递的 JSON 相匹配的强类型对象。并确保您将要发布的 JSON 字符串化。

这是我的 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 ()
        {
        });

这是我的 WebAPI 控制器:

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