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

时间:2016-05-03 05:09:48

标签: c# asp.net-mvc mvvm asp.net-mvc-routing url-routing

在用户登录之前,路线为:

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

我应该如何将路线更改为用户名?

1 个答案:

答案 0 :(得分:1)

您需要添加路线以涵盖具有用户名的案例。

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

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

然后,只需在用户登录时执行302重定向即可。您可以在global 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());
    }
}

MVC将automatically reuse route values from the request when genrating URLs,因此您无需更改任何ActionLinks以包含username

使用MVC5,OWIN和ASP.NET Identity在GitHub上

Here is a working demo