Using Subdomains in ASP.NET MVC

January 20th, 2016

Experienced web developers create subdomains for a number of reasons. Today, I discuss how to easily add subdomains to your ASP.NET MVC site.

If you're a web developer, or more specifically an ASP.NET MVC developer, subdomains aren't used too much except for experienced web developers.

There are a number of reasons to create them, but those reasons aren't acknowledged unless you have a specific goal in mind for your website.

What I refer to with implementing subdomains is to either speed up the browser's ability to download content faster or to create an additional sub-site (i.e. m.danylkoweb.com) for targeting specific devices.

Today, I cover how to setup your ASP.NET MVC website with a subdomain.

Overview

What we'll focus on today is creating a mobile subdomain for your primary site (m.site.com).

There are a number of ways to address subdomains, but after a lot of research and examining other techniques, I thought the easiest way to create a subdomain would be through the ASP.NET MVC Routing mechanism using RouteBase.

It requires a minimal amount of setup, can be instantly tested locally, and fits right in with the Routes syntax in your RouteConfig.cs.

So how do we get started?

First, we need our new subdomain route.

Routing\SubdomainRoute.cs

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
 
namespace SubdomainExample.Routing
{
    public class SubdomainRoute : RouteBase
    {
        private readonly string _subDomain;
        private readonly RouteValueDictionary _routeData;

        public SubdomainRoute(string subDomain, object routeData) :             this(subDomain, new RouteValueDictionary(routeData))         { }
        public SubdomainRoute(string subDomain, RouteValueDictionary routeData)         {             _subDomain = subDomain;             _routeData = routeData;         }
        public override RouteData GetRouteData(HttpContextBase httpContext)         {             var url = httpContext.Request.Headers["HOST"];
            var index = url.IndexOf(".", StringComparison.Ordinal);             if (index < 0) return null;
            var firstDomain = url.Split('.')[0];             if ((firstDomain.Equals("www") || firstDomain.Equals("localhost"))                 && !firstDomain.Equals(_subDomain))                 return null;
            var handler = new MvcRouteHandler();             var result = new RouteData { RouteHandler = handler };             foreach (var route in _routeData)             {                 result.Values.Add(route.Key, route.Value);             }
            return result;         }
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)         {             return null;         }     } }

When the context is passed into the GetRouteData method, we grab the server variable HOST to find out the URL.

Once we have the Url, we check to see if there are any periods. If there are, we grab the first domain by splitting the host into an array and grab the first element.

If the first element equals 'www' or 'localhost' AND the value we passed into the constructor is NOT the subdomain, we ignore the route and let it continue to the next route in the list. If a null is returned, it moves to the next route to evaluate and execute if necessary. If we return a non-null value, then we are good. 

Now that we have a valid subdomain, we need to determine where we want to route it.

We create the RouteData and add a standard MvcRouteHandler to it. The route data we defined through the constructor is added to the route and returned.

We need Routes! Where's the Routes?!

The SubdomainRoute is complete, but we need to add it to our RegisterRoutes. This is the simple process.

App_Start\RouteConfig.cs

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        routes.Add(
            new SubdomainRoute("m",
                new { controller = "M", action = "Index", id = UrlParameter.Optional }));
 
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

The new code is in bold. This is the reason I wanted to use RouteBase. It easily integrates into your existing routing engine.

How awesome is that?!

The only thing you need to do it create an MController (or whatever you called your specific controller...it could go to the MobileController if you want) and a Views/M/Index.cshtml and everything should be hooked up and ready to go.

I'm Not Done Yet!

Ok, I lied! We aren't ready to go yet.

This is the part of the post where we focus on the network/server part of your website.

In Visual Studio 2015, we need to change how IIS Express runs your development environment.

  1. In Visual Studio 2015, right-click on the solution file.
  2. Select 'Open Folder in File Explorer'
  3. Go to the containing folder and look for a .vs folder.
  4. Inside, there will be a config folder containing an applicationhost.config file.
  5. Open it in your favorite text editor (I use Notepad++)
  6. Under the Configuration/system.applicationHost/Sites, you should see your site in bindings with a port and localhost.
    <binding protocol="http" bindingInformation="*:38254:localhost" />
    
  7. Duplicate this line and add your subdomain to this binding.
    <binding protocol="http" bindingInformation="*:38254:m.localhost" />
    
  8. Save this file and reload your project.

That was to configure your site in Visual Studio.

Now we need to head to our Hosts file to modify that as well.

  1. Go to C:\Windows\System32\Drivers\Etc in File Explorer.
  2. Open the HOSTS file (it has no extension)
  3. At the bottom of the hosts file, add the following two lines.

    127.0.0.1    localhost
    127.0.0.2    m.localhost

  4. Save the file.

Now we can run our Visual Studio and see our subdomain actually run.

NOW WHAT?!

When we run Visual Studio, we get a problem with launching the IIS Express Web Server.

"Unable to Launch the IIS Express Web Server."? Access is denied?!?

Hmm...

It seems that you need to give Visual Studio 2015 Administrative rights to use subdomains.

Well, let's get to it.

  1. In Windows 10, I have my Visual Studio 2015 pinned to my taskbar. Right-click on the Visual Studio 2015 icon.
  2. On the context menu, right-click on the "Visual Studio 2015" link.
  3. In the secondary context menu, there will be "Open", "Run as Administrator", "Unpin from Taskbar", and "Properties." Click on Properties.
  4. Click the "Advanced..." button.
  5. Make sure the option "Run as Administrator" is checked. If not, check it.
  6. Click OK.
  7. Click Apply and accept the changes.
  8. Click OK one last time to save the changes.
  9. Run Visual Studio 2015 and load your subdomain project.

OK, NOW we can run our site.

As you can see my "mobile page" isn't too fancy, but the key thing here is the subdomain.

One Additional Note

While this is great running in your IDE, deploying this code to production may be a problem.

Whoever hosts your site, your network administrator would have to add an alias to the DNS so your subdomain is directed to the right location.

For example, here is a document for creating a DNS subdomain on GoDaddy. You would have to apply this same logic to your hosting company's DNS.

Again, make sure you know what you're doing before you start changing DNS entries. You may want to contact the hosting company for assistance.

Conclusion

Today, we covered how to setup your development environment to use subdomains.

You can also use this method for optimizing your site for CSS, Scripts, and Images. Since it's considered a different domain(ish), this would maximize performance by allowing the browser to download even more content in parallel allowing your site to appear quicker.

Did this make sense? Post your comments below and let's discuss it.