Ingenious Solution or Horrible Hack?

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:

address bar

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!