La POST del formulario de ASP.NET Core da como resultado una respuesta de tipo de medio HTTP 415 no compatible

173

El envío de un formulario POST solicitud HTTP ( Content-Type: application/x-www-form-urlencoded) al controlador a continuación da como resultado una respuesta de tipo de medio HTTP 415 no compatible .

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

Encabezados HTTP de publicación de formulario:

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

Esto solía funcionar con ASP.NET MVC 5 en .NET 4.6.

Bart Verkoeijen
fuente
no tiene que usar [FromForm] "Enviar (modelo MyModel)" también obtiene el modelo correctamente.
hasan

Respuestas:

298

Para formularios, use el [FromForm]atributo en lugar del [FromBody]atributo.

El siguiente controlador funciona con ASP.NET Core 1.1:

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

Nota: [FromXxx]se requiere si su controlador está anotado con [ApiController]. Para los controladores de vista normales, se puede omitir.

Bart Verkoeijen
fuente
104

Puede usar, [FromBody]pero debe configurar el Content-Typeencabezado de su solicitud application/json, es decir

Content-Type: application/json
Bjorn Bailleul
fuente
1
Es por eso que la pregunta menciona específicamente un formulario POST, con tipo de contenido application/x-www-form-urlencoded. Me gusta de a <form>en una página HTML.
Bart Verkoeijen
Esto fue útil para mí, porque estaba enviando un objeto, no un formulario. La respuesta aceptada es la más correcta para el OP, que ya estaba usando el tipo de contenido correcto para [FromForm]. Aún así, me alegro de que este también estuviera aquí. :)
Ken Lyon
1
Esto no responde a la pregunta en absoluto. La pregunta es cómo hacer que los cuerpos de formularios sean compatibles con el servidor, ¡no cómo decirles a todos sus clientes que dejen de enviarlos!
csauve
Espera, ¿eso significa que es imposible ingerir contenido del cuerpo de una solicitud diferente a application/json, como application/text? @BartVerkoeijen alguna idea?
SpiritBob
10

Primero debe especificar en los encabezados Content-Type, por ejemplo, puede ser application/json.

Si configura el application/jsontipo de contenido, debe enviar un json.

Entonces, en el caso bodyde su solicitud, no enviará form-data, x-www-for-urlencodedsino un rawjson, por ejemplo{"Username": "user", "Password": "pass"}

Puede adaptar el ejemplo a varios tipos de contenido, incluido lo que desea enviar.

Puedes usar una herramienta como Postman o curl para jugar con esto.

Gabriel P.
fuente
6

Además de buenas respuestas, no tiene que usar [FromForm]para obtener datos de formulario en el controlador. Framework convierte automáticamente los datos del formulario al modelo que desee. Puede implementar como sigue.

[HttpPost]
public async Task<IActionResult> Submit(MyModel model)
{
    //...
}
Hasan
fuente
3
No es lo que veo.
François
Lo probé y estaba funcionando. Puede haber otro problema con su código
Hasan
Esto resolvió mi problema. Estaba desconcertando un objeto FormData con campos y archivos, [FromForm] o [FromBody] no funcionaba. Los eliminó y funcionó. (Asp.Net MVC Core 2.1 atrás, vanilla js frente). Gist aquí .
Daniel Szabo
Es curioso, unos meses después de mi comentario anterior: hoy tuve el mismo problema en el proyecto AspNetCore 2.2 Web Api y tuve que usar [FromFrom] para que funcionara en un controlador WebAPI (ver la respuesta de @ Bart).
Daniel Szabo
1
Para mí, tenía un [FromQuery]parámetro, pero no estaba especificando el Tipo de contenido como application/json; al agregarlo en mi solicitud, esto también funcionó con el parámetro [FromQuery].
Mike Upjohn
5

Este es mi caso: se ejecuta Entorno: Controlador AspNet Core 2.1:

public class MyController
{
    // ...

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

Ver:

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

el problema puede deberse a MVC MW. debe configurar formatterType en las opciones de 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
fuente
Donde options.UseCustomStringModelBinder () está disponible? No encontré documentación en ningún lugar.
Fabricio Araujo
0

La "respuesta de tipo de medio HTTP 415 no compatible" se deriva de Content-Type en el encabezado de su solicitud. por ejemplo en 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
fuente