Как передать данные json POST в метод Web API как объект?
Приложение ASP.NET MVC4 Web API определяет метод post для сохранения клиента.
Клиент передается в формате json в теле запроса POST.
Параметр Customer в методе post содержит значения null для свойств.
Как исправить это, чтобы отправленные данные передавались как объект клиента?
Если возможно, 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"}
Ответы
Ответ 1
РЕДАКТИРОВАТЬ: 31/10/2017
Тот же код/подход будет работать и для Asp.Net Core 2.0. Основное отличие состоит в том, что в ядре asp.net контроллеры веб-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"
});
});
Результат
![enter image description here]()
Свойство contentType
сообщает серверу, что мы отправляем данные в формате JSON. Поскольку мы отправили структуру данных JSON, привязка модели произойдет правильно.
Если вы проверяете заголовки запроса ajax, вы можете видеть, что значение Content-Type
установлено как application/json
.
Если вы не укажете явно тип содержимого, он будет использовать тип содержимого по умолчанию application/x-www-form-urlencoded;
Внесите изменения в ноябрь 2015 года, чтобы устранить другие возможные проблемы, поднятые в комментариях
Размещение сложного объекта
Допустим, у вас есть класс модели сложного представления в качестве параметра метода действия веб-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;}
}
и ваша конечная точка веб-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 :)
});
Привязка модели работает для некоторых свойств, но не для всех! Почему?
Если вы не украсили параметр метода web api атрибутом [FromBody]
[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
, которая будет использовать тип содержимого по умолчанию при отправке запроса.
$.post("../product/save", model, function (res) {
//res contains the markup returned by the partial view
console.log('res', res);
});
Ответ 2
Работа с POST в webapi может быть сложной!
Хотелось бы добавить к уже правильному ответу.
Будет фокусироваться конкретно на POST, поскольку работа с GET тривиальна. Я не думаю, что многие будут искать решения для решения проблемы с GET с помощью webapis. В любом случае..
Если у вас есть вопрос - в MVC Web Api, как - - Использовать собственные имена методов действий, отличные от общих глаголов HTTP? - Выполнять несколько сообщений? - Опубликовать несколько простых типов? - Поместить сложные типы через jQuery?
Тогда следующие решения могут помочь:
Во-первых, для использования Пользовательских методов действий в веб-API добавьте веб-маршрут 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) }
});
Во-вторых, выполнять несколько сообщений. Это просто, создать несколько методов действий и украсить атрибут [HttpPost]. Используйте [ActionName ( "MyAction" )], чтобы назначить пользовательские имена и т.д. Приходится к jQuery в четвертой точке ниже
В-третьих, во-первых, размещение нескольких типов SIMPLE в одном действии невозможно.
Кроме того, существует специальный формат, чтобы опубликовать даже простой простой тип (кроме передачи параметра в строке запроса или стиле REST).
В этом и заключался момент, когда я ударился головой с клиентами по отдыху (например, с расширением Fiddler и Chrome Advanced 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":"[email protected]"}
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, у которого есть идентификатор и имя. Итак, из 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;
}
Все вышеперечисленное, работало для меня!! Ура!
Ответ 3
Я только что играл с этим и обнаружил довольно странный результат. Предположим, что у вас есть общедоступные свойства в вашем классе на С#, например:
public class Customer
{
public string contact_name;
public string company_name;
}
то вы должны сделать трюк JSON.stringify, предложенный Shyju, и называть его следующим образом:
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
Однако, если вы определяете геттеры и сеттеры в своем классе следующим образом:
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
Я не совсем уверен, что происходит здесь, но это выглядит как ошибка (функция?) в рамках. Предположительно, различные методы привязки вызывают разные "адаптеры", и, хотя адаптер для приложения /json работает с общедоступными свойствами, тот, который для данных, закодированных в форме, не имеет.
Я понятия не имею, что считается лучшей практикой.
Ответ 4
Используйте JSON.stringify(), чтобы получить строку в формате JSON, убедитесь, что при вызове AJAX вы передаете ниже указанные атрибуты:
- contentType: 'application/json'
Ниже приведен код JQuery для выполнения пост-вызова Ajax на веб-интерфейсе asp.net:
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);
}
});
Ответ 5
Убедитесь, что ваша служба WebAPI ожидает строго типизированного объекта со структурой, которая соответствует передаваемой вами JSON. И убедитесь, что вы подкрепили JSON, который вы используете POSTING.
Вот мой 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";
}
Ответ 6
Следующий код для возврата данных в формате json вместо API xml -Web 2: -
Поместите следующую строку в файл Global.asax
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
Ответ 7
@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")
}
Ответ 8
Microsoft дала хороший пример:
https://docs.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, не нужно беспокоиться об этом.
Ответ 9
1) На стороне клиента вы можете отправить запрос http.post в виде строки, как показано ниже
var IndexInfo = JSON.stringify(this.scope.IndexTree);
this.$http.post('../../../api/EvaluationProcess/InsertEvaluationProcessInputType', "'" + IndexInfo + "'" ).then((response: any) => {}
2) Затем в вашем веб-контроллере 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) перед выполнением команды JsonConvert.DeserializeObject на шаге 2 убедитесь, что ваша сериализованная строка (здесь IndexInfo) становится похожей на структуру ниже
var resp = @"
{
""element"": [
{
""A"": ""A Jones"",
""B"": ""500015763""
},
{
""A"": ""B Smith"",
""B"": ""504986213""
},
{
""A"": ""C Brown"",
""B"": ""509034361""
}
]
}";