¿Cómo cambiar la ruta al nombre de usuario después de iniciar sesión?

Antes del inicio de sesión del usuario, la ruta es:

localhost:54274/Home localhost:54274/Home/About localhost:54274/Home/Contact localhost:54274/Home/Login localhost:54274/Home/Register 

Una vez que el usuario inicia sesión, la ruta es:

 1. localhost:54274/Project 2. localhost:54274/Project/Create 3. localhost:54274/Project/Edit/1 4. localhost:54274/Project/Delete/2 5. localhost:54274/Project/1/Requirement 6. localhost:54274/Project/1/Requirement/Create 7. localhost:54274/Project/1/Requirement/Edit/3 8. localhost:54274/Project/1/Requirement/Delete/4 

Quiero que la ruta cambie al nombre de usuario una vez que el usuario inicie sesión. Por ejemplo, el nombre de usuario es hendyharf.

 1. localhost:54274/hendyharf/Project 2. localhost:54274/hendyharf/Project/Create 3. localhost:54274/hendyharf/Project/Edit/1 4. localhost:54274/hendyharf/Project/Delete/2 5. localhost:54274/hendyharf/Project/1/Requirement 6. localhost:54274/hendyharf/Project/1/Requirement/Create 7. localhost:54274/hendyharf/Project/1/Requirement/Edit/3 8. localhost:54274/hendyharf/Project/1/Requirement/Delete/4 

El controlador para mi proyecto son solo 3 controladores: HomeController , ProjectController y RequirementController

Mi RouteConfig.cs todavía está en un valor predeterminado

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } 

¿Cómo se supone que debo hacer para que la ruta cambie a nombre de usuario?

Debe agregar una ruta para cubrir el caso que tiene un nombre de usuario.

 public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Username_Default", url: "{username}/{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, constraints: new { username = new OwinUsernameConstraint() } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } 

Pero para que funcione correctamente, deberá agregar una cadena literal a su URL para identificar el segmento como nombre de usuario (es decir, username-{username}\ ) o tendrá que hacer una restricción que solo permita los nombres de usuario que son en la base de datos. Aquí hay un ejemplo de esto último:

 using MvcUsernameInUrl.Models; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Web; using System.Web.Caching; using System.Web.Routing; namespace MvcUsernameInUrl { public class OwinUsernameConstraint : IRouteConstraint { private object synclock = new object(); public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) { if (parameterName == null) throw new ArgumentNullException("parameterName"); if (values == null) throw new ArgumentNullException("values"); object value; if (values.TryGetValue(parameterName, out value) && value != null) { string valueString = Convert.ToString(value, CultureInfo.InvariantCulture); return this.GetUsernameList(httpContext).Contains(valueString); } return false; } private IEnumerable GetUsernameList(HttpContextBase httpContext) { string key = "UsernameConstraint.GetUsernameList"; var usernames = httpContext.Cache[key]; if (usernames == null) { lock (synclock) { usernames = httpContext.Cache[key]; if (usernames == null) { // Retrieve the list of usernames from the database using (var db = ApplicationDbContext.Create()) { usernames = (from users in db.Users select users.UserName).ToList(); } httpContext.Cache.Insert( key: key, value: usernames, dependencies: null, absoluteExpiration: Cache.NoAbsoluteExpiration, slidingExpiration: TimeSpan.FromSeconds(15), priority: CacheItemPriority.NotRemovable, onRemoveCallback: null); } } } return (IEnumerable)usernames; } } } 

NOTA: Recomiendo utilizar el almacenamiento en caché para esto como en el ejemplo, ya que las restricciones de ruta se ejecutan en cada solicitud y no es bueno acceder a la base de datos en cada solicitud. La desventaja de esto es que el nombre de usuario tarda hasta 15 segundos en activarse después de que se haya registrado. Podría solucionar esto actualizando la caché (de forma segura para hilos) cuando se registra una cuenta nueva además de agregar el registro a la base de datos, lo que lo haría disponible inmediatamente en la restricción de ruta.

Entonces es simplemente una cuestión de hacer una redirección 302 cuando el usuario inicia sesión. Podría hacer eso en un filtro global .

 using System.Web; using System.Web.Mvc; namespace MvcUsernameInUrl { public class RedirectLoggedOnUserFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext filterContext) { var routeValues = filterContext.RequestContext.RouteData.Values; bool isLoggedIn = filterContext.HttpContext.User.Identity.IsAuthenticated; bool requestHasUserName = routeValues.ContainsKey("username"); if (isLoggedIn && !requestHasUserName) { var userName = filterContext.HttpContext.User.Identity.Name; // Add the user name as a route value routeValues.Add("username", userName); filterContext.Result = new RedirectToRouteResult(routeValues); } else if (!isLoggedIn && requestHasUserName) { // Remove the user name as a route value routeValues.Remove("username"); filterContext.Result = new RedirectToRouteResult(routeValues); } } public void OnActionExecuted(ActionExecutedContext filterContext) { // Do nothing } } } 

Uso

 public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new RedirectLoggedOnUserFilter()); filters.Add(new HandleErrorAttribute()); } } 

MVC reutilizará automáticamente los valores de ruta de la solicitud cuando genere URL , por lo que no es necesario cambiar ninguno de sus ActionLinks para incluir el username .

Aquí hay una demostración funcional en GitHub usando MVC5, OWIN y ASP.NET Identity.