ASP.NET Core form POST entraîne une réponse HTTP 415 de type de support non pris en charge

173

L'envoi d'une requête POST HTTP ( Content-Type: application/x-www-form-urlencoded) de formulaire au contrôleur ci-dessous entraîne une réponse HTTP 415 Type de support non pris en charge .

public class MyController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Submit([FromBody] MyModel model)
    {
        //...
    }
}

Formulaire d'en-têtes HTTP de publication:

POST /submit HTTP/1.1
Host: example.com:1337
Connection: keep-alive
Content-Length: 219
Pragma: no-cache
Cache-Control: no-cache
Origin: https://example.com:1337
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://example.com:1337/submit
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,nl;q=0.6

Cela fonctionnait avec ASP.NET MVC 5 sur .NET 4.6.

Bart Verkoeijen
la source
vous n'avez pas besoin d'utiliser [FromForm] "Soumettre (modèle MyModel)" pour obtenir le modèle correctement.
hasan

Réponses:

298

Pour les formulaires, utilisez l' [FromForm]attribut au lieu de l' [FromBody]attribut.

Le contrôleur ci-dessous fonctionne avec ASP.NET Core 1.1:

public class MyController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Submit([FromForm] MyModel model)
    {
        //...
    }
}

Remarque: [FromXxx]est obligatoire si votre contrôleur est annoté avec [ApiController]. Pour les contrôleurs de vue normaux, il peut être omis.

Bart Verkoeijen
la source
104

Vous pouvez utiliser [FromBody]mais vous devez définir l'en- Content-Typetête de votre demande sur application/json, c'est- à -dire

Content-Type: application/json
Bjorn Bailleul
la source
1
C'est pourquoi la question mentionne spécifiquement un formulaire POST, avec content-type application/x-www-form-urlencoded. Comme à partir d'un <form>sur une page HTML.
Bart Verkoeijen
Cela m'a été utile, car je soumettais un objet, pas un formulaire. La réponse acceptée est la plus correcte pour l'OP, qui utilisait déjà le type de contenu correct pour [FromForm]. Pourtant, je suis content que celui-ci soit là aussi. :)
Ken Lyon
1
Cela ne répond pas du tout à la question. La question est de savoir comment créer des corps de formulaire de support serveur, pas comment dire à tous vos clients d'arrêter de les envoyer!
csauve
Attendez, cela signifie-t-il qu'il est impossible d'ingérer du contenu à partir d'un corps de requête différent de application/json, comme application/text? @BartVerkoeijen des idées?
SpiritBob
10

Vous devez d'abord spécifier dans les en-têtes Content-Type, par exemple, cela peut être application/json.

Si vous définissez le application/jsontype de contenu, vous devez envoyer un fichier json.

Donc dans le bodyde votre demande vous n'enverrez pas form-data, pas x-www-for-urlencodedmais un rawjson, par exemple{"Username": "user", "Password": "pass"}

Vous pouvez adapter l'exemple à différents types de contenu, y compris ce que vous souhaitez envoyer.

Vous pouvez utiliser un outil comme Postman ou curl pour jouer avec cela.

Gabriel P.
la source
6

En plus de bonnes réponses, vous n'avez pas à utiliser [FromForm]pour obtenir des données de formulaire dans le contrôleur. Framework convertit automatiquement les données de formulaire en modèle comme vous le souhaitez. Vous pouvez implémenter comme suit.

[HttpPost]
public async Task<IActionResult> Submit(MyModel model)
{
    //...
}
hasan
la source
3
Pas ce que je vois.
François
Je l'ai testé et cela fonctionnait, il peut y avoir un autre problème avec votre code
hasan
Cela a résolu mon problème. J'ajaxais un objet FormData avec des champs et des fichiers, [FromForm] ou [FromBody] ne fonctionnait pas. Je les ai supprimés et cela a fonctionné. (Asp.Net MVC Core 2.1 à l'arrière, vanilla js à l'avant). Gist ici .
Daniel Szabo
Drôle, quelques mois après mon commentaire précédent - aujourd'hui, j'ai eu le même problème dans le projet AspNetCore 2.2 Web Api, et j'ai dû utiliser [FromFrom] pour le faire fonctionner dans un contrôleur WebAPI (voir la réponse de @ Bart).
Daniel Szabo
1
Pour moi, j'avais un [FromQuery]paramètre, mais je ne spécifiais pas le Content-Type comme application/json- en ajoutant cela dans ma demande, cela fonctionnait également avec le paramètre [FromQuery].
Mike Upjohn
5

C'est mon cas: il est exécuté Environnement: AspNet Core 2.1 Controller:

public class MyController
{
    // ...

    [HttpPost]
    public ViewResult Search([FromForm]MySearchModel searchModel)
    {
        // ...
        return View("Index", viewmodel);
    }
}

Vue:

<form method="post" asp-controller="MyController" asp-action="Search">
    <input name="MySearchModelProperty" id="MySearchModelProperty" />
    <input type="submit" value="Search" />
</form>
Quang Vu
la source
2

le problème peut être dû à MVC MW.vous devez définir formatterType dans les options MVC:

services.AddMvc(options =>
            {
                options.UseCustomStringModelBinder();
                options.AllowEmptyInputInBodyModelBinding = true;
                foreach (var formatter in options.InputFormatters)
                {
                    if (formatter.GetType() == typeof(SystemTextJsonInputFormatter))
                        ((SystemTextJsonInputFormatter)formatter).SupportedMediaTypes.Add(
                            Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/plain"));
                }
            }).AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
            });
hamid_reza hobab
la source
Où options.UseCustomStringModelBinder () est disponible ?? Je n'ai trouvé de documentation à aucun endroit.
Fabricio Araujo le
0

"Réponse HTTP 415 Type de média non pris en charge" provient de Content-Type dans l'en-tête de votre requête. par exemple en javascript par axios:

Axios({
            method: 'post',
            headers: { 'Content-Type': 'application/json'},
            url: '/',
            data: data,  // an object u want to send
          }).then(function (response) {
            console.log(response);
          });
Mahdi Jalali
la source