skip to Main Content

For SEO and SEM reasons I have been asked to implement the following URL in our MVC ASP.NET application:

/colour/{colour1}/[{colour2}]/[{colour3}]/[{colour4}]/fill

In all cases the URL needs to start with /colour and end with /fill. There will be at leastcolour1 and optionally three additional colours ({colour2..4}) so all of the following are valid:

/colour/red/fill
/colour/red/blue/fill
/colour/red/blue/green/fill
/colour/red/blue/green/yellow/fill
/colour/yellow/blue/green/red/fill

The following does NOT work:

aRoutes.MapRoute("Blah",  "colour/{colour1}/{colour2}/{colour3}/{colour4}/fills", new
  {
      controller = "MyController",
      action = "MyAction",
      colour2 = UrlParameter.Optional,
      colour3 = UrlParameter.Optional,
      colour4 = UrlParameter.Optional

});

[HttpGet]
public virtual ActionResult MyAction(string colour1, string colour2 = "", string colour3 = "", string colour4 = "")
{
    return null;
}

and neither does:

aRoutes.MapRoute("Blah",  "colour/{*colour}/fills", new
  {
      controller = "MyController",
      action = "MyAction2",
});

as the trailing /fills causes an issue.

So my questions are:

  • Can this all be done with a single route definition in route config? What is the minimal amount of route configuration I need to have to achieve this?
  • Can I have a single action method in my controller to handle all of these? Or do I need to declare a separate method based on each of the number of parameters?

2

Answers


  1. Chosen as BEST ANSWER

    The solution I was able to implement requires additional routes to be declared that are all directed to the same method. Be sure to declare them in descending order in terms of the number of parameters (so all 4 first and the single one last):

    aRoutes.MapRoute("Blah",  "colour/{colour1}/{colour2}/{colour3}/{colour4}/fills", new
      {
          controller = "MyController",
          action = "MyAction",
    });
    
    aRoutes.MapRoute("Blah",  "colour/{colour1}/{colour2}/{colour3}/fills", new
      {
          controller = "MyController",
          action = "MyAction",
    });
    
    aRoutes.MapRoute("Blah",  "colour/{colour1}/{colour2}/fills", new
      {
          controller = "MyController",
          action = "MyAction",
    });
    
    aRoutes.MapRoute("Blah",  "colour/{colour1}/fills", new
      {
          controller = "MyController",
          action = "MyAction",
    });
    

    and the controller method looks like:

    public virtual ActionResult MyAction(string colour1, string colour2 = "", string colour3 = "", string colour4 = "")
    {
                return null;
    }
    

    Ultimately not a great solution because if we wanted to add colour5 then we would need to modify the route table and the action method. But that is how the cookie crumbles in this case.


  2. Catch-All needs to be the last parameter in the list.

    Visual Studio will throw the following error if you have the /fill after the catch-all:

    An exception of type 'System.ArgumentException' occurred in
    Microsoft.AspNet.Routing.dll but was not handled in user code
    
    Additional information: A catch-all parameter can only appear as the
    last segment of the route template.
    

    Easiest solution would be to move the /fill to before the catch-all if it is static. If /fill is the action for the colours, perhaps use /colourAction/{colourAction} to pull the action to your function in the Controller?

    https://msdn.microsoft.com/en-us/library/cc668201.aspx#Anchor_5

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search