Comment transmettre les données POST json à la méthode API Web comme objet

L'application ASP.NET MVC4 Web API définit la méthode de publication pour enregistrer le client. Le client est transmis au format json dans un organisme de demande POST. Le paramètre client dans la méthode post contient des valeurs nulles pour les propriétés.

Comment réparer ceci afin que les données publiées passent comme objet client?

Si possible Type de contenu: application / x-www-form-urlencoded devrait être utilisé car je ne sais pas comment le modifier dans la méthode javascript qui publie le formulaire.

Manette:

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

Demande:

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

Utilisation

 contentType:"application/json" 

Vous devez utiliser la méthode JSON.stringify pour la convertir au format JSON lorsque vous l'envoyez,

Et la liaison du modèle lie les données json à votre objet de classe.

Le code ci-dessous fonctionnera bien (testé)

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

Résultat

Entrez la description de l'image ici

contentType propriété contentType indique au serveur que nous envoyons les données au format JSON. Comme nous avons envoyé une structure de données JSON, la liaison du modèle se produira correctement.

Si vous inspectez les en-têtes de la requête ajax, vous pouvez voir que la valeur Content-Type est définie comme application/json .

Si vous ne spécifiez pas spécifiquement le type de contenu, il utilisera le type de contenu par défaut qui est application/x-www-form-urlencoded;


Modifier en novembre 2015 pour aborder d'autres problèmes possibles soulevés dans les commentaires

Affichage d'un objet complexe

Disons que vous avez une classe de modèle de vue complexe comme votre paramètre de méthode d'action web api comme celui-ci

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

Et votre point final d'api web est comme

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

Au moment de la rédaction de ce document, ASP.NET MVC 6 est la dernière version stable et MVC6. Les deux contrôleurs Web api et les contrôleurs MVC héritent de la classe de base Microsoft.AspNet.Mvc.Controller .

Pour envoyer des données à la méthode du côté client, le code ci-dessous devrait fonctionner correctement

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

Le modèle de liaison fonctionne pour certaines propriétés, mais pas pour tous! Pourquoi ?

Si vous ne décorez pas le paramètre de méthode web api avec l'attribut [FromBody]

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

Et envoyez le modèle (objet javascript brut, pas au format JSON) sans spécifier la valeur de la propriété contentType

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

La liaison au modèle fonctionnera pour les propriétés plates du modèle, et non sur les propriétés où le type est complexe / un autre type. Dans notre cas, les propriétés Id et Name seront correctement liées au paramètre m , mais la propriété Tags sera une liste vide.

Le même problème se produira si vous utilisez la version courte, $.post qui utilisera le Type de contenu par défaut lors de l'envoi de la requête.

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

Travailler avec POST en webapi peut être délicat! Je voudrais ajouter à la réponse déjà correcte …

Se concentrera spécifiquement sur POST car traiter avec GET est trivial. Je ne pense pas que beaucoup rechercheraient pour résoudre un problème avec GET avec webapis. Quoi qu'il en soit …

Si votre question est – Dans MVC Web Api, comment … – Utiliser des noms de méthodes d'actions personnalisées autres que les verbes HTTP génériques? – Effectuer plusieurs publications? – Publiez plusieurs types simples? – Publiez des types complexes via jQuery?

Ensuite, les solutions suivantes peuvent aider:

Tout d'abord, pour utiliser des méthodes d'action personnalisées dans l'API Web, ajoutez une route Web api comme suit:

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

Et vous pouvez créer des méthodes d'action comme:

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

Maintenant, lancez le jQuery suivant à partir de votre console de navigation

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

Deuxièmement, pour effectuer plusieurs publications , il est simple, créez plusieurs méthodes d'action et décorez avec [HttpPost] attrib. Utilisez [ActionName ("MyAction")] pour attribuer des noms personnalisés, etc. Venez à jQuery dans le quatrième point ci-dessous

Troisièmement, Tout d'abord, l'affichage de plusieurs types SIMPLES dans une seule action n'est pas possible. En outre, il existe un format spécial pour poster même un seul type simple (en plus de passer le paramètre dans la chaîne de requête ou le style REST). C'est ce qui m'a fait frapper la tête avec Rest Clients (comme Fiddler et l'extension de client REST Advanced REST) ​​et la chasse sur le Web pendant près de 5 heures lorsque, éventuellement, l'URL suivante s'est révélée utile. Citer le contenu pertinent pour le lien pourrait devenir mort!

 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: remarqué la syntaxe particulière ?

http://forums.asp.net/t/1883467.aspx?La+valorit&#xE9; reçue+ est+null+when+I+try+to+Post+to+my+Web+Api

Quoi qu'il en soit, laissez-nous comprendre cette histoire. En cours:

Quatrièmement, publier des types complexes via jQuery, bien sûr, $ .ajax () entrera rapidement dans le rôle:

Disons que la méthode d'action accepte un objet Personne qui a un identifiant et un nom. Ainsi, à partir de 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) } }); 

Et l'action ressemblera à:

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

Tout ce qui précède a fonctionné pour moi !! À votre santé!

Je viens de jouer avec ça et j'ai découvert un résultat plutôt étrange. Dites que vous avez des propriétés publiques sur votre classe dans C # comme ceci:

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

Alors vous devez faire l'astuce JSON.stringify comme suggéré par Shyju et appelez-le comme ceci:

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

Cependant, si vous définissez les getters et les setters sur votre classe comme ceci:

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

Alors vous pouvez l'appeler beaucoup plus simplement:

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

Cela utilise l'en-tête HTTP:

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

Je ne suis pas tout à fait sûr de ce qui se passe ici, mais il ressemble à un bug (fonctionnalité?) Dans le cadre. On peut supposer que les différentes méthodes de liaison appellent différentes "adaptateurs", et tandis que l'adaptateur pour application / json on travaille avec des propriétés publiques, celui pour les données codées par formulaire ne le fait pas.

Je n'ai aucune idée de ce qui serait considéré comme la meilleure pratique.

Utilisez le JSON.stringify () pour obtenir la chaîne au format JSON, assurez-vous que tout en effectuant l'appel AJAX vous passe ci-dessous les attributs mentionnés:

  • ContentType: 'application / json'
  • DataType: 'json'

Voici le code give jquery pour faire un appel ajax à 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); } }); 

Assurez-vous que votre service WebAPI attend un objet fortement typé avec une structure qui correspond à la JSON que vous passez. Et assurez-vous que vous identifiez le JSON que vous POSER.

Voici mon JavaScript (utilisant 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 () { }); 

Et voici mon contrôleur WebAPI:

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

Code suivant pour renvoyer les données au format json, au lieu de xml -Web API 2: –

Mettre la ligne suivante dans le fichier 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"; } <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 a donné un bon exemple de ceci:

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

Valider d'abord la demande

 if (ModelState.IsValid) 

Et utiliser les données sérialisées.

 Content = new StringContent(update.Status) 

Ici 'Status' est un champ du type complexe. La sérialisation est effectuée par .NET, pas besoin de s'inquiéter à ce sujet.