injecting changing view engine list

689 Views Asked by At

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?

0

There are 0 best solutions below