3

I am building a MVC application in asp.NET for a web portal. I have prepared a series of controllers, and mapped all the paths that don't macth to this to a Page controller, which will render the appropriate page.

My default route works like this:

routes.MapRoute(
  "Default",
  "{level1}/{level2}/{level3}",
  new { controller = "Page", action = "Index", level1 = "home", level2 = "", level3 = "" }
      );

But this has fixed width, it will accept only up to 3 levels. Moreover, I'd like to manage actions appended to the path, like "edit" and "delete". Is this possible?

company/about/who_we_are/staff -> Controller: Page, Action: Index, Parms: company/about/who_we_are/staff
company/about/who_we_are/staff/edit  -> Controller: Page, Action: Edit, Parms: company/about/who_we_are/staff
company/edit  -> Controller: Page, Action: Edit, Parms: company

Or is there a better way to model this? All the paths to the pages are in the database, so they change dynamically.

3 Answers 3

5

You can use a wild-card route:

"{*data}"

take a look a this SO: ASP.net MVC custom route handler/constraint


simple possible solution:

(not tested but...)

The route:

routes.Add(new Route
                           (
                           "{*data}",
                           new RouteValueDictionary(new {controller = "Page", action = "Index", data = ""}),
                           new PageRouteHandler()
                           )
                );

The handler would look like:

public class PageRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new PageHttpHandler(requestContext);
    }
}

class PageHttpHandler : MvcHandler
{
    public PageHttpHandler(RequestContext requestContext)
        : base(requestContext)
    {
    }

    protected override void ProcessRequest(HttpContextBase httpContext)
    {
        IController controller = new PageController();

        ((Controller)controller).ActionInvoker = new PageActionInvoker();

        controller.Execute(RequestContext);
    }
}

class PageActionInvoker : ControllerActionInvoker
{
    protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
    {
        string data = controllerContext.RouteData.GetRequiredString("data");
        string[] tokens = data.Split('/');


        int lenght = tokens.Length;

        if (lenght == 0)                   
            return new NotFoundResult();

        if (tokens[tokens.Length - 1] == "edit")
        {
            parameters["action"] = "edit";
            lenght--;
        }

        for (int i = 0; i < length; i++)
            parameters["level" + (i + 1).ToString()] = tokens[i];

        return base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Seems like it won't allow a simple way to append the "edit" action to my paths :( but that's a problem of the MVC engine itself. Maybe I'll just prepend the action instead...
2

Greedy segment anywhere in the URL, possible? It is yes!

I've written GreedyRoute class that supports greedy (catch all) segment anywhere in the URL. It's been a while since you needed it, but it may be useful to others in the future.

It supports any of the following patterns:

  • {segment}/{segment}/{*greedy} - this is already supported with default Route class
  • {segment}/{*greedy}/{segment} - greedy in the middle
  • {*greedy}/{segment}/{segment} - greedy at the beginning

You can read all the details on my blog post and get the code as well.

Comments

1

As far as i know, you can use regular expressions to express what the routes can look like (see the bottom code section here). With this, it should be possible to make a regex-string that can take an undetermined number of sub-sections ("forward-slashe and text/number-groups"). You can then parse the URL string in your application and retrieve the appropriate section.

I am, however, not capable of writing this regex-string by myself without spending hours, so someone else can probably help you there. :-)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.