Exceção intermitente do mvc do asp.net: “Um método de ação pública ABC não pôde ser encontrado no controlador XYZ.”

92

Estou recebendo uma exceção intermitente dizendo que asp.net mvc não consegue encontrar o método de ação. Aqui está a exceção:

Um método de ação pública 'Fill' não pôde ser encontrado no controlador 'Schoon.Form.Web.Controllers.ChrisController'.

Acho que tenho o roteamento configurado corretamente porque este aplicativo funciona na maioria das vezes. Aqui está o método de ação do controlador.

[ActionName("Fill")]
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post), UserIdFilter, DTOFilter]
public ActionResult Fill(int userId, int subscriberId, DisplayMode? mode)
{
     //…
}

O percurso:

routes.MapRoute(
        "SchoonForm",
        "Form/Fill/{subscriberId}",
        new { controller = "ChrisController", action = "Fill" },
        new { subscriberId = @"\d+" }
    );

E aqui está a pilha:

System.Web.HttpException: Um método de ação pública 'Preencher' não pôde ser encontrado no controlador 'Schoon.Form.Web.Controllers.ChrisController'. em System.Web.Mvc.Controller.HandleUnknownAction (String actionName) em C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: linha 197 em System.Web.Mvc.Controller.ExecuteCore () em C : \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: linha 164 em System.Web.Mvc.ControllerBase.Execute (RequestContext requestContext) em C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: linha 76 em System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute (RequestContext requestContext) em C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: linha 87 em System.Web.Mvc.MvcHandler.ProcessRequest (HttpContextBase httpContext) em C:

Aqui está um exemplo de meus filtros, todos eles funcionam da mesma maneira:

public class UserIdFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        const string Key = "userId";

        if (filterContext.ActionParameters.ContainsKey(Key))
        {
            filterContext.ActionParameters[Key] = // get the user id from session or cookie
        }

        base.OnActionExecuting(filterContext);
    }
}

Obrigado chris

Chris Schoon
fonte
28
Tive um problema semelhante que acho que vale a pena observar aqui, pois este foi o primeiro resultado que apareceu no Google ao pesquisar a exceção acima. Meu aplicativo lançou essa exceção ao enviar um formulário inválido. Isso ocorreu porque a página que estava sendo (re) renderizada chamando RenderAction e a ação que foi chamada para renderizar uma visualização parcial foi marcada com o atributo HttpGet, a remoção desse atributo resolveu o problema.
s1mm0t
3
Também observei esse comportamento - talvez seja melhor não aplicar nenhum atributo Http aos métodos do controlador que retornam PartialViewResults.
Stuart
1
@ s1mm0t: está certo. para meu caso, seu comentário resolveu o problema
Mazdak Shojaie
@ s1mm0t - envie-me seu endereço postal imediatamente. Uma garrafa de Scotch está a caminho para você neste Natal !!!!!
Shane
Encontramos algo semelhante: em certos casos, retornar outro resultado de ação em vez de um redirecionamento para a ação que estava causando o problema. Ex PostSomething { return HomePageActionMethod() }falha onde PostSomething { return RedirectToAction(nameof(HomePageActionMethod)); }funciona. (em nosso caso, a ação ofensiva na visualização está localizada em um controlador diferente e, presumivelmente, esse controlador não foi totalmente inicializado com o primeiro método de chamada.
jleach

Respostas:

62

Encontramos a resposta. Verificamos nossos registros da web. Ele mostrou que estávamos recebendo algumas ações http estranhas (verbos / métodos) como OPTIONS, PROPFIND e HEAD.

Essa parece ser a causa de algumas dessas exceções. Isso explica por que era intermitente.

Reproduzimos o problema com a ferramenta curl.exe:

curl.exe -X OPTIONS http://localhost/v2.3.1.0/(S(boztz1aquhzurevtjwllzr45))/Form/Fill/273
curl.exe -X PROPFIND http://localhost/v2.3.1.0/(S(boztz1aquhzurevtjwllzr45))/Form/Fill/273
curl.exe -X HEAD http://localhost/v2.3.1.0/(S(boztz1aquhzurevtjwllzr45))/Form/Fill/273

A correção que usamos foi adicionar uma seção de autorização ao web.config:

<authorization>
  <deny users="*" verbs="OPTIONS, PROPFIND, HEAD"/>
</authorization>
Chris Schoon
fonte
3
Também descobrimos que às vezes os bots rastreiam o seu site - e até mesmo o javascript - para encontrar links. Em seguida, eles tentam enviar solicitações a esses URIs com o verbo HTTP errado. Por exemplo, se você tiver uma chamada jQuery para alguma ação - por exemplo, / alguma-ação e este método requer um POST, o bot pode tentar enviar um GET, o que fará com que esse erro apareça. Seus registros da web podem definitivamente ajudar a confirmar se esse for o caso. Nós até vemos o googlebot fazendo isso.
jakejgordon
Estou tendo esse mesmo erro apenas no servidor Live (IIS 7.5). A implantação funciona bem na minha máquina de desenvolvimento, bem como em outra máquina de suporte. adicionar esses verbos e remover HttpGet não corrigiu o problema. Quaisquer outras sugestões, por favor.
bjan
Uma alternativa para negar solicitações HEAD de entrada, você pode desejar fornecer uma resposta apropriada. Consulte stackoverflow.com/a/3197128/12484
Jon Schneider de
15

Tivemos um problema semelhante, mas descobrimos que isso estava acontecendo porque um usuário estava postando em um controlador depois que seu login expirou. O sistema então redirecionou para a tela de login. Depois de fazer login, ele redirecionava de volta para a URL em que o usuário estava tentando postar, mas desta vez estava fazendo uma solicitação GET e, portanto, não encontrando a ação que estava marcada com um atributo [HttpPost].

Johann Strydom
fonte
Minha solução atual é, na medida do possível, sempre fazer um redirecionamento de volta para a ação Index no final de uma ação. Desculpe pela resposta tardia.
Johann Strydom
7

Eu tenho o mesmo problema no asp.net mvc. este erro - 404 não encontrado. Eu resolvo o problema desta forma - coloque este código em MyAppControllerBase(MVC)

    protected override void HandleUnknownAction(string actionName)
    {
        this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<PagesController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Pages");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }
Dmitriy
fonte
6

Acabamos de ter o mesmo problema em nosso aplicativo e fui capaz de rastreá-lo a um problema de javascript / jquery. Temos links em nosso aplicativo definidos usando Html.ActionLink () que mais tarde são substituídos em POSTs por jquery.

Primeiro definimos o link:

Html.ActionLink("Click Me", "SomeAction", new { id = Model.Id})

Posteriormente, substituímos a ação padrão com nossa função SomePostEventHandler:

 $(document).ready(function() {
      $('#MyLink').click(SomePostEventHandler);
 }

Isso estava atingindo nossa ação MVC que tinha um filtro HttpPost:

 [HttpPost]
 public ActionResult SomeAction(int id)
 {
      //Stuff
 }

O que descobrimos é que na maioria das vezes isso funcionava muito bem. No entanto, em alguns carregamentos de página lentos (ou usuários realmente rápidos), o usuário clicava no link antes do evento jquery $ (document) .ready () ser disparado, o que significa que eles estavam tentando GET / Controller / SomeAction / XX em vez de postagem.

Não queremos que o usuário OBTENHA esse url, portanto, remover o filtro não é uma opção para nós. Em vez disso, apenas conectamos o evento onclick do link de ação diretamente (tivemos que alterar SomePostEventHandler () ligeiramente para que funcionasse):

string clickEvent = "return SomePostEventHandler(this);";

Html.ActionLink("Click Me", "SomeAction", new { id = Model.Id}, new { onclick = clickEvent })

Portanto, a moral da história, pelo menos para nós, é que, se você está vendo esses erros, rastreie a URL para a qual você ACHA que está postando e certifique-se de que está.

jslatts
fonte
2

Eu também tive esse problema.

No meu caso, estava relacionado a restrições de verbos na ação solicitada, onde a visão era uma, POSTmas a visão parcial sendo solicitada em suportado GETe HEADsomente. Adicionar o POSTverbo ao AcceptVerbsAttribute(no MVC 1.0) resolveu o problema.

wolfyuk
fonte
2

A partir dos registros do IIS, nosso problema foi causado por uma tentativa do Googlebot de POST e GET para uma ação do controlador somente POST.

Para este caso, eu recomendo lidar com a sugestão 404 like Dmitriy.

Ampliação
fonte
1

A resposta aceita atualmente funciona conforme o esperado, mas não é o caso de uso principal para o recurso. Em vez disso, use o recurso definido pelo ASP.NET. No meu caso, neguei tudo, exceto GET e POST:

  <system.webServer>
  <security>
      <requestFiltering>
          <verbs allowUnlisted="false">
              <add verb="GET" allowed="true"/>
              <add verb="POST" allowed="true"/>
          </verbs>
      </requestFiltering>
  </security>
 </system.webServer>

Com o snippet de código acima, o MVC retornará corretamente um 404

Valchris
fonte
0

Não deveria ser

routes.MapRoute(
        "SchoonForm",
        "Form/Fill/{subscriberId}",
        new { controller = "Chris", action = "Fill" },

Além disso, o que seus filtros fazem? Eles não podem ocultar a ação, como ActionMethodSelectorAttribute?

queen3
fonte
Isso é um erro de edição. Eu estava tentando proteger os inocentes.
Chris Schoon
Eles preenchem alguns dos parâmetros. Por exemplo, o UserIdFilter é um auxiliar para obter o id do usuário da sessão / cookie / etc. Ele preenche o primeiro parâmetro. Vou editar a postagem para incluí-la.
Chris Schoon
0

Tenho um problema semelhante com qq File Upload

Quando a ação post é /Document/Save, recebo a exceção Um método de ação pública 'Salvar' não foi encontrado no controlador 'Project.Controllers.DocumentController'.

Mas se a ação da postagem for /Document/Save/, a postagem está correta e funciona!

Deus salve o / ?

Tuizi
fonte
0

Minha causa raiz era semelhante à mencionada no comentário.

Eu era ajaxSubmittingum formulário com o clique de um botão. Um dos campos do formulário era do tipo Date. No entanto, devido à diferença nos formatos de data entre a máquina cliente e servidor, ela não executou o método POST no controlador. O servidor enviou de volta uma 302resposta e, em seguida, enviou uma GETsolicitação para o mesmo método novamente.

No entanto, a ação no controlador foi decorada com o HttpPostatributo e, portanto, não pôde encontrar o método e enviou de volta uma 404resposta.

Acabei de consertar o código de forma que a incompatibilidade nos formatos de data não causasse um erro e o problema foi corrigido.

mridula
fonte
0

Remova os [HttpGet]atributos e vai funcionar :)

Cătălin Rădoi
fonte
Embora isso "resolva" os erros, a probabilidade é que você (ou alguém antes de você) coloque esses [HttpGet]atributos ali propositalmente, para evitar que as ações sejam chamadas por quaisquer outros VERBOS
Nick Orlando
0

Para qualquer pessoa que tenha este problema com angularjs, MVC e {{imagepath}} digite inserções nos atributos src da imagem, por exemplo:

"Um método de ação pública '{{imagepath}} previous.png' não foi encontrado no controlador"

A solução é usar ng-src em vez de src.

Espero que isso ajude alguém :)

Davaus
fonte
quase um ano depois, eu estava procurando por isso :) tnx!
Verthosa
0

Veja se simplesmente navegar até o URL em questão é suficiente para reproduzir o erro. Seria se a ação fosse definida apenas como uma ação POST. Isso permite que você reproduza o erro à vontade.

Em qualquer caso, você pode lidar globalmente com o erro conforme abaixo. Outra resposta aqui que faz referênciaHandleUnknownAction tratam apenas de URLs com nomes de ação inválidos, não nomes de controladores ruins. A abordagem a seguir trata de ambos.

Adicione isso ao seu controlador de base (veja o código omitido aqui):

public ActionResult Error(string errorMessage)
{
    return View("Error");  // or do something like log the error, etc.
}

Adicione um manipulador de exceção global a Global.asax.cs que chama o método acima ou faz o que quer que você queira fazer com o erro 404 detectado:

void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();  // get the exception object
    HttpException httpException = ex as HttpException;

    if (httpException != null && httpException.GetHttpCode() == 404)  // if action not found
    {
        string errorMessage = "The requested page was not found.";

        RouteData routeData = new RouteData();
        routeData.Values.Add("controller", "Base");
        routeData.Values.Add("action", "Error");
        routeData.Values.Add("errorMessage", errorMessage);

        Server.ClearError();
        Response.TrySkipIisCustomErrors = true;

        // Go to our custom error view.
        IController errorController = new BaseController();
        errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    }
}
Tawab Wakil
fonte