405 método no permitido API web

88

Este error es muy común, probé todas las soluciones y ninguna funcionó. He desactivado la publicación de WebDAV en el panel de control y agregué esto a mi archivo de configuración web:

  <handlers>
  <remove name="WebDAV"/>
  </handlers>
  <modules runAllManagedModulesForAllRequests="true">
  <remove name="WebDAVModule"/>
  </modules>

El error aún persiste. Este es el controlador:

   static readonly IProductRepository repository = new ProductRepository();

    public Product Put(Product p)
    {
        return repository.Add(p);
    }

Implementación del método:

 public Product Add(Product item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }
        item.Id = _nextId++;
        products.Add(item);
        return item;
    }

Y aquí es donde se lanza la excepción:

client.BaseAddress = new Uri("http://localhost:5106/");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));      
var response = await client.PostAsJsonAsync("api/products", product);//405 exception

¿Alguna sugerencia?

Xardas
fuente

Respuestas:

61

Estás publicando desde el cliente:

await client.PostAsJsonAsync("api/products", product);

no PONER.

Su método de API web solo acepta solicitudes PUT.

Entonces:

await client.PutAsJsonAsync("api/products", product);
Darin Dimitrov
fuente
El error 'HttpClient' no contiene una definición para 'PostAsJsonAsync' cuando se prueba su código.
agileDev
61

Tuve la misma excepción. Mi problema era que había usado:

using System.Web.Mvc; // Wrong namespace for HttpGet attribute !!!!!!!!!
[HttpGet]
public string Blah()
{
    return "blah";
}

DEBIERA SER

using System.Web.Http; // Correct namespace for HttpGet attribute !!!!!!!!!
[HttpGet]
public string Blah()
{
    return "blah";
}
Llad
fuente
18

Intenté muchas cosas para que el método DELETE funcionara (obtenía el método 405 no permitido web api), y finalmente agregué [Route ("api / scan / {id}")] a mi controlador y funcionó bien. Espero que esta publicación ayude a alguien.

     // DELETE api/Scan/5
    [Route("api/scan/{id}")]
    [ResponseType(typeof(Scan))]
    public IHttpActionResult DeleteScan(int id)
    {
        Scan scan = db.Scans.Find(id);
        if (scan == null)
        {
            return NotFound();
        }

        db.Scans.Remove(scan);
        db.SaveChanges();

        return Ok(scan);
    }
usuario2662006
fuente
Por alguna razón, mi solo no estaba funcionando para la eliminación, para crear y actualizar funcionó bien. Bueno, acabo de agregar [HttpPost] y funcionó. Pero gracias, me
pusiste
1
¿Por qué no agrega simplemente el atributo [HttpDelete]?
Johnny 5 de
14

Mi problema resultó ser el enrutamiento de atributos en WebAPI. Creé una ruta personalizada y la trató como un GET en lugar de WebAPI descubriendo que era un POST

    [Route("")]
    [HttpPost] //I added this attribute explicitly, and it worked
    public void Post(ProductModel data)
    {
        ...
    }

Sabía que tenía que ser algo tonto (que consume todo tu día)

Nexxas
fuente
¡Esto me salvó el día!
Phate01
6

Chrome muchas veces intenta hacer una OPTIONSllamada antes de hacer una publicación. Hace esto para asegurarse de que los encabezados CORS estén en orden. Puede ser problemático si no está manejando la OPTIONSllamada en su controlador API.

public void Options() { }
Nate Zaugg
fuente
6

Este error también puede ocurrir cuando intenta conectarse a http mientras el servidor está en https.

Fue un poco confuso porque mis solicitudes de obtención estaban bien, el problema solo estaba presente con las solicitudes posteriores.

FrankyHollywood
fuente
4

Estaba obteniendo el 405 en mi llamada GET y el problema resultó que nombré el parámetro en el método del lado del servidor GET Get(int formId)y necesitaba cambiar la ruta o cambiarle el nombre Get(int id).

Sako73
fuente
4

También puede obtener el error 405 si dice que su método espera un parámetro y no lo está pasando.

Esto NO funciona (error 405)

Vista HTML / Javascript

$.ajax({
         url: '/api/News',
         //.....

API web:

public HttpResponseMessage GetNews(int id)

Por lo tanto, si la firma del método es como la anterior, debe hacer:

Vista HTML / Javascript

$.ajax({
         url: '/api/News/5',
         //.....
Tom Stickel
fuente
Parece que me estoy encontrando con errores 405 por varias razones, todos se reducen al hecho de que intenta HIT en la firma del método y un problema de parámetro o un problema de nomenclatura de convención o un problema de atributo, etc.
Tom Stickel
4

Llego tarde a esta fiesta, pero como nada de lo anterior era viable o funcionaba en la mayoría de los casos, así es como esto finalmente se resolvió para mí.

En el servidor en el que estaba alojado el sitio / servicio, se requería una función. ACTIVACIÓN HTTP !!!

Administrador del servidor> Administrar> Agregar roles y características> siguiente siguiente siguiente hasta que llegue a Características> Bajo .NET (cada versión) marque Activación HTTP. También tenga en cuenta que hay uno oculto en> net> WCF Services.

¡Esto funcionó al instante! Que estaba derritiendo mi cerebro

Monolithcode
fuente
4

Si tienes una ruta como

[Route("nuclearreactors/{reactorId}")]

Debe usar exactamente el mismo nombre de parámetro en el método, por ejemplo

public ReactorModel GetReactor(reactorId)
{
 ...
}

Si no pasa exactamente el mismo parámetro, puede obtener el error "405 método no permitido" porque la ruta no coincidirá con la solicitud y WebApi activará un método de controlador diferente con un método HTTP permitido diferente.

Roylac
fuente
¡Esta tampoco es una respuesta!
Divyang Desai
@Div "405 método no permitido" se puede mostrar en el caso que compartí porque el método no detectará la llamada de API ya que la configuración de la ruta no es válida. La llamada api puede llegar a otro método no deseado que podría tener una acción HTTP diferente permitida. Sí, estoy de acuerdo en que esta respuesta puede no ser 100% relevante para la pregunta real, sin embargo, el título de la pregunta de Xardas no es muy específico y creo que muchas personas que llegan aquí en busca de respuestas a la pregunta como se indica en el título pueden encuentre útil esta respuesta.
roylac
3

Esto no responde a su pregunta específica, pero cuando tuve el mismo problema terminé aquí y pensé que más personas podrían hacer lo mismo.

El problema que tuve fue que había declarado indebidamente mi método Get como estático . Me perdí esto toda una mañana y no provocó advertencias de atributos o similares.

Incorrecto:

public class EchoController : ApiController
{
    public static string Get()
    {
        return string.Empty;
    }
}

Correcto:

public class EchoController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }
}
Por Stolpe
fuente
2

¡[HttpPost] es innecesario!

[Route("")]
public void Post(ProductModel data)
{
    ...
}
user3963793
fuente
1
Sí, la forma en que lo está haciendo es correcta en el sentido de que no necesita un [HttpPost] explícito, sin embargo, hay algunas personas que no siguen la convención (yikes) y, por lo tanto, algo como [Route ("MyMethodSaver"] cadena pública MyMethodtoSave (int? id) -> eso necesitaría un [HttpPost] y luego funcionaría
Tom Stickel
2

NO pude resolver esto. Tenía CORS habilitado y funcionando siempre que el POST devolviera vacío (ASP.NET 4.0 - WEBAPI 1). Cuando intenté devolver un HttpResponseMessage, comencé a recibir la respuesta HTTP 405.

Según la respuesta de Llad anterior, eché un vistazo a mis propias referencias.

Tenía el atributo [System.Web.Mvc.HttpPost] en la lista sobre mi método POST.

Cambié esto para usar:

[System.Web.Http.HttpPostAttribute]
[HttpOptions]
public HttpResponseMessage Post(object json)        
{
    ...
    return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}

Esto solucionó mis problemas. Espero que esto ayude a alguien más.

En aras de la integridad, tenía lo siguiente en mi web.config:

<httpProtocol>
    <customHeaders>
        <clear />
        <add name="Access-Control-Expose-Headers " value="WWW-Authenticate"/>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT, PATCH, DELETE" />
        <add name="Access-Control-Allow-Headers" value="accept, authorization, Content-Type" />
        <remove name="X-Powered-By" />
    </customHeaders>
</httpProtocol>
Spencer Sullivan
fuente
Esto hará que se invoque el método en la solicitud previa al vuelo OPTIONS (así como en la POST), momento en el que jsones probable nullque las solicitudes previas al vuelo generalmente no tengan cargas útiles, o ejecutará la acción posterior dos veces.
Glennsl
1

Tuvimos un problema similar. Estábamos tratando de OBTENER de:

[RoutePrefix("api/car")]
public class CarController: ApiController{

    [HTTPGet]
    [Route("")]
    public virtual async Task<ActionResult> GetAll(){

    }

}

Entonces lo haríamos .GET("/api/car")y esto arrojaría un 405 error.


La solución:

El CarController.csarchivo estaba en el directorio, /api/carpor lo que cuando solicitábamos este punto final de la API, IIS enviaba un error porque parecía que estábamos tratando de acceder a un directorio virtual al que no teníamos permiso.

Opción 1: cambiar / renombrar el directorio en el que se encuentra el controlador.
Opción 2: cambiar el prefijo de ruta a algo que no coincida con el directorio virtual.

Zze
fuente
1

En mi caso, tenía una carpeta física en el proyecto con el mismo nombre que la ruta WebAPI (por ejemplo, sandbox) y solo la solicitud POST fue interceptada por el controlador de archivos estáticos en IIS (obviamente).

Obtener un error 405 engañoso en lugar del 404 más esperado fue la razón por la que tardé mucho en solucionar el problema.

No es fácil caer en esto, pero es posible. Espero que ayude a alguien.

Panos Roditakis
fuente
1

Por mi parte, mi controlador POST era de esta forma:

[HttpPost("{routeParam}")]
public async Task<ActionResult> PostActuality ([FromRoute] int routeParam, [FromBody] PostData data)

Descubrí que tenía que intercambiar los argumentos , es decir, los datos del cuerpo primero y luego el parámetro de ruta, como este:

[HttpPost("{routeParam}")]
public async Task<ActionResult> PostActuality ([FromBody] PostData data, [FromRoute] int routeParam)
Alexandre Daubricourt
fuente
0

revise el archivo .csproj de su proyecto y cambie

<IISUrl>http://localhost:PORT/</IISUrl>

a la URL de su sitio web como esta

<IISUrl>http://example.com:applicationName/</IISUrl>
Ankit
fuente
0

Otro posible problema que causa el mismo comportamiento son los parámetros predeterminados en el enrutamiento. En mi caso, el controlador se ubicó y se instanciaron correctamente, pero la POST se bloqueó debido a la Getacción predeterminada especificada:

config.Routes.MapHttpRoute(
    name: "GetAllRoute",
    routeTemplate: "api/{controller}.{ext}"/*,
    defaults: new { action = "Get" }*/ // this was causing the issue
);
Eadel
fuente
0

Estaba teniendo exactamente el mismo problema. Busqué durante dos horas lo que estaba mal sin suerte hasta que me di cuenta de que mi POSTmétodo era en privatelugar de public.

Es curioso ver que el mensaje de error es algo genérico. ¡Espero eso ayude!

Gonzo345
fuente
0

Asegúrese de que su controlador herede de la Controllerclase.

Incluso podría ser más loco que las cosas funcionen localmente incluso sin eso.

RAM
fuente