Método 405 não permitido API da Web

90

Esse erro é muito comum, tentei todas as soluções e nenhuma funcionou. Desativei a publicação de WebDAV no painel de controle e adicionei isso ao meu arquivo de configuração da web:

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

O erro ainda persiste. Este é o controlador:

   static readonly IProductRepository repository = new ProductRepository();

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

Implementação do método:

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

E é aqui que a exceção é lançada:

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

Alguma sugestão?

Xardas
fonte

Respostas:

62

Você está POSTANDO do cliente:

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

não colocando.

Seu método de API da Web aceita apenas solicitações PUT.

Então:

await client.PutAsJsonAsync("api/products", product);
Darin Dimitrov
fonte
Erro 'HttpClient' não contém uma definição para 'PostAsJsonAsync' é lançado, quando você tentou seu código.
agileDev
61

Eu tive a mesma exceção. Meu problema era que eu tinha usado:

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

DEVERIA ESTAR

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

Eu tentei várias coisas para fazer o método DELETE funcionar (eu estava obtendo o método 405 não permitido na API da web) e, finalmente, adicionei [Route ("api / scan / {id}")] ao meu controlador e funcionou bem. espero que este post ajude alguém.

     // 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);
    }
user2662006
fonte
Por algum motivo, só não estava funcionando para excluir, para criar e atualizar funcionou bem. Bem, acabei de adicionar [HttpPost] e funcionou. Mas obrigado, você me colocou no caminho certo e só me custou 5 minutos agora :)
Rubenisme
1
Por que você não está apenas adicionando o atributo [HttpDelete]?
johnny 5 de
14

Meu problema acabou sendo o Roteamento de Atributos na WebAPI. Eu criei uma rota personalizada e a tratou como um GET em vez de WebAPI, descobrindo que era um POST

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

Eu sabia que tinha que ser algo bobo (que consome o dia inteiro)

Nexxas
fonte
Isso salvou meu dia!
Phate01 de
6

O Chrome frequentemente tenta fazer uma OPTIONSchamada antes de fazer uma postagem. Ele faz isso para garantir que os cabeçalhos CORS estejam em ordem. Pode ser problemático se você não estiver lidando com a OPTIONSchamada em seu controlador de API.

public void Options() { }
Nate Zaugg
fonte
6

Este erro também pode ocorrer quando você tenta se conectar a http enquanto o servidor está em https.

Foi um pouco confuso porque minhas solicitações de obtenção estavam OK, o problema estava presente apenas com solicitações posteriores.

FrankyHollywood
fonte
4

Eu estava recebendo o 405 em minha chamada GET, e o problema acabou que eu nomeei o parâmetro no método do lado do servidor GET Get(int formId)e precisei alterar a rota ou renomeá-la Get(int id).

Sako73
fonte
4

Você também pode obter o erro 405 se disser que seu método está esperando um parâmetro e você não o está passando.

Isso NÃO funciona (erro 405)

Visualização HTML / Javascript

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

Web Api:

public HttpResponseMessage GetNews(int id)

Portanto, se a assinatura do método for como a acima, você deve fazer:

Visualização HTML / Javascript

$.ajax({
         url: '/api/News/5',
         //.....
Tom Stickel
fonte
Parece que estou encontrando erros 405 por vários motivos, todos eles se resumem ao fato de tentar HIT a assinatura do método e um problema de parâmetro ou um problema de nomenclatura de convenção ou um problema de atributo, etc ...
Tom Stickel
4

Estou atrasado para esta festa, mas como nada acima era viável ou funcionava na maioria dos casos, aqui está como isso foi finalmente resolvido para mim.

No servidor em que o site / serviço estava hospedado, um recurso era necessário! ATIVAÇÃO HTTP !!!

Server Manager> Manage> Add Roles and Features> next next next to you get to Features> Under .NET (each version), tick HTTP Activation. Observe também que há um escondido em> net> WCF Services.

Isso funcionou instantaneamente! Isso estava derretendo meu cérebro

Monolithcode
fonte
4

Se você tem uma rota como

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

Você precisa usar exatamente o mesmo nome de parâmetro no método, por exemplo

public ReactorModel GetReactor(reactorId)
{
 ...
}

Se você não passar exatamente o mesmo parâmetro, poderá obter o erro "método 405 não permitido" porque a rota não corresponderá à solicitação e o WebApi atingirá um método controlador diferente com método HTTP permitido diferente.

roylac
fonte
Isso também não é uma resposta!
Divyang Desai
@Div "Método 405 não permitido" pode ser mostrado no caso que eu compartilhei porque o método não irá capturar api-call porque a configuração da rota é inválida. A api-call pode então atingir outro método não intencional que pode ter uma ação HTTP diferente permitida. Sim, concordo que esta resposta pode não ser 100% relevante para a pergunta real, porém o título da pergunta do Xardas não é muito específico e acredito que muitas pessoas que chegam aqui em busca de respostas para a pergunta declarada pelo título podem achar esta resposta útil.
roylac 01 de
3

Isso não responde à sua pergunta específica, mas quando tive o mesmo problema, acabei aqui e imaginei que mais pessoas poderiam fazer o mesmo.

O problema que eu tive foi que eu tinha declarado indeliberadamente meu método Get como estático . Perdi isso durante toda a manhã e não causou avisos de atributos ou similares.

Incorreta:

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

Corrigir:

public class EchoController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }
}
Per Stolpe
fonte
3

Aqui está uma solução

<handlers accessPolicy="Read, Script"> <remove name="WebDAV" /> </handlers>

artigo de solução docs.microsoft.com

e remover WebDAV dos módulos

<remove name="WebDAVModule" />

Danushka Amith Weerasingha
fonte
2

[HttpPost] é desnecessário!

[Route("")]
public void Post(ProductModel data)
{
    ...
}
user3963793
fonte
1
Sim, a maneira que você está fazendo é correta, pois você não precisa de um [HttpPost] explícito, no entanto, existem algumas pessoas que não seguem a convenção (caramba) e, portanto, algo como [Route ("MyMethodSaver"] public string MyMethodtoSave (int? id) -> isso precisaria de um [HttpPost] e funcionaria
Tom Stickel
2

Eu NÃO consegui resolver isso. Eu estava com o CORS habilitado e funcionando desde que o POST retornasse vazio (ASP.NET 4.0 - WEBAPI 1). Quando tentei retornar um HttpResponseMessage, comecei a obter a resposta HTTP 405.

Com base na resposta de Llad acima, dei uma olhada em minhas próprias referências.

Eu tinha o atributo [System.Web.Mvc.HttpPost] listado acima do meu método POST.

Eu mudei isso para usar:

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

Isso resolveu meus problemas. Espero que isto ajude alguém.

Para fins de integridade, eu tinha o seguinte em meu 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
fonte
Isso terá o método chamado na solicitação pré-voo OPTIONS (bem como no POST), ponto em que jsoné provável, nulluma vez que as solicitações pré-voo geralmente não têm cargas úteis, ou você executará a ação pós duas vezes.
glennsl,
1

Tivemos um problema semelhante. Estávamos tentando OBTER de:

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

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

    }

}

Então nós faríamos .GET("/api/car")e isso geraria um 405 error.


O conserto:

O CarController.csarquivo estava no diretório/api/car portanto, quando solicitávamos esse endpoint da API, o IIS retornava um erro porque parecia que estávamos tentando acessar um diretório virtual para o qual não tínhamos permissão.

Opção 1: alterar / renomear o diretório em que o controlador está.
Opção 2: alterar o prefixo da rota para algo que não corresponda ao diretório virtual.

Zze
fonte
1

No meu caso, eu tinha uma pasta física no projeto com o mesmo nome da rota WebAPI (ex. Sandbox) e apenas a solicitação POST foi interceptada pelo manipulador de arquivos estáticos no IIS (obviamente).

Receber um erro 405 enganoso em vez do 404 mais esperado, foi o motivo pelo qual demorei para solucionar o problema.

Não é fácil cair nisso, mas é possível. Espero que ajude alguém.

Panos Roditakis
fonte
1

De minha parte, meu gerenciador de POST tinha a seguinte forma:

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

Descobri que precisava trocar os argumentos , ou seja, os dados do corpo primeiro, depois o parâmetro da rota, como este:

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

verifique o arquivo .csproj do projeto e altere

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

para o url do seu site assim

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

Outro possível problema que causa o mesmo comportamento são os parâmetros padrão no roteamento. No meu caso, o controlador foi localizado e instanciado corretamente, mas o POST foi bloqueado devido à Getação padrão especificada:

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

Eu estava tendo exatamente o mesmo problema. Procurei por duas horas o que estava errado sem sorte até perceber que meu POSTmétodo era o privatecontrário public.

Engraçado agora ver que a mensagem de erro é genérica. Espero que ajude!

Gonzo345
fonte
0

Certifique-se de que seu controlador herda da Controllerclasse.

Pode até ser mais louco que as coisas funcionem localmente, mesmo sem isso.

RAM
fonte