Прерывистое исключение asp.net mvc: «Метод открытого действия ABC не может быть найден на контроллере XYZ».

92

Я получаю периодическое исключение, говорящее, что asp.net mvc не может найти метод действия. Вот исключение:

Не удалось найти общедоступный метод действия Fill на контроллере Schoon.Form.Web.Controllers.ChrisController.

Я думаю, что у меня правильно настроена маршрутизация, потому что это приложение работает большую часть времени. Вот метод действия контроллера.

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

Маршрут:

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

А вот и стек:

System.Web.HttpException: не удалось найти общедоступный метод действия «Fill» на контроллере «Schoon.Form.Web.Controllers.ChrisController». в System.Web.Mvc.Controller.HandleUnknownAction (String actionName) в C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: строка 197 в System.Web.Mvc.Controller.ExecuteCore () в C : \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ Controller.cs: строка 164 в System.Web.Mvc.ControllerBase.Execute (RequestContext requestContext) в C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: строка 76 в System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute (RequestContext requestContext) в C: \ dev \ ThirdParty \ MvcDev \ src \ SystemWebMvc \ Mvc \ ControllerBase.cs: строка 87 в System.Web.Mvc.MvcHandler.ProcessRequest (HttpContextBase httpContext) в C:

Вот пример моих фильтров, все они работают одинаково:

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

Спасибо Крис

Крис Шун
источник
28
У меня была аналогичная проблема, которую, я думаю, стоит отметить здесь, поскольку это был первый результат, который появился в Google при поиске указанного выше исключения. Мое приложение выдало это исключение при отправке недействительной формы. Это произошло из-за того, что страница, которая была (повторно) визуализирована, вызывала RenderAction, и действие, которое было вызвано для визуализации частичного представления, было помечено атрибутом HttpGet, удаление этого атрибута решило проблему.
s1mm0t
3
Я тоже заметил это поведение - возможно, лучше не применять какие-либо атрибуты Http к методам контроллера, которые возвращают PartialViewResults.
Стюарт
1
@ s1mm0t: верно. в моем случае его комментарий решил проблему
Mazdak Shojaie
@ s1mm0t - немедленно пришлите мне свой почтовый адрес. Бутылка скотча в пути для вас на это Рождество !!!!!
Шейн
Мы обнаружили нечто подобное: в некоторых случаях возвращение другого результата действия вместо перенаправления на это действие вызывало проблему. Ex PostSomething { return HomePageActionMethod() }не PostSomething { return RedirectToAction(nameof(HomePageActionMethod)); }работает там, где работает. (в нашем случае оскорбительное действие в представлении находится в другом контроллере, и, предположительно, этот контроллер не полностью инициализирован с помощью первого метода вызова.
jleach 06

Ответы:

62

Мы нашли ответ. Мы заглянули в наши веб-журналы. Он показал, что мы получали некоторые странные HTTP-действия (глаголы / методы), такие как OPTIONS, PROPFIND и HEAD.

Это, кажется, причина некоторых из этих исключений. Это объясняет, почему он был прерывистым.

Мы воспроизвели проблему с инструментом 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

Исправление, которое мы использовали, заключалось в добавлении раздела авторизации в web.config:

<authorization>
  <deny users="*" verbs="OPTIONS, PROPFIND, HEAD"/>
</authorization>
Крис Шун
источник
3
Мы также обнаружили, что боты иногда сканируют ваш сайт - и даже javascript - в поисках ссылок. Затем они пытаются отправить запросы на эти URI с неправильным HTTP-глаголом. Например, если у вас есть вызов jQuery для некоторого действия, например / some-action, и для этого метода требуется POST, бот может попытаться отправить GET, что приведет к появлению этой ошибки. Ваши веб-журналы определенно могут помочь подтвердить, так ли это. Мы даже видим, как это делает робот Google.
jakejgordon 01
У меня такая же ошибка только на Live сервере (IIS 7.5). Развертывание отлично работает на моей машине разработки, а также на другой машине поддержки. добавление этих глаголов и удаление HttpGet не устранило проблему. Любые дальнейшие предложения, пожалуйста.
bjan 08
В качестве альтернативы отклонению входящих запросов HEAD вы можете предоставить соответствующий ответ. См. Stackoverflow.com/a/3197128/12484
Джон Шнайдер
15

У нас была аналогичная проблема, но мы обнаружили, что это происходит из-за того, что пользователь отправлял сообщение на контроллер после того, как его логин истек. Затем система перенаправляется на экран входа в систему. После входа в систему он перенаправлялся обратно на URL-адрес, по которому пользователь пытался отправить сообщение, но на этот раз он выполнял запрос GET и, следовательно, не находил действие, которое было отмечено атрибутом [HttpPost].

Иоганн Стридом
источник
Мое текущее решение - по возможности всегда выполнять перенаправление обратно к действию Index в конце действия. Извините за поздний ответ.
Johann Strydom
7

У меня такая же проблема в asp.net mvc. эта ошибка - 404 не найдено. Я решаю проблему таким образом - помещаю этот код в 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();
    }
Дмитрий
источник
6

У нас была такая же проблема в нашем приложении, и я смог отследить ее до проблемы с javascript / jquery. У нас есть ссылки в нашем приложении, определенные с помощью Html.ActionLink (), которые позже переопределяются в POST с помощью jquery.

Сначала мы определили ссылку:

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

Позже мы переопределим действие по умолчанию с помощью нашей функции SomePostEventHandler:

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

Это поразило наше действие MVC с фильтром HttpPost:

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

Мы обнаружили, что большую часть времени это работало отлично. Однако при медленной загрузке страницы (или очень быстрых пользователях) пользователь щелкал ссылку до того, как сработало событие jquery $ (document) .ready (), что означает, что они пытались GET / Controller / SomeAction / XX вместо размещение.

Мы не хотим, чтобы пользователь ПОЛУЧИЛ этот URL-адрес, поэтому удаление фильтра для нас не вариант. Вместо этого мы просто подключили событие onclick ссылки действия напрямую (нам пришлось немного изменить SomePostEventHandler (), чтобы это работало):

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

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

Итак, мораль этой истории, по крайней мере для нас, заключается в том, что если вы видите эти ошибки, отследите URL-адрес, на который, как вы думаете, вы отправляете сообщение, и убедитесь, что это так.

jslatts
источник
В общем, вы должны быть осторожны при отправке POST с гиперссылки html. Существуют гиперссылки для перехода пользователя на другую страницу (http get), а кнопки html должны отправлять форму (http post).
stevie_c
2

У меня тоже была эта проблема.

В моем случае это было связано с ограничениями глаголов на запрошенное действие, где представление было, POSTно частичное представление запрашивалось в пределах поддерживаемого GETи HEADтолько. Добавление POSTглагола в AcceptVerbsAttribute(в MVC 1.0) решило проблему.

вольфюк
источник
2

Судя по журналам IIS, наша проблема была вызвана попыткой робота Googlebot выполнить POST и GET для действия контроллера только POST.

В этом случае я рекомендую обрабатывать 404, как предложение Дмитрия.

Увеличить
источник
1

Принятый в настоящее время ответ работает должным образом, но не является основным вариантом использования этой функции. Вместо этого используйте функцию, определенную ASP.NET. В моем случае я отрицал все, кроме GET и POST:

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

В приведенном выше фрагменте кода MVC правильно вернет 404

Valchris
источник
0

Не должно быть

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

Кроме того, что делают ваши фильтры? Разве они не могут скрыть действие, такое как ActionMethodSelectorAttribute?

королева3
источник
Это ошибка редактирования. Я пытался защитить невиновных.
Chris Schoon
Они заполняют некоторые параметры. Например, UserIdFilter является помощником для получения идентификатора пользователя из сеанса / cookie и т. Д. Он заполняет первый параметр. Я отредактирую сообщение, чтобы включить его.
Chris Schoon
0

У меня аналогичная проблема с загрузкой файла qq

Когда выполняется действие публикации, /Document/Saveя получаю исключение . Метод открытого действия «Сохранить» не был найден на контроллере Project.Controllers.DocumentController.

Но если действие поста есть /Document/Save/, пост правильный и работает!

Боже, храни / ?

Туизи
источник
0

Моя основная причина была аналогична той, что упоминалась в комментарии.

Я был ajaxSubmittingформой по щелчку кнопки. Одно из полей формы было типа Date. Однако из-за разницы в форматах даты между клиентским и серверным компьютером он не выполнил метод POST в контроллере. Сервер отправил 302ответ, а затем снова отправил GETзапрос на тот же метод.

Однако действие в контроллере было оформлено HttpPostатрибутом, поэтому он не смог найти метод и отправил 404ответ.

Я просто исправил код таким образом, чтобы несоответствие форматов даты не приводило к ошибке, и проблема была исправлена.

мридула
источник
0

Уберите [HttpGet]атрибуты и все заработает :)

Кэтэлин Рэдой
источник
Хотя это «решает» ошибки, существует вероятность того, что вы (или кто-то до вас) [HttpGet]намеренно поместили эти атрибуты туда, чтобы предотвратить вызов действий через любые другие ГЛАГОЛЫ
Ник Орландо,
0

Для тех, у кого есть эта проблема с angularjs, MVC и тип {{imagepath}} вставляют в атрибуты src изображения, например:

«На контроллере не найден метод открытого действия '{{imagepath}} previous.png'»

Решение - использовать ng-src вместо src.

Надеюсь, это кому-то поможет :)

Даваус
источник
почти год спустя искал вот такую ​​:) tnx!
Verthosa
0

Посмотрите, достаточно ли простого перехода по указанному URL-адресу для воспроизведения ошибки. Было бы, если бы действие было определено только как действие POST. Это позволяет воспроизвести ошибку по желанию.

В любом случае вы можете глобально обработать ошибку, как показано ниже. Другой ответ здесь, который ссылается HandleUnknownActionтолько на обработку URL-адресов с неправильными именами действий, а не с плохими именами контроллеров. Следующий подход обрабатывает оба.

Добавьте это в свой базовый контроллер (код просмотра здесь опущен):

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

Добавьте в Global.asax.cs глобальный обработчик исключений, который вызывает указанный выше метод или выполняет все, что вы хотите сделать с обнаруженной ошибкой 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));
    }
}
Таваб Вакил
источник