Routing in ASP.NET MVC, showing username in URL

2019-01-02 16:24发布

问题:

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.

回答1:

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.



回答2:

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



标签: