登录后如何更改路由到用户名?

在用户登录之前,路由是:

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

用户登录后,路由为:

 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 

我想在用户登录后将路由更改为用户名。例如,用户名为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 

我的项目的控制器只有3个控制器: HomeControllerProjectControllerRequirementController

我的RouteConfig.cs仍处于默认状态

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

如何将路由更改为用户名?

您需要添加一个路由来覆盖具有用户名的案例。

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

但为了使其正常工作,您需要在URL中添加一个文字字符串,以将该段标识为用户名(即username-{username}\ ),或者您需要创建一个仅允许用户名的约束。在数据库中。 以下是后者的一个例子:

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

注意:我强烈建议在示例中使用缓存,因为路由约束在每个请求上运行,并且在每个请求上访问数据库都不好。 这样做的缺点是用户名在注册后最多需要15秒才能生效。 除了将记录添加到数据库之外,您还可以通过在注册新帐户时更新缓存(以线程安全的方式)来解决此问题,这将使其在路由约束中立即可用。

然后,只需在用户登录时执行302重定向即可。您可以在全局filter中执行此操作 。

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

用法

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

生成URL时 ,MVC将自动重用请求中的路由值 ,因此无需更改任何ActionLinks以包含username

这是一个使用MVC5,OWIN和ASP.NET Identity在GitHub上运行的演示 。