【问题标题】:ASP.NET MVC SubdomainsASP.NET MVC 子域
【发布时间】:2014-01-03 18:37:45
【问题描述】:

我有这样的主机和域名:

www.EXAMPLE.com

我已经创建了几个这样的子域:

www.PAGE1.EXAMPLE.com
www.PAGE2.EXAMPLE.com
www.PAGE3.EXAMPLE.com
... etc...

所有这些子域都指向同一个 ASP.NET MVC 5 应用程序。

我想制作一个根据子域加载数据的系统。 示例:

我有文章对象,可以是自动评论或游戏评论或书评等...

我想 www.auto.example.com 加载文章类型为 Auto 的数据,到 www.book.example.com 我想加载 Book 等类型的数据。

会有很多类型的页面。

这样做的最佳做法是什么?

顶级域 www.example.com 应该显示其他内容。这将是其他人的主页。

【问题讨论】:

标签: asp.net-mvc subdomain


【解决方案1】:

您可以通过编写自定义路由来做到这一点。方法如下(改编自Is it possible to make an ASP.NET MVC route based on a subdomain?

public class SubdomainRoute : RouteBase
{

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var host = httpContext.Request.Url.Host;
        var index = host.IndexOf(".");
        string[] segments = httpContext.Request.Url.PathAndQuery.Split('/');

        if (index < 0)
            return null;

        var subdomain = host.Substring(0, index);
        string controller = (segments.Length > 0) ? segments[0] : "Home";
        string action = (segments.Length > 1) ? segments[1] : "Index";

        var routeData = new RouteData(this, new MvcRouteHandler());
        routeData.Values.Add("controller", controller); //Goes to the relevant Controller  class
        routeData.Values.Add("action", action); //Goes to the relevant action method on the specified Controller
        routeData.Values.Add("subdomain", subdomain); //pass subdomain as argument to action method
        return routeData;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        //Implement your formating Url formating here
        return null;
    }
}

像这样添加到 Global.asax.cs 中的路由表中:

routes.Add(new SubdomainRoute());

还有你的控制器方法:

public ActionResult Index(string subdomain)
{
    //Query your database for the relevant articles based on subdomain
    var viewmodel = MyRepository.GetArticles(subdomain);
    Return View(viewmodel);
}

【讨论】:

  • 但是使用这段代码,我必须为每个子域设置所有控制器。当我将拥有 200 个子域时,这意味着我必须编写 200 个控制器并且每个控制器都应该有操作索引?每个控制器和动作中都有相同的逻辑和代码,唯一的区别是加载数据的类型:(
  • 不,不需要。硬编码值只是为了简化说明。您可以轻松地从 url 解析值或从数据库或某些描述的站点地图中查找它们。
  • 拜托,你能举个例子,当 subDomain == user1 时,我得到所有作者为 user1 的文章,当 subDomain == user2 时,我得到所有作者为 user2 的文章。例如,我不知道如何在最简单的操作中使用索引。
  • 好的,我已经修改了上面的示例,使其符合您的场景。
  • 我已经使用了您的解决方案,但它不起作用。在动作中我得到空参数。我确定我做得很好。有什么不对吗?
【解决方案2】:

这是我长期以来一直想用 ASP.NET MVC 做的事情,但是......这不是 ASP.NET MVC 负责的问题。这是一个服务器问题 (IIS)。您需要做的是在您的 IIS 服务器上允许通配符子域并将它们指向您的 one 应用程序。

然后你可以用 HttpContext 做这样的事情:

HttpContext.Current.Request.Url.Host // user1.yourwebsite.com

然后您只需要解析它并将其推送到您认为合适的 ASP.NET MVC 应用程序中:

  • 将其推送到会话中
  • 更新当前路线数据并在其中推送一个值
  • 等等……

选择权完全取决于您。

注意:这里的缺点是这会使本地开发变得越来越困难,因此您可能需要模拟一种方法来伪造应用程序中的子域。

【讨论】:

  • “您需要做的是在您的 IIS 服务器上允许通配符子域”... 最佳实践是什么?你掩饰它,好像它很简单,但我似乎找不到任何人谈论这样做的好方法。
【解决方案3】:

我试过Paul Taylor 上面的答案非常好,但这对我来说并不完全有效。 我使用Route 类的这个实现。

将您的自定义域添加到 C:/Windows/System32/drivers/etc/hosts 文件中

  • 127.0.0.1 subdomain.localhost.com

DomainData.cs

public class DomainData
{
  public string Protocol { get; set; }
  public string HostName { get; set; }
  public string Fragment { get; set; }
}

DomainRoute.cs

public class DomainRoute : Route
{
  private Regex domainRegex;
  private Regex pathRegex;

  public string Domain { get; set; }

  public DomainRoute(string domain, string url, RouteValueDictionary defaults)
    : base(url, defaults, new MvcRouteHandler())
{
    Domain = domain;
}

public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
    : base(url, defaults, routeHandler)
{
    Domain = domain;
}

public DomainRoute(string domain, string url, object defaults)
    : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
{
    Domain = domain;
}

public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler)
    : base(url, new RouteValueDictionary(defaults), routeHandler)
{
    Domain = domain;
}

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 && requestDomain.ToLower() != "tg.local" &&
        requestDomain.ToLower() != "tg.terrasynq.net" && requestDomain.ToLower() != "www.townsgossip.com" &&
        requestDomain.ToLower() != "townsgossip.com")
    {
        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 = ""
    };
}

private Regex CreateRegex(string source)
{
    // Perform replacements
    source = source.Replace("/", @"\/?");
    source = source.Replace(".", @"\.?");
    source = source.Replace("-", @"\-?");
    source = source.Replace("{", @"(?<");
    source = source.Replace("}", @">([a-zA-Z0-9_\-]*))");

    return new Regex("^" + source + "$");
}

private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
{
    var tokenRegex =
        new Regex(
            @"({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?({[a-zA-Z0-9_\-]*})*\.?\/?");
    Match tokenMatch = tokenRegex.Match(Domain);
    for (int i = 0; i < tokenMatch.Groups.Count; i++)
    {
        Group group = tokenMatch.Groups[i];
        if (group.Success)
        {
            string key = group.Value.Replace("{", "").Replace("}", "");
            if (values.ContainsKey(key))
                values.Remove(key);
        }
    }

    return values;
  }
}

参考:http://www.howtobuildsoftware.com/index.php/how-do/UaR/aspnet-mvc-5-domain-routing-in-mvc5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2011-03-17
    • 2011-12-25
    • 2013-12-08
    • 1970-01-01
    相关资源
    最近更新 更多