Intermittent asp.net mvc exception: “A public acti

2020-01-29 03:14发布

I'm getting an intermittent exception saying that asp.net mvc can’t find the action method. Here’s the exception:

A public action method 'Fill' could not be found on controller 'Schoon.Form.Web.Controllers.ChrisController'.

I think I have the routing set up correctly because this application works most of the time. Here is the controller’s action method.

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

The route:

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

And here is the stack:

System.Web.HttpException: A public action method 'Fill' could not be found on controller 'Schoon.Form.Web.Controllers.ChrisController'. at System.Web.Mvc.Controller.HandleUnknownAction(String actionName) in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\Controller.cs:line 197 at System.Web.Mvc.Controller.ExecuteCore() in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\Controller.cs:line 164 at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\ControllerBase.cs:line 76 at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\ControllerBase.cs:line 87 at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\MvcHandler.cs:line 80 at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\MvcHandler.cs:line 68 at System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) in C:\dev\ThirdParty\MvcDev\src\SystemWebMvc\Mvc\MvcHandler.cs:line 104 at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Here is an example of my filters they all work the same way:

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

Thanks, Chris

13条回答
Deceive 欺骗
2楼-- · 2020-01-29 03:52

See if simply browsing to the URL in question is enough to reproduce the error. It would if the action was only defined as a POST action. Doing this allows you to reproduce the error at will.

In any case, you can globally handle the error as below. Another answer here that references HandleUnknownAction only handles URLs with bad action names, not bad controller names. The following approach handles both.

Add this to your base controller (view code omitted here):

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

Add a global exception handler to Global.asax.cs that calls the method above or does whatever else you want to do with the caught 404 error:

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));
    }
}
查看更多
我想做一个坏孩纸
3楼-- · 2020-01-29 03:55

From the IIS logs our problem was caused by Googlebot attempting POST and a GET for a POST only controller action.

For this case I recommend handling the 404 like Dmitriy suggestion.

查看更多
我只想做你的唯一
4楼-- · 2020-01-29 03:59

My root cause was similar to the one mentioned in the comment.

I was ajaxSubmitting a form upon the click of a button. One of the form fields was of type Date. However, because of the difference in the date formats between the client and server machine it did not execute the POST method in the controller. The server sent back a 302 response and then sent a GET request for the same method again.

However, the action in the controller was decorated with the HttpPost attribute and hence it could not find the method and sent back a 404 response.

I just fixed the code such that the mismatch in the Date formats would not cause an error and the problem was fixed.

查看更多
再贱就再见
5楼-- · 2020-01-29 04:03

The currently accepted answer does work as expected but isn't the primary use case for the feature. Instead use the feature defined by ASP.NET. In my case, I denied everything but GET and POST:

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

With the code snippet above, MVC will correctly return a 404

查看更多
男人必须洒脱
6楼-- · 2020-01-29 04:03

For anyone having this problem with angularjs, MVC and {{imagepath}} type inserts in image src attributes, eg:

"A public action method '{{imagepath}}previous.png' was not found on controller"

The solution is to use ng-src instead of src.

Hope this helps someone :)

查看更多
ゆ 、 Hurt°
7楼-- · 2020-01-29 04:05

I have the similar issue with qq File Upload

When the post action is /Document/Save I get the exception A public action method 'Save' was not found on controller 'Project.Controllers.DocumentController'.

But if the post action is /Document/Save/, the post is correct and works!

God save the / ?

查看更多
登录 后发表回答