Sporadyczny wyjątek mvc asp.net: „Nie można znaleźć metody akcji publicznej ABC na kontrolerze XYZ”.

92

Otrzymuję sporadyczny wyjątek z informacją, że mvc asp.net nie może znaleźć metody akcji. Oto wyjątek:

W kontrolerze „Schoon.Form.Web.Controllers.ChrisController” nie można znaleźć metody akcji publicznej „Fill”.

Myślę, że mam poprawnie skonfigurowany routing, ponieważ ta aplikacja działa przez większość czasu. Oto metoda działania kontrolera.

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

Trasa:

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

A oto stos:

System.Web.HttpException: nie można znaleźć metody akcji publicznej „Fill” na kontrolerze „Schoon.Form.Web.Controllers.ChrisController”. at System.Web.Mvc.Controller.HandleUnknownAction (String actionName) w C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: wiersz 197 w System.Web.Mvc.Controller.ExecuteCore () w C : \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: wiersz 164 w System.Web.Mvc.ControllerBase.Execute (RequestContext requestContext) w C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: wiersz 76 w System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute (RequestContext requestContext) w C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: wiersz 87 w System.Web.Mvc.MvcHandler.ProcessRequest (HttpContextBase httpContext) w C:

Oto przykład moich filtrów, wszystkie działają w ten sam sposób:

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

Dzięki, Chris

Chris Schoon
źródło
28
Miałem podobny problem, który moim zdaniem jest wart odnotowania w tym miejscu, ponieważ był to pierwszy wynik, który pojawił się w Google podczas wyszukiwania powyższego wyjątku. Moja aplikacja zgłosiła ten wyjątek podczas przesyłania nieprawidłowego formularza. Było to spowodowane tym, że strona, która była (ponownie) renderowana, wywołując RenderAction, a akcja, która została wywołana w celu renderowania częściowego widoku, została oznaczona atrybutem HttpGet, usunięcie tego atrybutu rozwiązało problem.
s1mm0t
3
Zauważyłem również to zachowanie - być może najlepiej jest nie stosować żadnych atrybutów HTTP do metod kontrolera, które zwracają PartialViewResults.
Stuart
1
@ s1mm0t: ma rację. w moim przypadku jego komentarz rozwiązał problem
Mazdak Shojaie
@ s1mm0t - natychmiast prześlij mi swój adres pocztowy. Butelka szkockiej jest już w drodze w te Święta !!!!!
Shane
Znaleźliśmy coś podobnego: w niektórych przypadkach zwracanie wyniku innej akcji zamiast przekierowania do tej akcji powodowało problem. Ex PostSomething { return HomePageActionMethod() }zawodzi tam, gdzie PostSomething { return RedirectToAction(nameof(HomePageActionMethod)); }działa. (w naszym przypadku obraźliwa akcja w widoku znajduje się w innym kontrolerze i prawdopodobnie ten kontroler nie jest w pełni zainicjowany pierwszą metodą wywołania.
jleach

Odpowiedzi:

62

Znaleźliśmy odpowiedź. Przejrzeliśmy nasze dzienniki internetowe. Okazało się, że otrzymywaliśmy dziwne akcje http (czasowniki / metody), takie jak OPCJE, PROPFIND i HEAD.

Wydaje się, że jest to przyczyną niektórych wyjątków od tez. To wyjaśnia, dlaczego było to przerywane.

Odtworzyliśmy problem za pomocą narzędzia 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

Poprawka, której użyliśmy, polegała na dodaniu sekcji autoryzacji do web.config:

<authorization>
  <deny users="*" verbs="OPTIONS, PROPFIND, HEAD"/>
</authorization>
Chris Schoon
źródło
3
Odkryliśmy również, że boty czasami przeszukują Twoją witrynę - a nawet JavaScript - w celu znalezienia linków. Następnie próbują wysyłać żądania do tych identyfikatorów URI z niewłaściwym czasownikiem HTTP. Na przykład, jeśli masz wywołanie jQuery do jakiejś akcji - np. / Some-action i ta metoda wymaga POST, bot może próbować wysłać GET, co spowoduje wyświetlenie tego błędu. Twoje dzienniki internetowe z pewnością mogą pomóc w potwierdzeniu, czy tak jest. Widzimy nawet, jak robi to Googlebot.
jakejgordon
Ten sam błąd występuje tylko na serwerze Live (IIS 7.5). Wdrożenie działa dobrze na moim komputerze deweloperskim, a także na innym komputerze wsparcia. dodanie tych czasowników i usunięcie HttpGet nie rozwiązało problemu. Wszelkie dalsze sugestie proszę.
bjan
Alternatywą dla odrzucania przychodzących żądań HEAD może być podanie odpowiedniej odpowiedzi. Zobacz stackoverflow.com/a/3197128/12484
Jon Schneider
15

Mieliśmy podobny problem, ale stwierdziliśmy, że dzieje się tak, ponieważ użytkownik wysyłał post do kontrolera po przekroczeniu limitu czasu logowania. System został następnie przekierowany do ekranu logowania. Po zalogowaniu się przekierował z powrotem na adres URL, do którego użytkownik próbował wysłać wiadomość, ale tym razem zamiast tego wykonywał żądanie GET, a zatem nie znajdował akcji oznaczonej atrybutem [HttpPost].

Johann Strydom
źródło
Moje obecne rozwiązanie polega na tym, aby zawsze przekierowywać z powrotem do akcji Indeks na końcu akcji. Przepraszam za późną odpowiedź.
Johann Strydom,
7

Mam ten sam problem w asp.net mvc. ten błąd - 404 nie znaleziono. Rozwiązuję problem w ten sposób - umieść ten kod w 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
źródło
6

Właśnie mieliśmy ten sam problem z naszą aplikacją i udało mi się go prześledzić do problemu z javascript / jquery. Mamy linki w naszej aplikacji zdefiniowane za pomocą Html.ActionLink (), które są później nadpisywane w POST przez jquery.

Najpierw zdefiniowaliśmy link:

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

Później nadpisujemy domyślną akcję naszą funkcją SomePostEventHandler:

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

To uderzało w naszą akcję MVC, która miała filtr HttpPost:

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

Odkryliśmy, że przez większość czasu działało to świetnie. Jednak przy niektórych powolnym ładowaniu strony (lub bardzo szybkich użytkownikach) użytkownik klikał odsyłacz przed uruchomieniem zdarzenia jquery $ (document) .ready (), co oznacza, że ​​próbował GET / Controller / SomeAction / XX zamiast mianowanie.

Nie chcemy, aby użytkownik POBIERAŁ ten ​​adres URL, więc usunięcie filtra nie jest dla nas opcją. Zamiast tego po prostu powiązaliśmy zdarzenie onclick linku akcji bezpośrednio (musieliśmy nieznacznie zmienić SomePostEventHandler (), aby to zadziałało):

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

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

Tak więc morał z tej historii, przynajmniej dla nas, jest taki, że jeśli widzisz te błędy, wyśledź adres URL, na który MYŚLISZ, że publikujesz i upewnij się, że tak jest.

jslatts
źródło
Generalnie należy zachować ostrożność podczas POST z hiperłącza html. Istnieją hiperłącza, które prowadzą użytkownika do innej strony (http get), a przyciski html powinny przesyłać formularz (post http).
stevie_c
2

Ja też miałem ten problem.

W moim przypadku to było związane z czasownika ograniczeń w zakresie wymaganym działaniem, gdzie widok był POSTjednak częściowy widok stosownego wniosku w ciągu wspierany GETi HEADwyłącznie. Dodanie POSTzlecenia do AcceptVerbsAttribute(w MVC 1.0) rozwiązało problem.

wolfyuk
źródło
2

Z dzienników IIS wynika, że ​​nasz problem był spowodowany przez Googlebota próbującego POST i GET dla akcji kontrolera tylko POST.

W tym przypadku polecam obsłużyć sugestię 404 jak Dmitriy.

Powiększenie
źródło
1

Aktualnie zaakceptowana odpowiedź działa zgodnie z oczekiwaniami, ale nie jest podstawowym przypadkiem użycia tej funkcji. Zamiast tego użyj funkcji zdefiniowanej przez ASP.NET. W moim przypadku zaprzeczyłem wszystkiemu oprócz GET i POST:

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

Z powyższym fragmentem kodu MVC poprawnie zwróci błąd 404

Valchris
źródło
0

Nie powinno

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

Co robią twoje filtry? Czy nie mogą ukryć akcji, na przykład ActionMethodSelectorAttribute?

królowa3
źródło
To jest błąd edycji. Próbowałem chronić niewinnych.
Chris Schoon,
Wypełniają niektóre parametry. Na przykład UserIdFilter jest pomocnikiem w pobieraniu identyfikatora użytkownika z sesji / pliku cookie / itp. Wypełnia pierwszy parametr. Zmienię post, aby go uwzględnić.
Chris Schoon,
0

Mam podobny problem z ładowaniem plików qq

Kiedy akcja wpisu to /Document/Save, otrzymuję wyjątek Publiczna metoda akcji „Zapisz” nie została znaleziona na kontrolerze „Project.Controllers.DocumentController”.

Ale jeśli akcja post jest /Document/Save/ taka, post jest poprawny i działa!

Boże chroń / ?

Tuizi
źródło
0

Moja główna przyczyna była podobna do tej wspomnianej w komentarzu.

Byłem ajaxSubmittingformularzem po kliknięciu przycisku. Jedno z pól formularza było typu Date. Jednak ze względu na różnice w formatach daty między komputerem klienckim a serwerem nie wykonał metody POST w kontrolerze. Serwer odesłał 302odpowiedź, a następnie wysłał plikGET żądanie tej samej metody.

Jednak akcja w kontrolerze została ozdobiona HttpPostatrybutem i dlatego nie mogła znaleźć metody i odesłała plik404 odpowiedź.

Właśnie naprawiłem kod w taki sposób, że niezgodność formatów daty nie powodowała błędu, a problem został naprawiony.

mridula
źródło
0

Usuń [HttpGet]atrybuty i zadziała :)

Cătălin Rădoi
źródło
Chociaż to „rozwiązuje” błędy, istnieje prawdopodobieństwo, że ty (lub ktoś przed tobą) umieścisz [HttpGet]tam te atrybuty celowo, aby zapobiec wywoływaniu działań przez inne VERB
Nick Orlando
0

Dla każdego, kto ma ten problem z angularjs, MVC i {{imagepath}} wstawiamy w atrybutach image src, np .:

„W kontrolerze nie znaleziono metody akcji publicznej '{{imagepath}} previous.png'”

Rozwiązaniem jest użycie ng-src zamiast src.

Mam nadzieję, że to komuś pomoże :)

davaus
źródło
prawie rok później szukałem tego :) tnx!
Verthosa
0

Sprawdź, czy samo przejście do danego adresu URL wystarczy, aby odtworzyć błąd. Byłoby tak, gdyby akcja została zdefiniowana tylko jako akcja POST. Dzięki temu możesz dowolnie odtworzyć błąd.

W każdym razie możesz globalnie obsłużyć błąd, jak poniżej. Inna odpowiedź, która odwołuje się, HandleUnknownActionobsługuje tylko adresy URL ze złymi nazwami akcji, a nie złymi nazwami kontrolerów. Poniższe podejście obsługuje oba.

Dodaj to do swojego kontrolera podstawowego (tutaj pominięto kod wyświetlania):

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

Dodaj globalną procedurę obsługi wyjątków do Global.asax.cs, która wywołuje powyższą metodę lub robi wszystko, co chcesz zrobić z przechwyconym błędem 404:

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
źródło