Como passar dados POST json para o método API da Web como um object?

O aplicativo de API da Web da ASP.NET MVC4 define o método post para salvar o cliente. O cliente é passado no formato json no corpo da solicitação POST. O parâmetro do cliente no método post contém valores nulos para propriedades.

Como corrigir isso para que os dados postados passem como object do cliente?

Se possível Content-Type: application / x-www-form-urlencoded deve ser usado desde que eu não sei como alterá-lo no método javascript que postar formulário.

Controlador:

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

Pedido:

 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

O mesmo código / abordagem funcionará também para o Asp.Net Core 2.0 . A principal diferença é que, no núcleo asp.net, os controladores web api e os controladores Mvc são mesclados no modelo de controlador único. Então, seu tipo de retorno pode ser IActionResult ou uma de suas implementações (Ex: OkObjectResult )


Usar

 contentType:"application/json" 

Você precisa usar o método JSON.stringify para convertê-lo em string JSON ao enviá-lo,

E o fichário do modelo ligará os dados do json ao seu object de class.

O código abaixo funcionará bem (testado)

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

Resultado

insira a descrição da imagem aqui

contentType propriedade contentType informa ao servidor que estamos enviando os dados no formato JSON. Como enviamos uma estrutura de dados JSON, a vinculação de modelo ocorrerá corretamente.

Se você inspecionar os headers da solicitação do ajax, poderá ver que o valor Content-Type está definido como application/json .

Se você não especificar contentType explicitamente, ele usará o tipo de conteúdo padrão que é application/x-www-form-urlencoded;


Editar em novembro de 2015 para abordar outras possíveis questões levantadas nos comentários

Postar um object complexo

Digamos que você tenha uma class de modelo de visualização complexa como seu parâmetro de método de ação da web api como este

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

e o ponto final da sua API da web é como

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

No momento desta publicação, a ASP.NET MVC 6 é a versão estável mais recente e, no MVC6, os controladores api da Web e os controladores MVC são herdados da class base Microsoft.AspNet.Mvc.Controller .

Para enviar dados para o método do lado do cliente, o código abaixo deve funcionar bem

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

A binding de modelo funciona para algumas propriedades, mas não todas! Por quê ?

Se você não decorar o parâmetro do método web api com o atributo [FromBody]

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

E envie o modelo (object javascript bruto, não no formato JSON) sem especificar o valor da propriedade contentType

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

A binding de modelo funcionará para as propriedades simples no modelo, não para as propriedades em que o tipo é complexo / outro tipo. No nosso caso, as propriedades Id e Name serão ligadas corretamente ao parâmetro m , mas a propriedade Tags será uma lista vazia.

O mesmo problema ocorrerá se você estiver usando a versão curta, $.post que usará o Content-Type padrão ao enviar a solicitação.

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

Trabalhar com o POST no webapi pode ser complicado! Gostaria de adicionar à resposta já correta ..

Focará especificamente no POST, pois lidar com o GET é trivial. Não acho que muitos procurariam resolver um problema com o GET com o webapis. De qualquer maneira..

Se a sua pergunta é – No MVC Web Api, como – Usar nomes de methods de ação personalizados além dos verbos HTTP genéricos? – Realizar vários posts? – Postar vários tipos simples? – Postar tipos complexos via jQuery?

Então as seguintes soluções podem ajudar:

Primeiro, para usar os methods de ação personalizados na API da Web, adicione uma rota da API da web como:

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

E então você pode criar methods de ação como:

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

Agora, dispare o seguinte jQuery a partir do console do seu navegador

 $.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) } }); 

Segundo, para executar vários posts , é simples, crie vários methods de ação e decore com o atributo [HttpPost]. Use o [ActionName (“MyAction”)] para atribuir nomes personalizados, etc. Virá para jQuery no quarto ponto abaixo

Em terceiro lugar, em primeiro lugar, postar vários tipos SIMPLE em uma única ação não é possível. Além disso, há um formato especial para postar até mesmo um único tipo simples (além de passar o parâmetro na string de consulta ou no estilo REST). Esse foi o ponto que me fez bater a cabeça com os Rest Clients (como o Fiddler e a extensão de cliente REST Advanced do Chrome) e caçar na Web por quase 5 horas quando, eventualmente, o URL a seguir provou ser de ajuda. Vai citar o conteúdo relevante para o link pode virar morto!

 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: Notou a syntax peculiar ?

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

De qualquer forma, vamos superar essa história. Se movendo:

Quarto, postar tipos complexos via jQuery, é claro, $ .ajax () virá imediatamente na function:

Digamos que o método de ação aceite um object Person que tenha um id e um nome. Então, do 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) } }); 

E a ação será semelhante a:

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

Todos os itens acima, trabalhou para mim !! Felicidades!

Acabei de brincar com isso e descobri um resultado bastante estranho. Digamos que você tenha propriedades públicas em sua class em C # assim:

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

então você deve fazer o truque JSON.stringify como sugerido por Shyju e chamá-lo assim:

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

No entanto, se você definir getters e setters em sua class da seguinte forma:

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

então você pode chamar muito mais simplesmente:

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

Isso usa o header HTTP:

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

Não tenho certeza do que está acontecendo aqui, mas parece um bug (característica?) No framework. Presumivelmente, os diferentes methods de binding estão chamando diferentes “adaptadores” e, enquanto o adaptador para application / json se trabalha com propriedades públicas, aquele para dados codificados por formulário não funciona.

Eu não tenho ideia de qual seria a melhor prática.

Use o JSON.stringify () para obter a string no formato JSON, assegure-se de que, ao fazer a chamada AJAX, você passe os atributos abaixo mencionados:

  • contentType: ‘aplicativo / json’
  • dataType: ‘json’

Abaixo está o código dar jquery para fazer ajax post call para 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); } }); 

Certifique-se de que seu serviço WebAPI esteja esperando um object fortemente tipado com uma estrutura que corresponda ao JSON que você está passando. E certifique-se de restringir o JSON que você está enviando.

Aqui está o meu JavaScript (usando o 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 () { }); 

E aqui está o meu controlador WebAPI:

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

Seguindo o código para retornar dados no formato json, em vez do xml -Web API 2: –

Coloque a seguinte linha no arquivo 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"; }   

ProductDetails

ProductDetails
@Html.LabelFor(model => model.ProductName)
@Html.ValidationMessageFor(model => model.ProductName)
@Html.LabelFor(model => model.ProductDetail)
@Html.ValidationMessageFor(model => model.ProductDetail)
@Html.LabelFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price)

@Html.ActionLink("Back to List", "Index")
@section Scripts { @Scripts.Render("~/bundles/jqueryval") }

A Microsoft deu um bom exemplo de fazer isso:

http://www.google.com/adwords

Primeiro valide o pedido

 if (ModelState.IsValid) 

e que use os dados serializados.

 Content = new StringContent(update.Status) 

Aqui ‘Status’ é um campo no tipo complexo. A serialização é feita pelo .NET, não precisa se preocupar com isso.

1) No seu lado do cliente, você pode enviar a solicitação http.post em string como abaixo

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

2) Em seguida, no seu controlador de API da web, você pode desserializá-lo

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

3) Sua class ApiReceivedListOfObjects deve ser como abaixo

 public class ApiReceivedListOfObjects { public List element { get; set; } } 

4) certifique-se de que sua seqüência serializada (IndexInfo aqui) se torne como estrutura abaixo antes do comando JsonConvert.DeserializeObject na etapa 2

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