c# asp.net-mvc mvvm asp.net-mvc-routing url-routing

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



asp.net-mvc mvvm (1)

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 eso funcione correctamente, deberá agregar una cadena literal a su URL para identificar el segmento como nombre de usuario (es decir, username-{username}/ ) o deberá establecer 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<string> 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<string>)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 registrarse. Potencialmente, podría evitar esto actualizando el caché (de manera segura para subprocesos) cuando se registra una nueva cuenta además de agregar el registro a la base de datos, lo que lo haría disponible de inmediato en la restricción de ruta.

Entonces es simplemente una cuestión de hacer una redirección 302 cuando el usuario inicia sesión. Potencialmente podría hacerlo 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 al generar 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.

Antes de iniciar sesión, 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 inició 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 haya iniciado 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 debo hacer para que la ruta cambie a nombre de usuario?