views:

133

answers:

3

Here is my dilemma. I have a collection of entities that I want to use to define as the starting point for a set of routes. For example, I want to give all of the users in my site their own "subsites" of the form mydomain.com/username, and then hang all of the UserController actions off of that.

Here is a rough example of what I am doing:

I have a "UserController", with action methods like "Index", "Profile" and "Bio".

public ActionResult Profile( int UserID )
{
    User u = User.SingleOrDefault(u => u.UserID == UserID);
    return View(u);
}

In RegisterRoutes() method, I do this:

foreach (User user in User.Find(u => u.Active == true))
{
    routes.MapRoute(
         "",
         user.UserName + "/{action}",
         new { controller="User", action="Index", UserID=user.UserID }
     );
}

This works, and it works exactly as I want it to:

domain.com/[username]/Profile
domain.com/[username]/Bio

are now valid, working routes, and they can take in the UserID as the method parameter in the controller because each user gets their own route. Also, the default routes still work. Yay.

My question is, is this insane? I am creating an entry in the route table for every user in the system. How many routes is too many? Will this kill my server if there are over 10 users? 50? 1000?

And if this is insane, how else might I accomplish this goal?

Thanks in advance. I look forward to some input from the hive-mind.

+2  A: 

There are a lot of concerns with your approach in my mind. What if someone has a username that matches one of your other controller names? You would never be able to call into that controller. Additionally, the routing system (as I understand it), tests all routes sequentially, meaning that thousands of routes would start to slow down routing lookups, including generation of Urls (like Url.Content() or Route.GetVirtualPath()).

Can't you just do

/{username}/{action}

and pass in the username as part of your parameters? What's the point of generating routes for each user if every route is going to the same controller and action methods?

If you need that to only match the User controller, consider implementing a custom route constraint. The link provides an example of creating a list of values that the controller parameter must match, but you could easily do it for your Action method names. Alternately, your custom constraint code could look up a username in the database to see if it matched.

womp
That would match the default route too, correct? I guess I didn't make that part clear.
obliojoe
Just constrain your route. I added a link to a great post that should help.
womp
Thanks for the tip. I am going to look into route constraints today and see if they work for me. I'll report my findings back here. Also - I am not worried about the username/controller conflict you bring up (my project is different than the example I used in my question) but I was mostly looking for some concrete information about how the routing system handles large numbers of entries in the route table.Thnaks.
obliojoe
Thank you so much womp. Route constraints are mighty powerful and I was totally unaware of them. This will in fact allow me to solve this problem without the big list of dynamically generated URLs. You rock.
obliojoe
A: 

I'm not sure what your limitations are, but the Routing system is built to allow you to do this with one route rather than one for each user.

A very simple example based on your own would be:

routes.MapRoute(
         "",
         "{UserName}/{action}",
         new { controller="User", action="Index", UserID=user.UserID }
     );
SirDemon
That would conflict with the default route, yes? I suppose I should have been more clear about that in my question. I did it this way to have the subsites, but also keep a default {controller}/{action}/{id} route around
obliojoe
A: 

An alternative approach would be looking at using constraints in your MapRoute(). Keep the same values of routes.MapRoute("", "{UserName}/{action}", new { controller="user", action="Index", UserID=user.UserID});, but add the contraint that UserName needs to be in a specific format or in a list.

I don't know if it will be more performant, but it is an alternative to registering that many (nearly identical) routes. And because of the constraint it won't conflict with the default route, which you should have as the last MapRoute() call anyways, so these will be evaluated first.

Agent_9191