0

I'm trying to develop a multi-tenancy project wherein each client can have their own specific view engines.

Specifically I'd like to compile the views to a DLL (using RazorEngine) and have an individual RazorViewEngine for each client but also provide a fallback to the standard RazorViewEngine if no matching views are found, just as the MVC framework does if you have multiple view engines specified.

I have found I can inject view engines using autofac in the Global.asax of my MVC 4 project using:

ViewEngines.Engines.Clear();

var builder = new ContainerBuilder();
builder.RegisterType<WebFormViewEngine>().As<IViewEngine>();

Now I also want to provide tenant specific overrides as mentioned above which I can do with the following code:

var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
mtc.ConfigureTenant("Client1", b => b.RegisterType<RazorViewEngine>().As<IViewEngine>());
DependencyResolver.SetResolver(new AutofacDependencyResolver(mtc));

In this example code I just wanted to see if I could set the WebFormsViewEngine as a fallback and then enable the RazorViewEngine for a specific tenant.

Upon loading and browsing to a non-tenant url, mvc will resolve just the WebFormsViewEngine as expected (through calling the DependencyResolver and in turn Autofac), this works as expected however when I then visit a url that would also include the RazorViewEngine no views are found, even though a valid razor view exists.

Conversely if I stop IISExpress or do something to generate an app pool recycle and visit a tenantable url first both view engines are registered.

From what I can tell MVC caches the list of view engines retrieved after the first call to the MultiServiceResolver.

internal IViewEngine[] CombinedItems
{
    get
    {
        IViewEngine[] combinedItems = _combinedItems;
        if (combinedItems == null)
        {
            combinedItems = MultiServiceResolver.GetCombined<IViewEngine>(Items, _dependencyResolver);
            _combinedItems = combinedItems;
        }
        return combinedItems;
    }
}

Is there a way to override this caching or another better way to achieve what I'm trying to get here?

Daniel Powell
  • 8,143
  • 11
  • 61
  • 108
  • The issue is that the app_start fires off when the app starts up, not per request, so if you are conditionally loading your viewengines in app_start, then no more will get loaded in. if you just want to override the viewengine, have you thought about using an actionfilter to determine the viewengine and adjust the viewenginecollection on the viewresult in the onactionexecuted event? – Slicksim Aug 27 '13 at 08:10
  • I thought about something along those lines, (modifying on beginrequest) but viewengines is static so wouldnt that modify if for every request then – Daniel Powell Aug 27 '13 at 12:16
  • this is a trivial example, in real use for instance not everyone would have the razorviewengine so id like not to penalise them for the lookup if they dont use it (no matter how miniscule it would be) and also some views just shouldnt ever be available to some tenants – Daniel Powell Aug 27 '13 at 12:17

0 Answers0