2

I want to setup routing as follows:

/Profile/Edit -> routes to Edit action

/Profile/Add -> routes to Add action

/Profile/username -> routes to Index action with parameter username, because action username doesn't exist.

So I want the second parameter to be parsed as the controller action, except when no controller with that name exists; then it should route to the default index page and use the url part as id.

Possible?

Jasper
  • 1,697
  • 2
  • 23
  • 48

4 Answers4

2

You can use regex in your route constraints like so

routes.MapRoute(
    "UserProfileRoute",
    "Profile/{username}",
    new { controller = "Profile", action = "Index" },
    new { username = "(?i)(?!edit$|add$)(.*)" });

this will match urls like /profile/addendum /profile/someusername and will ignore /profile/edit and /profile/add

Buildstarted
  • 26,529
  • 10
  • 84
  • 95
0

Anything is possible. However, why not just make /profile your root?

If that isn't possible, you may need to hardcode your action's routes.

Chance
  • 11,043
  • 8
  • 61
  • 84
  • Hmmm yeah, kind of stupid but I didn't really think of that :) I just might, that would make things a lot easier. – Jasper Apr 07 '11 at 20:34
0

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 :)

Matt Greer
  • 60,826
  • 17
  • 123
  • 123
  • Yeah, I though about that last comment and I'm going to implement some reflection logic to prevent users from choosing a username which equals an action. – Jasper Apr 07 '11 at 20:32
  • By the way, Facebook does the same these times, I can open my Facebook profile via facebook.com/username. Not so dangarous for my name, but others might be trickier. I wonder what they'll do if they ever want to create a folder or whatever at an address a user has already claimed. – Jasper Apr 07 '11 at 20:34
0

Matt's solution gets you 90% of the way. However, instead of using a route constraint to exclude action names, use a route constraint to include only valid usernames, like so:

public class MustMatchUserName : IRouteConstraint 
{ 

    private Users _db = new UserEntities(); 

    public MustMatchUserName() 
    { } 

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
        return _db.Users.FirstOrDefault(x => x.UserName.ToLower() == values[parameterName].ToString().ToLower()) != null; 
    } 
} 

Then, as Matt points out, in the user creation process, you must enforce a rule that your ActionNames are not valid for user names.

counsellorben

counsellorben
  • 10,924
  • 3
  • 40
  • 38