简体   繁体   中英

Url.Action doesnt work with non standard MVC Route

I am having trouble making @Url.Action work with Area's that have a non standard route structure.

For instance if I register this route in my Dashboard area:

        context.MapRoute(
            "Dashboard_default",
            "Dashboard/{controller}/{action}/{id}",
            new { controller = "View", action = "Display", id = UrlParameter.Optional }
        );

and then in my layout view I call:

        @Url.Action("Select", "View", new { area = "Dashboard" })

I get a proper url: /Dashboard/View/Select

However, if I change the route to include an optional secondary id like this:

        context.MapRoute(
            "Dashboard_default",
            "Dashboard/{controller}/{action}/{id}/{secondaryid}",
            new { controller = "View", action = "Display", id = UrlParameter.Optional, secondaryid = UrlParameter.Optional }
        );

Then the same call to @Url.Action(...) doesn't return any url. If I specify those optional parameters with real values like so:

        @Url.Action("Select", "View", new { area = "Dashboard", id = 1, secondaryid = 2 })

I do get a god return value of: /Dashboard/View/Select/1/2

The problem is that for some of my actions in this area don't need the id or secondary id and I want the url to be generated without them. If i set them to (int?)null it still doesn't work.

Am I doing something wrong? Shouldn't Url.Action(...) return the URL without the id and secondaryid tokens if I dont specify them in the routeValues parameter?

Having multiple optional parameters does funky things to your routes. Basically, the route engine cannot (has trouble) matching one or no optional parameters where there is a group of them. For more information, check out this blog post on the same issue .

Since you don't always need id or secondary id, just make a couple of routes to handle those cases.

context.MapRoute(
            "Dashboard_IdAndSecondaryId",
            "Dashboard/{controller}/{action}/{id}/{secondaryid}",
            new { controller = "View", action = "Display"}
        );
context.MapRoute(
            "Dashboard_default_WithSecondaryId",
            "Dashboard/{controller}/{action}/{secondaryid}",
            new { controller = "View", action = "Display"}
        );

context.MapRoute(
            "Dashboard_default",
            "Dashboard/{controller}/{action}/{id}/",
            new { controller = "View", action = "Display", id = UrlParameter.Optional}
        );

Now, when you send just an Id, just a secondaryId or both, you will have routes that will match. We can remove the optional parameter declarations in the first two routes, because in order to match that route, you would have to send the required parameters. Without sending the required parameters, you would want only the last route to match.

The last route is your default route when only Id or none is sent in the action link. I believe that this order works as well, keeping in mind you want your routes to go from most specific to least specific given that they are processed in order.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM