J'aimerais publier des données sur mon API à l'aide de AJAX, mais j'ai des problèmes. J'utilise Fiddler pour tester mon API et je peux publier correctement le code JSON, mais lors de la publication d'une chaîne de nom/valeur avec un code urlencodé, je reçois une requête 400 Bad dont le corps de la réponse est '{"": ["L'entrée n'était pas valide . "]} '.
Ma fenêtre de débogage affiche: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor:Information: Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.SerializableError'.
Le JSON affiché est:
{
"Name": "Test"
}
Les données de formulaire en cours d’enregistrement sont:
Name=Test
C'est le contrôleur et l'action:
[Route("api/[Controller]")]
[ApiController]
public class AccountsController : Controller
{
[HttpPost]
public IActionResult CreateAccount(Account account)
{
//code
}
}
Ceci est la classe Account:
public class Account
{
public string Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Website { get; set; }
}
Il semble évident qu'il y a un problème lors de la liaison du modèle, mais les données de formulaire semblent valides (j'ai également généré des données de formulaire à l'aide de AJAX et j'ai également un nombre 400).
Dans son article Modèle liant les POSTS JSON dans ASP.NET Core de 2016, Andrew Lock explique que pour lier un JSON POST dans ASP.NET Core, l'attribut [FromBody]
doit être spécifié sur l'argument, ainsi:
[HttpPost]
public IActionResult CreateAccount([FromBody] Account account)
{
// ...
}
Avec l'introduction de [ApiController]
dans ASP.NET Core 2.1, cela n'est plus nécessaire. Il est important ici que cet attribut déduise effectivement la présence de l'attribut [FromBody]
lorsque le type lié est «complexe» (ce qui est le cas dans votre exemple). En d'autres termes, c'est comme si vous aviez écrit le code comme je l'ai montré ci-dessus.
Dans son message, Andrew a également déclaré ce qui suit:
Dans certains cas, vous aurez peut-être besoin de pouvoir lier les deux types de données à une action. Dans ce cas, vous êtes un peu coincé, car il ne sera pas possible qu'un même point final reçoive deux ensembles de données différents.
Ici, en faisant référence à les deux types de données, Andrew fait référence à la fois à une publication JSON et à une publication POST basée sur un formulaire. Il continue en expliquant comment atteindre le résultat souhaité. En modifiant son exemple pour vos besoins, vous devez procéder comme suit:
// Form.
[HttpPost("FromForm")]
public IActionResult CreateAccountFromForm([FromForm] Account account)) =>
DoSomething(account);
// JSON.
[HttpPost("FromBody")]
public IActionResult CreateAccountFromBody(Account account) =>
DoSomething(account);
private IActionResult DoSomething(Account account) {
// ...
}
Dans l'exemple d'Andrew, le [FromBody]
est explicite et le [FromForm]
est implicite, mais compte tenu de l'effet que [ApiController]
a sur les valeurs par défaut, l'exemple modifié ci-dessus renverse le problème.
Assurez-vous que votre type de demande est défini sur "application/json". J'ai reproduit votre code, et la méthode n'était pas appelée à l'aide de Postman jusqu'à ce que je définisse le type de requête sur application/json.
Edit: Lorsque j’ajoutais le texte suivant aux en-têtes de fiddler, j’ai pu que fiddler appelle également ma méthode:
Type de contenu: application/json
Si vous voulez obtenir des données de formulaire pour le headr Content-Type: application/x-www-form-urlencoded) sur votre contrôleur api, vous devez alors mettre l'attribut [FromForm] dans la méthode d'action comme
// POST: api/Create
[HttpPost]
public IActionResult CreateAccount([FromForm] Account account)
{
}
Si vous souhaitez obtenir des données de formulaire pour l'en-tête Content-Type: application/json sur votre contrôleur d'api, vous devez insérer [FromBody]/No attribut dans la méthode d'action, comme
// POST: api/Create
[HttpPost]
public IActionResult CreateAccount([FromBody] Account account)
{
}
Ou
// POST: api/Create
[HttpPost]
public IActionResult CreateAccount(Account account)
{
}