Question

I need to have a custom route, like the default one, but this one should accept numeric values as strings. Like 0015. If I leave the parameter type as int, the value passed to the controller method get truncated to 15. And I need 0015. So what I did, I created the following:

        routes.MapRoute(
            name: "AccRef",
            url: "{controller}/{action}/{acc_ref}",
            defaults: new { controller = "Company", action = "Index", acc_ref = "" },
            constraints: new { acc_ref = @"^\d{1,4}$" }
        );
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id =       UrlParameter.Optional }
        );

And the problem is, as I understand, that when I now pass in an integer as "id"

@Url.Action("Method", "Controller", new { id = item.ref})

from the view, the routing still applies the first route to it and the call fails.

How would you go about solving this problem with routing? Is it possible to have two same routing configurations where one accepts int and another string?

No correct solution

OTHER TIPS

Your AccRef is too greedy.

If you look at the url generated from the Url helper it is:

Controller/Method/id

This matches your first AccRef route as well as the default route.

You have to be more specific with your routes. Also the order you define your routes are important. So you normally want to define greedier routes last.

Phil Haack has a route debugger on nuget (blog post here) which can help you identify route issues.

If you reverse the order like so:

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            name: "AccRef",
            url: "{controller}/{action}/{acc_ref}",
            defaults: new { controller = "Company", action = "Index", acc_ref = "" },
            constraints: new { acc_ref = @"^\d{1,4}$" }
        );

Your current scenario will work with above change but the url "/Home/Index/5" or "/Company/Index/0015" still matches both the routes. This is because the routes are generic (as correctly pointed out by Bigfellahull).

In your case since both the parameter is of type int, both the routes are matched.

Option 1:

You can add a extra string say "Acc" in the route url to make it more specific.

    routes.MapRoute(
        name: "AccRef",
        url: "{controller}/{action}/{acc}/{acc_ref}",
        defaults: new { controller = "Company", action = "Index", acc_ref = "" },
        constraints: new { acc_ref = @"^\d{1,4}$" }
    );

In this case the url will change to ".Company/Index/acc/0015".

Option 2:

If you can change the parameter type in action method like so:

    public class HomeController : Controller
    {
        public ActionResult Index(string id)
        {
        }
    }

The url will match only one route.

Option 1 and 2 are for example only to explain how you can make routes more specific.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top