asp.net-mvc-3dynamicasp.net-mvc-routingasp.net-mvc-3-areas

dynamic routing based on database entries


As often happens, I have a nice solution to one problem, which unfortunately causes another.

We have an app that provides services to members of various organizations, parts of a larger parent. The organizations require custom URLs. So, members of org A access the URL https://server/vdir/OrgA, and members of org B access the URL https://server/vdir/OrgB.

Both of these would map to the exact same area, controller, and action in the app, although they might look different to the end user due to some custom view content.

Because the list of organizations using this app is dynamic, and because not all organizations will start using it at the same time, I started out setting up the route mapping programmatically. In the target Area, I override the RegisterArea method, pull the active organizations from the database, and execute a custom context.MapRoute call for each.

Doing it this way avoids another problem, which was that the the URLs that have the organization sitepath ("OrgA") in them look exactly like those that have a meaningful area name in them, which actually does map to an area. Treating the organization sitepaths as virtual area names and explicitly mapping them to the target Area avoided certain misdirections.

And this works, nicely. But: it's all executed at Application_Start. If we add an organization, it doesn't become active until we restart the app, which would be highly disruptive to anybody who was using it at that time.

So my questions are two:

  1. Is there a better approach than mine for doing this? I did research the problem, but the relevant keywords are so ubiquitous that it was a bit of a needle-and-haystack situation.
  2. If there isn't one, is there a way to refresh the route mappings without restarting the app?

Solution

  • Phil Haack wrote an article dealing with exactly this problem.

    The really, really short version of which is that you place your route registrations in a file other than Global.asax and cache the contents of that file. The cache has the file as a dependency and calls a method when the cache is invalidated (read: file is altered) that re-registers your routes.