【问题标题】:Dynamic subdomains in asp.net mvcasp.net mvc 中的动态子域
【发布时间】:2009-11-30 19:49:53
【问题描述】:

我对 asp.net 还很陌生,对 iis 几乎没有经验。我想让我的应用程序的每个用户都有自己的子域,但都使用相同的控制器。然后子域将控制显示的内容。

例子:

user1subdomain.mydomain.com/Whatever
user2subdomain.mydomain.com/Whatever

两者都将使用相同的控制器。理想情况下,参数可以将用户名提供给控制器,然后控制器可以显示适当的内容。我希望它足够灵活,可以将新的子域添加到数据库中,而无需在每次添加新子域时重写路由规则。

【问题讨论】:

  • 到目前为止我实际上只使用内置的visual studio服务器,所以域是localhost。我根本无法获得任何 subdomain.localhost/Whatever 来让我使用有效的控制器。
  • 您不会使用 localhost - 要测试域管理方面,您必须运行 IIS。

标签: asp.net-mvc iis subdomain


【解决方案1】:

MVC 不绑定到域,只绑定到路径(例如http://domain/path)。

要正确执行此操作,您需要以下内容...

  1. 通配符 DNS 设置 *.yourdomain.com 指向您的服务器。
  2. IIS 设置中的站点 没有主机头。任何其他网站 托管在该 IIS 实例中 相同的 IP 必须有 Host 标头 指定。
  3. 您的应用程序需要检查 在页面加载时请求主机标头, 会话开始或其他一些事件。

【讨论】:

    【解决方案2】:

    我在此人的博客上找到了更简单的答案。非常惊讶它的效果和它一样好,而且这个解决方案已有 4 年多的历史了。

    http://blog.maartenballiauw.be/post/2009/05/20/aspnet-mvc-domain-routing.aspx

    自定义路由实现:

    public class DomainRoute : Route
    {
        public string Domain { get; set; }
    
    
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            // Build regex
            domainRegex = CreateRegex(Domain);
            pathRegex = CreateRegex(Url);
    
            // Request information
            string requestDomain = httpContext.Request.Headers["host"];
            if (!string.IsNullOrEmpty(requestDomain))
            {
                if (requestDomain.IndexOf(":") > 0)
                {
                    requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
                }
            }
            else
            {
                requestDomain = httpContext.Request.Url.Host;
            }
            string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    
            // Match domain and route
            Match domainMatch = domainRegex.Match(requestDomain);
            Match pathMatch = pathRegex.Match(requestPath);
    
            // Route data
            RouteData data = null;
            if (domainMatch.Success && pathMatch.Success)
            {
                data = new RouteData(this, RouteHandler);
    
                // Add defaults first
                if (Defaults != null)
                {
                    foreach (KeyValuePair<string, object> item in Defaults)
                    {
                        data.Values[item.Key] = item.Value;
                    }
                }
    
                // Iterate matching domain groups
                for (int i = 1; i < domainMatch.Groups.Count; i++)
                {
                    Group group = domainMatch.Groups[i];
                    if (group.Success)
                    {
                        string key = domainRegex.GroupNameFromNumber(i);
                        if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                        {
                            if (!string.IsNullOrEmpty(group.Value))
                            {
                                data.Values[key] = group.Value;
                            }
                        }
                    }
                }
    
                // Iterate matching path groups
                for (int i = 1; i < pathMatch.Groups.Count; i++)
                {
                    Group group = pathMatch.Groups[i];
                    if (group.Success)
                    {
                        string key = pathRegex.GroupNameFromNumber(i);
                        if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
                        {
                            if (!string.IsNullOrEmpty(group.Value))
                            {
                                data.Values[key] = group.Value;
                            }
                        }
                    }
                }
            }    
        return data;
        }
    
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
        }
    
        public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
        {
            // Build hostname
            string hostname = Domain;
            foreach (KeyValuePair<string, object> pair in values)
            {
                hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
            }
    
            // Return domain data
            return new DomainData
            {
                Protocol = "http",
                HostName = hostname,
                Fragment = ""
            };
        }}
    

    下面是它的使用方法。

    routes.Add("DomainRoute", new DomainRoute(
    "{controller}-{action}.example.com",     // Domain with parameters
    "{id}",    // URL with parameters
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
    ));
    

    【讨论】:

      【解决方案3】:

      基本上没有问题。我想!

      就应用程序/路由而言,路由从域结束的地方开始,因此将多个域映射到同一个应用程序不是问题,这样就可以了。

      就 IIS 而言,您可以将任意数量的域(当然会有限制)映射到单个站点 - 我不确定您是否可以使用通配符 - 您使用的是什么版本的 IIS?

      当请求到达时,您可以挂钩以查看域并因此设置您想要的参数(例如用户),请求的根 URL 也可在周期后期从上下文中获得 - 但您会想早点捡起来的。

      如果您可以使用通配符,这将变得相当简单 - 获取请求,针对数据库中的用户验证子域(如果无效重定向到默认站点),设置用户并通过正常路由继续。

      如果您不能使用通配符,那么挑战就是在将用户添加到数据库时从您的应用程序中动态地将主机标头添加到 IIS 应用程序(网站)。

      【讨论】:

      • 对于 IIS,如果没有为站点指定主机头值,那么它接受所有主机头值,您只需确保以这种方式在 IIS 中每个 IP 设置只有一个站点。
      猜你喜欢
      • 2014-01-03
      • 2011-12-25
      • 1970-01-01
      • 2016-12-01
      • 1970-01-01
      • 2013-12-08
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      相关资源
      最近更新 更多