Today I found myself writing something that feels…hacky. Very hacky, actually. But it does work, and that’s more than can be said for any of the “clean” solutions I could come up with.
Routing Problems
This all came about because I am working on a project that relies on a couple of specific routes being present in the MVC routing tables. This project is intended to be added to other MVC websites as a bolt-on dependency so it can’t rely on any other routing, and I wanted to be able to access arbitrary controllers using {controller}/{action}
.
As this is a bolt-on, I don’t want to affect any of the existing routes so I thought I would add a prefix to my routes so that existing routes would work as normal.
RouteTable.Routes.MapRoute(
name: "DefaultProxy",
url: "proxy/{controller}/{action}"
);
This way, you could use either http://server/Home/Index
or http://server/proxy/Home/Index
and get the same result…provided that the proxy/...
route is registered before any of the existing route definitions.
Problem solved, right?
More Specific Routing Problems
At first the approach above seemed to be working, but then I noticed the URLs generated by Url.Action
and Html.ActionLink
…
<a href="http://server/proxy/Home/Index">Home</a>
Even worse, the proxy
segment (obviously) shows up in the browser toolbar:
That doesn’t really qualify as “not affecting existing routes”…
Sadly, MVC is actually behaving exactly as it should: using the first and most specific route it can find to generate the URL. The fact that I don’t want it to use that route is irrelevant.
Surely There’s a Better Way?
After making this discovery and bashing my head against various convoluted solutions I finally came up with something that works. But it feels so very wrong…
RouteTable.Routes.MapRoute(
name: "DefaultProxy",
url: "{proxy}/{controller}/{action}",
defaults: new {},
constraints: new { proxy = "^proxy$" }
);
So what is this oddity? First, I’m specifying a new URL segment - “proxy” - that prefaces the familiar {controller}/{action}
. Then I’m setting up a constraint on that segment that will only allow the value “proxy” to appear using a regular expression.
This has the same overall effect that my original solution had, with the added bonus that (presumably because of the unrecognised URL segment) the URL-generation mechanisms ignore the new route.
This can’t be the best way to achieve this - there has to be a better solution that I just haven’t found yet.
Please - someone enlighten me in the comments!