Exception mvc asp.net intermittente: "Une méthode d'action publique ABC est introuvable sur le contrôleur XYZ."

92

Je reçois une exception intermittente indiquant que asp.net mvc ne peut pas trouver la méthode d'action. Voici l'exception:

Une méthode d'action publique «Fill» est introuvable sur le contrôleur «Schoon.Form.Web.Controllers.ChrisController».

Je pense que le routage est correctement configuré car cette application fonctionne la plupart du temps. Voici la méthode d'action du contrôleur.

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

La route:

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

Et voici la pile:

System.Web.HttpException: Une méthode d'action publique 'Fill' n'a pas pu être trouvée sur le contrôleur 'Schoon.Form.Web.Controllers.ChrisController'. à System.Web.Mvc.Controller.HandleUnknownAction (String actionName) dans C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: ligne 197 à System.Web.Mvc.Controller.ExecuteCore () dans C : \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: ligne 164 à System.Web.Mvc.ControllerBase.Execute (RequestContext requestContext) dans C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: ligne 76 à System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute (RequestContext requestContext) dans C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: ligne 87 à System.Web.Mvc.MvcHandler.ProcessRequest (HttpContextBase httpContext) dans C:

Voici un exemple de mes filtres, ils fonctionnent tous de la même manière:

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);
    }
}

Merci Chris

Chris Schoon
la source
28
J'ai eu un problème similaire qui, je pense, mérite d'être noté ici car c'était le premier résultat qui est apparu dans Google lors de la recherche de l'exception ci-dessus. Mon application a levé cette exception lors de la soumission d'un formulaire invalide. Cela était dû au fait que la page qui était (re) rendue appelait RenderAction et que l'action appelée pour rendre une vue partielle était marquée avec l'attribut HttpGet, la suppression de cet attribut résolvait le problème.
s1mm0t
3
J'ai également remarqué ce comportement - il est peut-être préférable de ne pas appliquer d'attributs Http aux méthodes de contrôleur qui retournent PartialViewResults.
Stuart
1
@ s1mm0t: a raison. pour mon cas, son commentaire a résolu le problème
Mazdak Shojaie
@ s1mm0t - veuillez m'envoyer votre adresse postale immédiatement. Une bouteille de Scotch est en route pour vous ce Noël !!!!!
Shane
Nous avons trouvé quelque chose de similaire: dans certains cas, le retour d'un autre résultat d'action au lieu d'une redirection vers cette action causait le problème. Ex PostSomething { return HomePageActionMethod() }échoue là où PostSomething { return RedirectToAction(nameof(HomePageActionMethod)); }fonctionne. (dans notre cas, l'action incriminée dans la vue est située dans un contrôleur différent, et vraisemblablement ce contrôleur n'est pas complètement initialisé avec la première méthode d'appel.
jleach

Réponses:

62

Nous avons trouvé la réponse. Nous avons examiné nos journaux Web. Cela a montré que nous recevions des actions http étranges (verbes / méthodes) comme OPTIONS, PROPFIND et HEAD.

Cela semble être la cause de certaines de ces exceptions. Cela explique pourquoi il était intermittent.

Nous avons reproduit le problème avec l'outil 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

Le correctif que nous avons utilisé était d'ajouter une section d'autorisation à web.config:

<authorization>
  <deny users="*" verbs="OPTIONS, PROPFIND, HEAD"/>
</authorization>
Chris Schoon
la source
3
Nous avons également constaté que les robots explorent parfois votre site - et même javascript - pour trouver des liens. Ils essaient ensuite d'envoyer des requêtes à ces URI avec le mauvais verbe HTTP. Par exemple, si vous avez un appel jQuery à une action - par exemple / some-action et que cette méthode nécessite un POST, le bot peut tenter d'envoyer un GET, ce qui provoquera l'apparition de cette erreur. Vos journaux Web pourraient certainement aider à confirmer si tel était le cas. Nous voyons même googlebot faire cela.
jakejgordon
J'ai cette même erreur uniquement sur le serveur Live (IIS 7.5). Le déploiement fonctionne bien sur ma machine de développement ainsi que sur une autre machine de support. l'ajout de ces verbes et la suppression de HttpGet n'ont pas résolu le problème. Toute autre suggestion s'il vous plaît.
bjan
Au lieu de refuser les demandes HEAD entrantes, vous souhaiterez peut-être servir une réponse appropriée. Voir stackoverflow.com/a/3197128/12484
Jon Schneider
15

Nous avons eu un problème similaire, mais nous avons constaté que cela se produisait parce qu'un utilisateur publiait sur un contrôleur après l'expiration de sa connexion. Le système est ensuite redirigé vers l'écran de connexion. Après s'être connecté, il a redirigé vers l'URL sur laquelle l'utilisateur essayait de publier, mais cette fois, il faisait une requête GET à la place et ne trouvait donc pas l'action qui était marquée d'un attribut [HttpPost].

Johann Strydom
la source
Ma solution actuelle est dans la mesure du possible de toujours faire une redirection vers l'action Index à la fin d'une action. Désolé pour la réponse tardive.
Johann Strydom
7

J'ai eu le même problème dans asp.net mvc. cette erreur - 404 introuvable. Je résous le problème de cette façon - mettez ce code dans 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
la source
6

Nous venons d'avoir le même problème sur notre application et j'ai pu le retracer jusqu'à un problème javascript / jquery. Nous avons des liens dans notre application définis à l'aide de Html.ActionLink () qui sont ensuite remplacés dans les POST par jquery.

Nous avions d'abord défini le lien:

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

Plus tard, nous remplaçons l'action par défaut avec notre fonction SomePostEventHandler:

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

Cela frappait notre action MVC qui avait un filtre HttpPost:

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

Ce que nous avons constaté, c'est que la plupart du temps, cela fonctionnait très bien. Cependant, sur certains chargements de page lents (ou utilisateurs très rapides), l'utilisateur cliquait sur le lien avant que l'événement jquery $ (document) .ready () ne se déclenche, ce qui signifie qu'il essayait de GET / Controller / SomeAction / XX au lieu de affectation.

Nous ne voulons pas que l'utilisateur OBTIENT cette URL, donc la suppression du filtre n'est pas une option pour nous. Au lieu de cela, nous avons simplement câblé l'événement onclick du lien d'action directement (nous avons dû modifier légèrement SomePostEventHandler () pour que cela fonctionne):

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

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

Donc, la morale de l'histoire, du moins pour nous, c'est que si vous voyez ces erreurs, retrouvez l'URL sur laquelle vous PENSEZ POSTER et assurez-vous que vous l'êtes.

jslatts
la source
2

J'ai aussi eu ce problème.

Dans mon cas, il s'agissait de restrictions verbales sur l'action demandée, où la vue était un POSTmais la vue partielle demandée dans pris en charge GETet HEADuniquement. L'ajout du POSTverbe à AcceptVerbsAttribute(dans MVC 1.0) a résolu le problème.

Wolfyuk
la source
2

À partir des journaux IIS, notre problème a été causé par Googlebot tentant de POST et par un GET pour une action de contrôleur POST uniquement.

Pour ce cas, je recommande de gérer le 404 comme la suggestion Dmitriy.

Zoom
la source
1

La réponse actuellement acceptée fonctionne comme prévu mais n'est pas le cas d'utilisation principal de la fonctionnalité. Utilisez plutôt la fonctionnalité définie par ASP.NET. Dans mon cas, j'ai tout nié mais GET et POST:

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

Avec l'extrait de code ci-dessus, MVC renverra correctement un 404

Valchris
la source
0

Ne devrait-il pas être

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

Aussi, que font vos filtres? Ne peuvent-ils pas masquer l'action, comme ActionMethodSelectorAttribute?

reine3
la source
C'est une erreur d'édition. J'essayais de protéger les innocents.
Chris Schoon
Ils remplissent certains des paramètres. Par exemple, UserIdFilter est une aide pour obtenir l'ID utilisateur de session / cookie / etc. Il remplit le premier paramètre. Je vais modifier le message pour l'inclure.
Chris Schoon
0

J'ai le même problème avec le téléchargement de fichiers qq

Lorsque l'action de publication est, /Document/Savej'obtiens l'exception. Une méthode d'action publique «Enregistrer» n'a pas été trouvée sur le contrôleur «Project.Controllers.DocumentController».

Mais si l'action de publication est /Document/Save/, la publication est correcte et fonctionne!

Dieu sauve le / ?

Tuizi
la source
0

Ma cause profonde était similaire à celle mentionnée dans le commentaire.

J'étais ajaxSubmittingune forme sur le clic d'un bouton. L'un des champs du formulaire était de type Date. Cependant, en raison de la différence dans les formats de date entre la machine client et serveur, il n'a pas exécuté la méthode POST dans le contrôleur. Le serveur a renvoyé une 302réponse, puis a renvoyé une GETdemande pour la même méthode.

Cependant, l'action dans le contrôleur a été décorée avec l' HttpPostattribut et par conséquent, il n'a pas pu trouver la méthode et a renvoyé une 404réponse.

Je viens de corriger le code de telle sorte que l'incohérence dans les formats de date ne provoque pas d'erreur et le problème a été résolu.

mridula
la source
0

Supprimez les [HttpGet]attributs et cela fonctionnera :)

Cătălin Rădoi
la source
Bien que cela «résout» les erreurs, il est probable que vous (ou quelqu'un avant vous) [HttpGet]y ayez volontairement mis ces attributs, pour éviter que les actions ne soient appelées via d'autres VERB
Nick Orlando
0

Pour toute personne ayant ce problème avec les insertions angularjs, MVC et {{imagepath}} dans les attributs image src, par exemple:

"Une méthode d'action publique '{{imagepath}} previous.png' n'a pas été trouvée sur le contrôleur"

La solution est d'utiliser ng-src au lieu de src.

J'espère que cela aide quelqu'un :)

Davaus
la source
presque un an plus tard, je cherchais ceci :) tnx!
Verthosa
0

Voyez si la simple navigation vers l'URL en question suffit à reproduire l'erreur. Ce serait le cas si l'action était uniquement définie comme une action POST. Cela vous permet de reproduire l'erreur à volonté.

Dans tous les cas, vous pouvez gérer globalement l'erreur comme ci-dessous. Une autre réponse ici qui fait référence HandleUnknownActionne gère que les URL avec de mauvais noms d'action, pas de mauvais noms de contrôleur. L'approche suivante gère les deux.

Ajoutez ceci à votre contrôleur de base (voir le code omis ici):

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

Ajoutez un gestionnaire d'exceptions global à Global.asax.cs qui appelle la méthode ci-dessus ou fait tout ce que vous voulez faire avec l'erreur 404 interceptée:

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
la source