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

编辑:31/10/2017

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


Use

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 action方法参数

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 MVC6是最新的稳定版本,在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);
});

模型绑定将适用于模型上的平面属性,而不适用于复杂类型/其他类型的属性。在本例中,Id和Name属性将正确地绑定到参数m,但Tags属性将是一个空列表。

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

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

在webapi中使用POST是很棘手的! 我想在已经正确的答案上再补充一下。

将特别关注POST,因为处理GET是微不足道的。我不认为有很多人会到处寻找通过webapi解决GET问题的方法。不管怎样. .

如果你的问题是-在MVC Web Api中,如何-使用自定义动作方法名而不是通用的HTTP动词?-执行多个帖子?-发布多个简单类型?- Post复杂类型通过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,这很简单,创建多个动作方法并用[HttpPost]属性装饰。使用[ActionName("MyAction")]来分配自定义名称,等等。将在下面第四点讲到jQuery

Third, First of all, posting multiple SIMPLE types in a single action is not possible. 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). 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. 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:注意到奇怪的语法了吗?

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

不管怎样,让我们忘掉那个故事吧。移动:

第四,通过jQuery发布复杂的类型,当然,$.ajax()将立即进入角色:

假设操作方法接受一个Person对象,该对象具有id和名称。因此,从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;
}

以上所有的方法都对我有用!!干杯!

我一直在研究这个问题,发现了一个相当奇怪的结果。假设在c#中你的类中有这样的公共属性:

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

那么你必须处理JSON。按照Shyju的建议,stringify trick,并如下所示:

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

我不太确定这里发生了什么,但它看起来像框架中的一个bug(功能?)假设不同的绑定方法调用不同的“适配器”,而application/json的适配器可以使用公共属性,而表单编码数据的适配器则不行。

不过,我不知道哪种做法才是最佳做法。

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

contentType:“application / json”

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

Var积= JSON.stringify ({ productGroup:“Fablet”, productId: 1、 productName:“Lumia 1525 64gb”, sellingPrice: 700 }); . ajax({美元 URL:“http://localhost/api/Products”, 类型:“文章”, contentType: application / json, 数据:产品, 成功:函数(数据,状态,xhr) { alert('成功! '); }, 错误:函数(xhr,状态,错误){ alert('更新错误发生- ' +错误); } });

确保您的WebAPI服务期望一个强类型对象,其结构与您传递的JSON相匹配。确保你对要发布的JSON进行了stringify。

这是我的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";
}

下面的代码返回json格式的数据,而不是xml - web API 2

在全局中放入以下一行。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")
}

微软给出了一个很好的例子:

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

首先验证请求

if (ModelState.IsValid)

然后使用序列化的数据。

Content = new StringContent(update.Status)

这里的“Status”是复杂类型中的一个字段。序列化是由。net完成的,不用担心。

1)在你的客户端,你可以给你发送http。在下面这样的字符串中提交请求

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

2)然后在你的web api控制器中你可以反序列化它

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

3)你的ApiReceivedListOfObjects类应该如下所示

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

    }

4)确保你的序列化字符串(这里的IndexInfo)变得像下面的结构在JsonConvert。步骤2中的反序列化对象命令

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