【问题标题】:Routing based on subdomain to areas while keeping same URL parameters基于子域路由到区域,同时保持相同的 URL 参数
【发布时间】:2018-03-21 09:20:38
【问题描述】:

我正在尝试基于子域路由到区域,而 URL 不包含 Area 参数。

例如,我希望能够走以下路线

example1.domain.com/login

example1.domain.com/landingpage

example2.domain.com/login

example2.domain.com/landingpage

我想让每个子域路由到不同的区域。我试过关注这个帖子Is it possible to make an ASP.NET MVC route based on a subdomain?,它把我带到了http://benjii.me/2015/02/subdomain-routing-in-asp-net-mvc/。但我似乎无法弄清楚如何在 URL 中没有 Area 参数。

如何获得我正在寻找的正确 URL 架构? {subdomain}.domain.com/{action}/{id}

【问题讨论】:

    标签: asp.net-mvc model-view-controller url-routing asp.net-mvc-routing


    【解决方案1】:

    要在区域中使用路由,除了进行其他子域路由之外,还需要将DataTokens["area"] 参数设置为正确的区域。这是一个例子:

    子域路由

    public class SubdomainRoute : Route
    {
        // Passing a null subdomain means the route will match any subdomain
        public SubdomainRoute(string subdomain, string url, IRouteHandler routeHandler) 
            : base(url, routeHandler)
        {
            this.Subdomain = subdomain;
        }
    
        public string Subdomain { get; private set; }
    
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            // A subdomain specified as a query parameter takes precedence over the hostname.
            string subdomain = httpContext.Request.Params["subdomain"]; 
            if (subdomain == null)
            {
                string host = httpContext.Request.Headers["Host"];
                int index = host.IndexOf('.');
                if (index >= 0)
                    subdomain = host.Substring(0, index);
            }
            // Check if the subdomain matches this route
            if (this.Subdomain != null && !this.Subdomain.Equals(subdomain, StringComparison.OrdinalIgnoreCase))
                return null;
    
            var routeData = base.GetRouteData(httpContext);
            if (routeData == null) return null; // The route doesn't match - exit early
    
            // Store the subdomain as a datatoken in case it is needed elsewhere in the app
            routeData.DataTokens["subdomain"] = subdomain;
    
            return routeData;
        }
    
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            // Read the current query string and cascade it to the current URL only if it exists
            object subdomainParam = requestContext.HttpContext.Request.Params["subdomain"];
            if (subdomainParam != null)
                values["subdomain"] = subdomainParam;
            return base.GetVirtualPath(requestContext, values);
        }
    }
    

    RouteCollectionExtensions

    这些扩展方法允许您在应用程序的非区域部分注册路由以使用子域。

    public static class RouteCollectionExtensions
    {
        public static SubdomainRoute MapSubdomainRoute(
            this RouteCollection routes, 
            string subdomain, 
            string url, 
            object defaults = null, 
            object constraints = null, 
            string[] namespaces = null)
        {
            return MapSubdomainRoute(routes, null, subdomain, url, defaults, constraints, namespaces);
        }
    
        public static SubdomainRoute MapSubdomainRoute(
            this RouteCollection routes,
            string name,
            string subdomain, 
            string url, 
            object defaults = null, 
            object constraints = null, 
            string[] namespaces = null)
        {
            var route = new SubdomainRoute(subdomain, url, new MvcRouteHandler())
            {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints),
                DataTokens = new RouteValueDictionary()
            };
            if ((namespaces != null) && (namespaces.Length > 0))
            {
                route.DataTokens["Namespaces"] = namespaces;
            }
            routes.Add(name, route);
            return route;
        }
    }
    

    AreaRegistrationContextExtensions

    这些扩展方法允许您注册区域路由以使用子域。

    public static class AreaRegistrationContextExtensions
    {
        public static SubdomainRoute MapSubdomainRoute(
            this AreaRegistrationContext context, 
            string url, 
            object defaults = null, 
            object constraints = null, 
            string[] namespaces = null)
        {
            return MapSubdomainRoute(context, null, url, defaults, constraints, namespaces);
        }
    
        public static SubdomainRoute MapSubdomainRoute(
            this AreaRegistrationContext context, 
            string name, 
            string url, 
            object defaults = null, 
            object constraints = null, 
            string[] namespaces = null)
        {
            if ((namespaces == null) && (context.Namespaces != null))
            {
                namespaces = context.Namespaces.ToArray<string>();
            }
            var route = context.Routes.MapSubdomainRoute(name, 
                context.AreaName, url, defaults, constraints, namespaces);
            bool flag = (namespaces == null) || (namespaces.Length == 0);
            route.DataTokens["UseNamespaceFallback"] = flag;
            route.DataTokens["area"] = context.AreaName;
            return route;
        }
    }
    

    用法

    要让 URL 模式 {subdomain}.domain.com/{action}/{id} 使用特定的特定区域,您只需将其注册为 AreaRegistration 的一部分。

    public class AppleAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "Apple";
            }
        }
    
        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapSubdomainRoute(
                url: "{action}/{id}", 
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
        }
    }
    

    注意:您的示例 URL 有一个限制,即每个区域只能使用一个控制器。 controller 是必需的路由值,因此您需要在 URL ({controller}/{action}/{id}) 中提供它,或者将其默认为上述示例 - 后一种情况意味着您只能拥有 1 个控制器。

    当然,您还需要设置 DNS 服务器以使用子域。

    【讨论】:

    • 感谢您的解决方案。我正在使用我的主机文件来设置 DNS 条目和本地 IIS 来托管网站。我可以调试并单步执行代码,我看到分配给 Datatoken 的正确值,但是,当我运行应用程序时,我得到一个 404 资源未找到。顺便说一下,路线值在字典中看起来是正确的。我在 RouteConfig 中遗漏了什么吗?在全局中,我正在注册所有区域 -AreaRegistration.RegisterAllAreas() 然后是 RouteConfig.RegisterRoutes(RouteTable.Routes) (它只忽略一条路线)。谢谢。
    • 不清楚为什么会出现 404。当您将子域作为查询字符串参数(如 Index?subdomain=Apple)提供时,它是否有效?此外,在应用此配置之前,您应确保“正常”路由配置正常工作,以确保您在正确的位置拥有所有控制器、操作和视图。
    • 我确实尝试将子域作为查询字符串参数提供,并且我检查了路由配置是否有效。所以我创建了一个全新的项目,它工作的中提琴!感谢你的付出!我已经接受你的答案是正确的。
    • 如果你想让 [AllowHtml] 工作需要把这个string subdomain = httpContext.Request.Params["subdomain"]; 改成string subdomain = httpContext.Request.Unvalidated.QueryString["subdomain"];
    猜你喜欢
    • 2011-07-29
    • 1970-01-01
    • 2011-05-25
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多