Search code examples
c#asp.net-web-api-routing

AreaRegistration MapRoutes for Help Docs


I have an api using web api 2 and I am trying to create help docs within an Area so that an incoming request like ...api/people.help will route to the people controller and people view and serve up the html. I am struggling with the route mapping for the area after refactoring the code. Previously, I had routes like this:

public override void RegisterArea(AreaRegistrationContext context) {
        context.MapRoute(
            name: "Help",
            url: "{action}.help",
            defaults: new { area = "help", controller = "default" }
        );

All the methods were in the default controller and this worked. Now, I need a separate controller for each resource (eg people, schedules etc) but can't get the routes to work. I would appreciate help, I am very new to this. How do I get each help request to map to the controller with the same action name?


Solution

  • Wouldn't it simply be something similar to:

    public override RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            name: "Help",
            url: "api/{controller}.help",
            defaults: new { area = "help" }
        );
    }
    

    What you have in your post is a default for the name of the controller, in this case, it's name will always be default. Instead, what you're looking for is that when someone routes to your controller name suffixed with .help, it'll route to a path akin to api/help/people, which will end up calling a default action (in MVC) such as index.cshtml or the default action for a GET request to the controller (for WebAPI).

    So, you want to set the default area to help as shown above. You also want to set the default action that should execute on the provided controller.

    Update: To answer question in comment

    For MVC, you can have an action method whose name matches what the controller name will be in the URL:

    public class PeopleController : Controller
    {
        [HttpGet] // Not strictly necessary, but just want to stress this is GET
        public ActionResult People()
        {
            // Do stuff in your action method
        }
    }
    

    The only problem is, your action method will be different for each controller, and so unknowable for route registration purposes. Therefore, you should maybe have just a default Help action:

    public class PeopleController : Controller
    {
        [HttpGet]
        public ActionResult Help()
        {
            // Do stuff
        }
    }
    

    Then you can have the following route:

    public override RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            name: "Help",
            url: "api/{controller}.help",
            defaults: new { area = "help", action = "Help" }
    }
    

    You could take this one step further and provide a Help method in a custom base controller class:

    public class MyBaseController : Controller
    {
        public virtual ActionResult Help()
        {
            // Do default behavior stuff, if appropriate
        }
    
        // If you don't have any "default" behavior, you could make the method abstract:
        // public abstract ActionResult Help();
    }
    
    public class PeopleController : MyBaseController
    {
         public override ActionResult Help()
         {
             // Do stuff.
         }
    }
    

    Update to further answer OP's question in comments

    So, now the OP is saying: "but I want my view to have the same name as my controller." Ok, that should be no problem:

    public class PeopleController : MyBaseController // if you're using a base class
    {
        public override ActionResult Help()
        {
            return ViewResult("People");
        }
    }
    

    So, you can have a view with any name you want. But if the view's name differs from the name of the action method, then when returning (say) a ViewResult, you'll need to specify the name of the view to return.

    Having said all that, the default folder structure for views in ASP.Net is Areas/{AreaName}/Views/{Controller}/{viewname}.{cs|vb}html. And here, {viewname} is by default assumed to be the action method name, but doesn't have to be when, as above, explicitly telling MVC which view to return (in the example above, People.cshtml).

    HTH.