So, I'm switching an area over from using AreaRegistration to using Attribute Routing. I'm running into an issue which appears to be caused by the order in which routes are loaded into the routing table. I'd solved the issue in AreaRegistration by loading in the problematic route last, so that only if all other routes didn't match would that route be matched. With Attribute Routing, this doesn't appear to be possible. I have the Order parameter when creating a route, but this doesn't affect how things hit the routing table except very narrowly.
Here's the route I have in the AreaRegistration file:
context.MapRoute(
name: "ActionItems_home",
url: "ActionItems/{group}/{statuses}/{overdueOnly}",
defaults: new { controller = "Home", action = "Index", group = "All", statuses = "New,Open", overdueOnly = false },
namespaces: new string[] { "IssueTracker.Areas.ActionItems.Controllers" }
);
Now, when I try to switch this to Attribute Routing the only thing that comes close to working is:
[Route("", Order = 4)]
[Route("{group:regex(^(?!Item|DecisionLogs))?}", Order = 3)]
[Route("{group:regex(^(?!Item|DecisionLogs))}/{statuses=New,Open?}", Order = 2)]
[Route("{group:regex(^(?!Item|DecisionLogs))}/{statuses=New,Open}/{overdueOnly:bool=false?}", Order = 1)]
Note that I have to put in the regex because otherwise the Item controller doesn't get called - instead, I end up with the string 'Item' being passed in as the group
parameter. But the regex doesn't particularly help with how the URL's end up being rendered.
I would like for the optional parameters to be suppressed in the URL unless they are non-default. I've tried specifying the parameters as optional, with default values, and both optional and with default values. None of them seems to really do the trick.
The current solution at least presents a URL without a querystring, but they include the optional parameters and make things ugly. For now, I've simply left the egregious routes to be defined in AreaRegistration
files & not decorated them with the [Route()]
pieces.
ASP.NET MVC is open source and it is designed in the way that every layer can be replaced by your own. You can download the source code, find problematic part and find out, how it works. Finally replace by own code if needed.
If you download this source code, you will find a System.Web.Mvc.RouteAttribute class with CreateRoute method. I am not sure, but it could be somehow connected with your problem.
Finding references on this interface, you can find DefaultDirectRouteProvider class.
Another approach is that you can try to find work "Order" in the project. If you omit test, there are not so many occurrences and some are in routeSomething classes.
You can uncheck "Just my code" in Visual Studio and debug the ASP.NET MVC code.
Your real problem is how to configure your original route with Attribute Routing. The order problem is just a side effect of configuring several routes instead of one. To achieve your desired configuration, you can create a custom RouteAttribute and do whatever you need inside.
You can see a sample here And the original RouteFactoryAttribute source for reference
I'm afraid I don't have time right now to provide the actual implementation myself, but I hope this will lead you to the right direction.
UPDATE I've given this a try and the following very simple solution works as expected. My attribute implementation is specific to the sample you provided with group, statuses and overdueOnly parameters, but you should be able to create a more generic solution that covers all your cases (you'll also need to add the namespace)
Then in the Controller:
And it works exactly the same as your initial routing configuration, but using an attribute.