ASP.NET MVC4 Web API-applikasjonen definerer post-metoden for å lagre kunden. Kunden sendes i json-format i POST-forespørselen. Kundeparameteren i post-metoden inneholder nullverdier for egenskaper.
Hvordan løser jeg dette slik at postdata sendes som kundeobjekt?
Hvis mulig bør Content-Type: application/x-www-form-urlencoded brukes siden jeg ikke vet hvordan jeg skal endre det i javascript-metoden som legger inn skjema.
Controller:
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; }
}
Forespørsel:
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
Den samme koden/tilnærmingen vil også fungere for Asp.Net Core 2.0. Den største forskjellen er at i asp.net core er både web api-kontrollere og Mvc-kontrollere slått sammen til en enkelt kontrollermodell. Så returtypen din kan være IActionResult
eller en av dens implementeringer (f.eks. OkObjectResult
).
Bruk
contentType:"application/json"
Du må bruke metoden JSON.stringify
for å konvertere den til JSON-streng når du sender den,
Og modellbindemiddelet vil binde json-dataene til klasseobjektet ditt.
Koden nedenfor vil fungere fint (testet)
$(function () {
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
});
Resultat
egenskapen contentType
forteller serveren at vi sender dataene i JSON-format. Siden vi har sendt en JSON-datastruktur, vil modellbindingen skje på riktig måte.
Hvis du inspiserer topptekstene i ajax-forespørselen, kan du se at verdien Content-Type
er satt til application/json
.
Hvis du ikke spesifiserer contentType eksplisitt, vil den bruke standard innholdstype som er application/x-www-form-urlencoded
.
*Redigert i november 2015 for å løse andre mulige problemer som er tatt opp i kommentarene.
La oss si at du har en kompleks visningsmodellklasse som parameter for en web-api action-metode, som dette
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;}
}
og sluttpunktet for web-api er som følger
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;
}
}
*I skrivende stund er ASP.NET MVC 6 den siste stabile versjonen, og i MVC6 arver både Web api-kontrollere og MVC-kontrollere fra basisklassen Microsoft.AspNet.Mvc.Controller
.
Hvis du vil sende data til metoden fra klientsiden, bør koden nedenfor fungere fint.
//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 :)
});
Hvis du ikke dekorerer web api-metodeparameteren med attributtet [FromBody]
.
[HttpPost]
public CreateUserViewModel Save(CreateUserViewModel m)
{
return m;
}
og sender modellen (rå javascript-objekt, ikke i JSON-format) uten å spesifisere contentType-egenskapsverdien
$.ajax({
type: "POST",
data: model,
url: "../product/save"
}).done(function (res) {
console.log('res', res);
});
Modellbinding vil fungere for de flate egenskapene i modellen, ikke egenskapene der typen er kompleks/annen type. I vårt tilfelle vil egenskapene Id
og Name
være riktig bundet til parameteren m
, men egenskapen Tags
vil være en tom liste.
Det samme problemet vil oppstå hvis du bruker kortversjonen, $.post
, som vil bruke standard Content-Type når du sender forespørselen.
$.post("../product/save", model, function (res) {
//res contains the markup returned by the partial view
console.log('res', res);
});
Å jobbe med POST i webapi kan være vanskelig! Vil gjerne legge til det allerede riktige svaret...
Vil fokusere spesielt på POST da det er trivielt å håndtere GET. Jeg tror ikke mange vil søke rundt for å løse et problem med GET med webapis. Uansett...
Hvis spørsmålet ditt er - I MVC Web Api, hvordan - - Bruk andre egendefinerte handlingsmetodenavn enn de generiske HTTP-verbene? - Utføre flere innlegg? - Legge ut flere enkle typer? - Publisere komplekse typer via jQuery?
Da kan følgende løsninger være til hjelp:
For det første, for å bruke Custom Action Methods i Web API, legger du til en web api-rute som:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}");
}
Deretter kan du opprette handlingsmetoder som f.eks:
[HttpPost]
public string TestMethod([FromBody]string value)
{
return "Hello from http post web api controller: " + value;
}
Utløs nå følgende jQuery fra konsollen i nettleseren din
$.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) }
});
For det andre, for å utføre flere innlegg, er det enkelt å opprette flere handlingsmetoder og dekorere med [HttpPost]-attributtet. Bruk [ActionName("MyAction")] for å tildele egendefinerte navn osv. Vi kommer til jQuery i det fjerde punktet nedenfor.
For det tredje er det for det første ikke mulig å legge ut flere SIMPLE typer i én enkelt handling. Dessuten er det et spesielt format for å legge ut selv en enkel enkel type (bortsett fra å sende parameteren i spørringsstrengen eller REST-stilen). Dette var poenget som fikk meg til å slå meg i hodet med Rest Clients (som Fiddler og Chrome' s Advanced REST-klientutvidelse) og jakte rundt på nettet i nesten 5 timer da følgende URL til slutt viste seg å være til hjelp. Vil sitere det relevante innholdet for lenken kan bli død!
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: La du merke til den særegne syntaksen?
http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api
Uansett, la oss komme over den historien. Vi går videre:
For det fjerde, posting av komplekse typer via jQuery, selvfølgelig, $.ajax() kommer raskt inn i rollen:
La oss si at handlingsmetoden godtar et Person-objekt som har en id og et navn. Så, fra 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) }
});
Og handlingen vil se slik ut:
[HttpPost]
public string TestMethod(Person person)
{
return "Hello from http post web api controller: " + person.Name;
}
Alle de ovennevnte fungerte for meg!!! Skål!
Jeg har nettopp lekt med dette og oppdaget et ganske merkelig resultat. La oss si at du har slike offentlige egenskaper på klassen din i C#:
public class Customer
{
public string contact_name;
public string company_name;
}
så må du gjøre JSON.stringify-trikset som foreslått av Shyju og kalle det slik:
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
Men hvis du definerer gettere og settere på klassen din slik:
public class Customer
{
public string contact_name { get; set; }
public string company_name { get; set; }
}
kan du kalle den mye enklere:
$.ajax({
type: "POST",
data :customer,
url: "api/Customer"
});
Dette bruker HTTP-headeren:
Content-Type:application/x-www-form-urlencoded
Jeg er ikke helt sikker på hva som skjer her, men det ser ut som en feil (funksjon?) i rammeverket. Antagelig kaller de forskjellige bindingsmetodene forskjellige "adaptere", og mens adapteren for application/json fungerer med offentlige egenskaper, gjør ikke den for skjemakodede data det.
Jeg har imidlertid ingen anelse om hva som anses som beste praksis.