Here is one way to accomplish this:
Make these your routes in Global.asax.cs:
routes.MapRoute("UserProfileRoute", "Profile/{username}",
new { controller = "Profile", action = "Index" });
routes.MapRoute("DefaultProfileRoute", "Profile/{action}",
new { controller = "Profile", action = "SomeDefaultAction" });
This will match /Profile/someUsername as expected. But it will fail for all other actions. All action names are assumed to be usernames now. A quick fix to this is to add an IRouteConstraint to the first route:
routes.MapRoute("UserProfileRoute", "Profile/{username}",
new { controller = "Profile", action = "Index" },
new { username = new NotAnActionRouteConstraint() });
routes.MapRoute("DefaultProfileRoute", "Profile/{action}",
new { controller = "Profile", action = "SomeDefaultAction" });
public class NotAnActionRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string value = values[parameterName].ToString();
// it is likely parameterName is not cased correctly,
// something that would need to be
// addressed in a real implementation
return typeof(ProfileController).GetMethod(parameterName,
BindingFlags.Public | BindingFlags.Instance) == null;
}
}
However, this is a bit ugly. Hopefully someone knows of a better solution.
You also have problems when one of your users picks a name that is the same as an action :)