Search code examples
c#asp.net-coreasp.net-core-mvcasp.net-core-routing

How to indicate a method in a controller is not an action method?


I have a situation where I want to use a page specific controller. In that controller I have an action method and a bunch of helper methods. In real life the helper methods are inherited from a BaseController but to make things simple lets assume I just have one helper method directly in my controller class like so:

[Route("/dev/test")]
public class TestController : Controller {

    public IActionResult Get() {
        return UnprocessedEntityResult();
    }

    //Some helper method that I don't want to be considered an 
    //action method by the routing engine.
    public IActionResult UnprocessedEntityResult() {
        return StatusCode(StatusCodes.Status422UnprocessableEntity);
    }
}

I specifically want to use attribute based routing and I want that attribute based route specified at the class level.

Given the situation as coded above, a AmbiguousActionException will be thrown when the /dev/test route is accessed and it will indicate that

AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:

App.Dev.TestController.Get
App.Dev.TestController.UnprocessedEntityResult

How can I tell the routing engine that UnprocessedEntityResult() is not an action method? I assume that there must be some attribute that I can apply to the method but I have have not been able to locate it.


Solution

  • Look up the [NonAction] attribute.

    Indicates that a controller method is not an action method.

    [Route("/dev/test")]
    public class TestController : Controller {
        [HttpGet]
        public IActionResult Get() {
            return UnprocessedEntityResult();
        }
    
        [NonAction]
        public IActionResult UnprocessedEntityResult() {
            return StatusCode(StatusCodes.Status422UnprocessableEntity);
        }
    }
    

    or you can also make the action protected.

    [Route("/dev/test")]
    public class TestController : Controller {
        [HttpGet]
        public IActionResult Get() {
            return UnprocessedEntityResult();
        }
    
        protected IActionResult UnprocessedEntityResult() {
            return StatusCode(StatusCodes.Status422UnprocessableEntity);
        }
    }
    

    It will be visible to derived types but won't confuse the route table.