Im trying to make a route so I can show the username In the URL like this:
http://localhost1234/john
Here Is my routeconfig:
routes.MapRoute(
name: "users", // Route name
url: "{username}", // URL with parameters
defaults: new { controller = "Home", action = "Index", username = "" } // Parameter defaults
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Here Is my HomeController:
public ActionResult Index(string username = "Test")
{
return View();
}
First of all, the URL Is not changed. When I set username = "Test"
inside my route-config, the URL Is not changed.
Second, I can't navigate to my other controllers. If I change the URL to http://localhost123/Welcome, nothing happens. It should redirect me to a new page.
What am I doing wrong here?
If I change the order of the routes, I can navigate to other pages, but the username Is not displayed In the URL.
I have googled and all of the answers on this subject says that I should use a route like the one above.
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.
You need to categorize the url for different section of your website so that url pattern matching mechanism go smooth. For example in your case put a category 'profile' or anything other. Now your request url look like http://localhost1234/profile/john and route will be
routes.MapRoute(
name: "users", // Route name
url: "Profile/{username}", // URL with parameters
defaults: new { controller = "Home", action = "Index" } // Parameter defaults
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
For more information follow link Routing in MVC