Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic subdomains in asp.net mvc

I am fairly new to asp.net, and have little experience with iis. I would like to have each user of my application get their own sub-domain, but all use the same controllers. The subdomain would then control what content is displayed.

Example:

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

Will both use the same controller. Ideally a parameter could give the user name to the controller, which could then display the appropriate content. I would like it to be flexible enough that new subdomains could be added to the database without rewriting routing rules every time a new subdomain is added.

like image 952
captncraig Avatar asked Nov 30 '09 19:11

captncraig


People also ask

Can you have 2 subdomains?

You create subdomains to help organize and navigate to different sections of your main website. Within your main domain, you can have as many subdomains as necessary to get to all of the different pages of your website.

Can you stack subdomains?

Yes. You can have as many levels as you like in DNS.

Can subdomains have subdomains?

All subdomains are on the same level. You won't have a subdomain within a subdomain like you would a subfolder within a subfolder.


2 Answers

MVC is not bound to the domain, just to the path (e.g. http://domain/path).

To do this properly you need the following...

  1. Wildcard DNS setup for *.yourdomain.com pointing to your server.
  2. The site in IIS setup with no Host Header. Any other sites hosted in that instance of IIS on the same IP must have Host headers specified.
  3. Your application will need to check the request host header either on page load, session start or some other event.
like image 197
MyItchyChin Avatar answered Nov 07 '22 08:11

MyItchyChin


I found an easier answer on this person's blog. Very surprised this works as well as it does and that this solution is more than 4 years old.

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

A custom route implementation:

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

And here is how it can be used.

routes.Add("DomainRoute", new DomainRoute(
"{controller}-{action}.example.com",     // Domain with parameters
"{id}",    // URL with parameters
new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
));
like image 26
Bon Avatar answered Nov 07 '22 09:11

Bon