O POST do formulário ASP.NET Core resulta em uma resposta HTTP 415 Tipo de Mídia Não Suportado

173

Enviar um formulário POST HTTP request ( Content-Type: application/x-www-form-urlencoded) para o controlador abaixo resulta em uma resposta HTTP 415 Tipo de mídia não suportado .

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

Cabeçalhos HTTP de postagem de formulário:

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

Isso costumava funcionar com o ASP.NET MVC 5 no .NET 4.6.

Bart Verkoeijen
fonte
você não precisa usar [FromForm] "Submit (modelo MyModel)" e também obter o modelo corretamente.
Hasan

Respostas:

298

Para formulários, use o [FromForm]atributo em vez do [FromBody]atributo.

O controlador abaixo funciona com o ASP.NET Core 1.1:

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

Nota: [FromXxx]é necessário se o seu controlador estiver anotado [ApiController]. Para controladores de exibição normal, isso pode ser omitido.

Bart Verkoeijen
fonte
104

Você pode usar, [FromBody]mas precisa definir o Content-Typecabeçalho da sua solicitação como application/json, por exemplo ,

Content-Type: application/json
Bjorn Bailleul
fonte
1
É por isso que a pergunta menciona especificamente um formulário POST, com tipo de conteúdo application/x-www-form-urlencoded. Como <form>em uma página HTML.
Bart Verkoeijen
Isso foi útil para mim, porque eu estava enviando um objeto, não um formulário. A resposta aceita é a mais correta para o OP, que já estava usando o tipo de conteúdo correto para [FromForm]. Ainda assim, estou feliz que este também esteve aqui. :)
Ken Lyon
1
Isso não responde à pergunta. A questão é como criar corpos de formulário de suporte ao servidor, não como simplesmente dizer a todos os seus clientes para parar de enviá-los!
Csauve
Espere, isso significa que é impossível receber conteúdo do corpo de uma solicitação diferente de application/json, como application/text? @BartVerkoeijen alguma idéia?
SpiritBob
10

Primeiro você precisa especificar nos cabeçalhos Content-Type, por exemplo, pode ser application/json.

Se você definir o application/jsontipo de conteúdo, precisará enviar um json.

Portanto, no bodyseu pedido, você não enviará form-data, x-www-for-urlencodedmas não um rawjson, por exemplo{"Username": "user", "Password": "pass"}

Você pode adaptar o exemplo a vários tipos de conteúdo, incluindo o que deseja enviar.

Você pode usar uma ferramenta como Postman ou curl para brincar com isso.

Gabriel P.
fonte
6

Como adição de boas respostas, você não precisa usar [FromForm]para obter dados do formulário no controlador. O Framework converte automaticamente os dados do formulário em modelo como desejar. Você pode implementar como a seguir.

[HttpPost]
public async Task<IActionResult> Submit(MyModel model)
{
    //...
}
hasan
fonte
3
Não é o que eu vejo.
François
Eu testei-o e ele estava funcionando, pode haver outro problema com o seu código
Hasan
Isso resolveu meu problema. Eu estava enviando um objeto FormData ajax com campos e arquivos, [FromForm] ou [FromBody] não funcionou. Removido e funcionou. (Asp.Net MVC Core 2.1 de volta, vanilla js front). Gist Here .
Daniel Szabo
Engraçado, alguns meses depois do meu comentário anterior - hoje eu tive o mesmo problema no projeto AspNetCore 2.2 Web Api e tive que usar o [FromFrom] para fazê-lo funcionar em um controlador WebAPI (consulte a resposta de @ Bart).
Daniel Szabo
1
Para mim, eu tinha um [FromQuery]parâmetro, mas não estava especificando o Tipo de Conteúdo como application/json- acrescentando que na minha solicitação, também fiz esse trabalho com o parâmetro [FromQuery].
21819 Mike Upjohn
5

Este é o meu caso: ele é executado. Ambiente: AspNet Core 2.1 Controller:

public class MyController
{
    // ...

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

Visão:

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

o problema pode ocorrer devido ao MVC MW. você deve definir formatterType nas opções do 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
fonte
Onde options.UseCustomStringModelBinder () está disponível ?? Não encontrei a documentação em nenhum lugar.
Fabricio Araujo
0

"Resposta do tipo de mídia HTTP 415 não suportada" decorre do Tipo de conteúdo no cabeçalho da sua solicitação. por exemplo em javascript por 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
fonte