MVC4 Razor Custom View Locator

2019-01-20 01:41发布

问题:

I'm working on an MVC4 application that is designed to service two domains. Most of our content will be shared across the domains, but sometimes we will need to render different markup (using Razor) depending on which site the request came from.

Ideally, I want a convention-based approach that allows me to have a folder structure like this:

Views
+ Domain1
    + ControllerName
        View1
        View2
+ Domain2
    + ControllerName
        View1
+ ControllerName
   View1
   View2

When resolving a view, I would like to check the domain-specific folder first, then the general views folder.

My first thoughts were to implement a custom view engine that inherits RazorViewEngine that would swap the ViewLocationFormats strings depending on the request domain. Unfortunately all this stuff is buried in the VirtualPathProviderEngine and can't be overridden.

回答1:

It turns out that the answer was to create a custom view engine (inherited from RazorViewEngine) for each domain that knows about the domain-specific folders:

public class Domain1ViewEngine() : RazorViewEngine
{
        ...

        ViewLocationFormats = new[]
        {
            "~/Views/Domain1/{1}/{0}.cshtml",
            "~/Views/Domain1/Shared/{0}.cshtml"
        };

        ...
}

I then needed to override the FindView and FindPartialView methods so that it only attempted to find locate views if the request had come from the right domain:

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
    if ([THIS IS NOT THE RIGHT DOMAIN]) 
    {
        return new ViewEngineResult(new string[] { });
    }

    return base.FindView(controllerContext, viewName, masterName, useCache);
}

To complete the process I registered the view engine in Global.asax.cs in the usual way:

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new Domain1ViewEngine());
    ViewEngines.Engines.Add(new RazorViewEngine());
}