Routing in ASP.NET MVC, showing username in URL
On its own, your routing will not work because if the url was .../Product
meaning that you wanted to navigate to the Index()
method of ProductController
, it would match your first route (and assume "Product" is the username
. You need to add a route constraint to your roue definitions that returns true
if the username
is valid and false
if not (in which case it will try the following routes to find a match).
Assuming you have a UserController
with the following methods
// match http://..../Bryan
public ActionResult Index(string username)
{
// displays the home page for a user
}
// match http://..../Bryan/Photos
public ActionResult Photos(string username)
{
// displays a users photos
}
Then you route definitions need to be
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "User",
url: "{username}",
defaults: new { controller = "User", action = "Index" },
constraints: new { username = new UserNameConstraint() }
);
routes.MapRoute(
name: "UserPhotos",
url: "{username}/Photos",
defaults: new { controller = "User", action = "Photos" },
constraints: new { username = new UserNameConstraint() }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Test", action = "Index", id = UrlParameter.Optional }
);
}
public class UserNameConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
List<string> users = new List<string>() { "Bryan", "Stephen" };
// Get the username from the url
var username = values["username"].ToString().ToLower();
// Check for a match (assumes case insensitive)
return users.Any(x => x.ToLower() == username);
}
}
}
If the url is .../Bryan
, it will match the User
route and you will execute the Index()
method in UserController
(and the value of username
will be "Bryan"
)
If the url is .../Stephen/Photos
, it will match the UserPhotos
route and you will execute the Photos()
method in UserController
(and the value of username
will be "Stephen"
)
If the url is .../Product/Details/4
, then the route constraint will return false for the first 2 route definitions and you will execute the Details()
method of ProductController
If the url is .../Peter
or .../Peter/Photos
and there is no user with username = "Peter"
then it will return 404 Not Found
Note that the the sample code above hard codes the users, but in reality you will call a service that returns a collection containing the valid user names. To avoid hitting the database each request, you should consider using MemoryCache
to cache the collection. The code would first check if it exists, and if not populate it, then check if the collection contains the username
. You would also need to ensure that the cache was invalidated if a new user was added.