Skip to content

Instantly share code, notes, and snippets.

@goenning
Created February 28, 2012 14:59

Revisions

  1. Guilherme Oenning created this gist Feb 28, 2012.
    122 changes: 122 additions & 0 deletions gistfile1.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    //Usage:
    context.Routes.Add("Site_Home", new SubdomainRoute(
    "",
    "",
    new { area = this.AreaName, controller = "Home", action = "Index" },
    new { httpMethod = new HttpMethodConstraint("GET") },
    new string[] { "SubdomainRouting.Areas.Site.Controllers" }
    ));

    //Custom Route:
    public class SubdomainRoute : Route, IRouteWithArea
    {
    private string[] namespaces;
    public string Subdomain { get; private set; }

    public SubdomainRoute(string subdomain, string url, object defaults, string[] namespaces)
    : this(subdomain, url, defaults, new { }, namespaces)
    {

    }

    public SubdomainRoute(string subdomain, string url, object defaults, object constraints, string[] namespaces)
    : base(url, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new MvcRouteHandler())
    {
    this.Subdomain = subdomain;
    this.namespaces = namespaces;
    }

    public string Area
    {
    get { return Convert.ToString(this.Defaults["area"]); }
    }

    private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
    {
    if (Constraints != null)
    {
    foreach (var constraintsItem in Constraints)
    {
    if (!ProcessConstraint(httpContext, constraintsItem.Value, constraintsItem.Key, values, routeDirection))
    {
    return false;
    }
    }
    }
    return true;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
    string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    string requestDomain = GetSubdomain(httpContext.Request.Headers["Host"]);

    RouteData data = null;
    Regex domainRegex = CreateRegex(this.Subdomain);
    Regex pathRegex = CreateRegex(this.Url);
    Match domainMatch = domainRegex.Match(requestDomain);
    Match pathMatch = pathRegex.Match(requestPath);

    if (domainMatch.Success && pathMatch.Success)
    {
    data = new RouteData(this, RouteHandler);

    if (Defaults != null)
    {
    foreach (KeyValuePair<string, object> item in Defaults)
    data.Values[item.Key] = item.Value;
    }

    if (!this.ProcessConstraints(httpContext, data.Values, RouteDirection.IncomingRequest))
    return null;

    for (int i = 0; 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;
    }
    }
    }
    }

    data.DataTokens.Add("Area", data.Values["area"]);
    data.DataTokens.Add("namespaces", this.namespaces);
    }

    return data;
    }

    public static string GetSubdomain(string host)
    {
    if (host.IndexOf(":") >= 0)
    host = host.Substring(0, host.IndexOf(":"));

    Regex tldRegex = new Regex(@"\.[a-z]{2,3}\.[a-z]{2}$");
    host = tldRegex.Replace(host, "");
    tldRegex = new Regex(@"\.[a-z]{2,4}$");
    host = tldRegex.Replace(host, "");

    if (host.Split('.').Length > 1)
    return host.Substring(0, host.IndexOf("."));
    else
    return string.Empty;
    }

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