Как передать данные JSON POST в метод Web API в качестве объекта?
ASP.NET приложение MVC4 Web API определяет метод post для сохранения клиента. Клиент передается в формате json в теле запроса POST. Параметр Customer в методе 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"}
9 ответов
редактировать : 31/10/2017
тот же код / подход будет работать для Asp.Net Core 2.0 как хорошо. Главное отличие в том, что asp.net ядро, как контроллеры 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;
Edit on Nov 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 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;
}
}
на момент написания этой статьи, 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);
});
работа с POST в webapi может быть сложной! Хотелось бы добавить к уже правильному ответу..
будет сосредоточен конкретно на сообщении, поскольку работа с 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] attrib. Использовать [ActionName ("MyAction")] для назначения пользовательских имен и т. д. Придет к jQuery в четвертом пункте ниже
в-третьих, прежде всего, размещение нескольких простой типы в одном действии невозможны. Более того, есть специальный формат опубликовать даже один простой типа (кроме передачи параметра в строке запроса или стиле REST). Это было то, что заставило меня стучать головой с клиентами Rest (например, Fiddler и Chrome Advanced REST client extension) и охота по сети в течение почти 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 () собирается оперативно прийти в роли:
предположим, что метод действия принимает объект 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;
}
все вышеперечисленное, работало на меня!! Ура!
Я только что играл с этим и обнаружил довольно странный результат. Скажем, у вас есть публичные свойства в вашем классе В C#, например:
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
Я не совсем уверен, что здесь происходит, но это похоже на ошибку (функция?) в рамках. Предположительно, различные методы привязки вызывают разные "адаптеры", и, хотя адаптер для application/json работает с общедоступными свойствами, для данных, закодированных в форме, нет.
Я понятия не имею, что будет считаться лучшей практикой.
использовать в формате JSON.преобразовать в строки() чтобы получить строку в формате JSON, убедитесь, что при выполнении вызова AJAX вы передаете ниже упомянутые атрибуты:
- contentType: 'application / json'
- тип данных:'json'
Ниже приведен код give jquery для вызова ajax post asp.net Web api:
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);
}
});
убедитесь, что служба WebAPI ожидает строго типизированный объект со структурой, соответствующей JSON, который вы передаете. И убедитесь, что вы stringify 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";
}
следующий код для возврата данных в формате 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")
}
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)
здесь "статус" - это поле сложного типа. Сериализация выполняется .NET, не нужно беспокоиться об этом.
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) Убедитесь, что ваша сериализованная строка (IndexInfo здесь) становится как ниже структуры перед JsonConvert.Команда DeserializeObject в шаге 2
var resp = @"
{
""element"": [
{
""A"": ""A Jones"",
""B"": ""500015763""
},
{
""A"": ""B Smith"",
""B"": ""504986213""
},
{
""A"": ""C Brown"",
""B"": ""509034361""
}
]
}";