0

I'm trying to do a multi-tenanted app, where tenants can get their own subdomains e.g.

  • tenant1.mysite.com
  • tenant2.mysite.com

I've tried using custom routedata, it works only on the first page, somehow on the other pages like /login, /register, etc there's always errors being thrown and it gets very cryptic.

I gave up and went ahead with using a wildcard DNS and let my HomeController determine how to render the View based on the subdomain

ActionFilter

public class SubdomainTenancy : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string subdomain = filterContext.RequestContext.HttpContext.Request.Params["subdomain"]; // A subdomain specified as a query parameter takes precedence over the hostname.
        if (subdomain == null)
        {
            string host = filterContext.RequestContext.HttpContext.Request.Headers["Host"];
            int index = host.IndexOf('.');
            if (index >= 0)
                subdomain = host.Substring(0, index);
            filterContext.Controller.ViewBag.Subdomain = subdomain; 
        }    
        base.OnActionExecuting(filterContext);
    }
}

Home Controller

[SubdomainTenancy]
[AllowAnonymous]
public class HomeController : BaseController
{
    public ActionResult Index()
    {
        string subdomain = ViewBag.Subdomain;
        if (subdomain != "www" && !string.IsNullOrEmpty(subdomain) )
        {
            var db = new tenantdb();
            var store = db.GetBySubdomain(subdomain);
            if (store == null) 
            {
                return Redirect(HttpContext.Request.Url.AbsoluteUri.Replace(subdomain, "www"));
            }
            else //it's a valid tenant, let's see if there's a custom layout
            { 
                //load custom view, (if any?)
            }
        }
        return View();            
    }       
}

So now the problem comes when i try to use VirtualPathProvider to load View from database based on the subdomain, but i'm unable to access HttpContext, perhaps due to the life cycle? Now i'm stuck, i've also tried to use RazorEngine to load custom views (from database)

What should i do to support multi-tenancy on my web app that will first search the database for custom views and render using the view in database, else if there's none, fall back to the default /Home/Index.cshtml?

Community
  • 1
  • 1
Lee Gary
  • 2,357
  • 2
  • 22
  • 38

1 Answers1

1

We did something similar by making a custom ViewEngine and making it aware of the multi tenancy of the app... The ViewEngine then can look for a view based on the subdomain (in our case physical, but could have been from a db).

We made our ViewEngine inherit from RazorViewEngine and then we overrode the methods as needed (FileExists, FindPartialView, FindView)

Once we had a custom ViewEngine, then we just cleared the other ViewEngines and registered the custom one in the application_start in global.asax.

ViewEngines.Engines.Clear()
ViewEngines.Engines.Add(new CustomViewEngine()) 

I don't have sample code I can share on the custom ViewEngine, but hopefully this will point you in the right direction.

Haldrich98
  • 379
  • 3
  • 13
  • how do you determine the subdomain in the virtualpathprovider? Can't use httpcontext there – Lee Gary Jul 06 '14 at 14:23
  • As I said, our approach overrides the RazorViewEngine. We don't need to rely on on virtualpathprovider. You can find the domain when you're overriding the various methods of RazorViewEngine. – Haldrich98 Jul 07 '14 at 04:55