Come modificare il percorso verso il nome utente dopo aver effettuato l’accesso?

Prima del login utente, il percorso è:

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

Una volta effettuato l’accesso, il percorso è:

 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 

Voglio che il percorso sia cambiato con il nome utente una volta dopo che l’utente ha effettuato l’accesso. Ad esempio, il nome utente è 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 

Il controller per il mio progetto sono solo 3 controller: HomeController , ProjectController e RequirementController

Il mio RouteConfig.cs è ancora in un predefinito

 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 } ); } } 

Come dovrei fare per fare in modo che il percorso cambi in username?

È necessario aggiungere un percorso per coprire il caso che ha un nome utente.

 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 } ); } 

Ma per farlo funzionare correttamente, dovrai aggiungere una stringa letterale al tuo URL per identificare il segmento come nome utente (es. username-{username}\ ) o dovrai creare un vincolo che permetta solo i nomi utente che sono nel database. Ecco un esempio di quest’ultimo:

 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: raccomando vivamente di utilizzare la memorizzazione nella cache per questo come nell’esempio, poiché i vincoli di instradamento si eseguono su ogni richiesta e non è opportuno colpire il database ad ogni richiesta. Lo svantaggio di questo è che occorrono fino a 15 secondi affinché lo username diventi attivo dopo essere stato registrato. È ansible aggirare questo problema aggiornando la cache (in modalità thread-safe) quando viene registrato un nuovo account oltre ad aggiungere il record al database, che lo renderebbe immediatamente disponibile nel vincolo del percorso.

Quindi si tratta semplicemente di eseguire un reindirizzamento 302 quando l’utente esegue il login. Potresti potenzialmente farlo in un filtro globale .

 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 automaticamente riutilizzerà i valori del percorso dalla richiesta durante la generazione degli URL , quindi non è necessario modificare alcuno dei ActionLinks per includere il username .

Ecco una demo funzionante su GitHub che utilizza MVC5, OWIN e ASP.NET Identity.