views:

139

answers:

3

I am writing a VirtualPathProvider to dynamically load my MVC views, which are located in a different directory. I successfully intercept the call before MVC (in FileExists), but in my VirtualPathProvider, I get the raw, pre-routed url like:

~/Apps/Administration/Account/LogOn

Personally, I know that MVC will look for

~/Apps/Administration/Views/Account/LogOn.aspx

and that I should be reading the file contents from

D:\SomeOtherNonWebRootDirectory\Apps\Administration\Views\Account\LogOn.aspx

but I'd rather not hard code the logic to "add the directory named Views and add aspx to the end".

Where is this logic stored and how can I get it into my virtual path provider?

Thanks. Sorry if I'm not being clear.

+1  A: 

Edited

You need to make a class that inherits WebFormViewEngine and sets the ViewLocationFormats property (inherited from VirtualPathProviderViewEngine).

The default values can be found in the MVC source code:

public WebFormViewEngine() {
    MasterLocationFormats = new[] {
        "~/Views/{1}/{0}.master",
        "~/Views/Shared/{0}.master"
    };

    AreaMasterLocationFormats = new[] {
        "~/Areas/{2}/Views/{1}/{0}.master",
        "~/Areas/{2}/Views/Shared/{0}.master",
    };

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

    AreaViewLocationFormats = new[] {
        "~/Areas/{2}/Views/{1}/{0}.aspx",
        "~/Areas/{2}/Views/{1}/{0}.ascx",
        "~/Areas/{2}/Views/Shared/{0}.aspx",
        "~/Areas/{2}/Views/Shared/{0}.ascx",
    };

    PartialViewLocationFormats = ViewLocationFormats;
    AreaPartialViewLocationFormats = AreaViewLocationFormats;
}

You should then clear the ViewEngines.Engines collection and add your ViewEngine instance to it.

SLaks
Can you please be more specific? Thanks.
JeffN825
Thanks. And how do I get from these format strings to have my VirtualPathProvider to know where to read the file from?
JeffN825
In other words, if my VirtualPathProvider gets a request for ~/Apps/Administration/Account/LogOn, how do I use the above information to know to look for D:\SomeOtherPath\Apps\Administrations\Views\Account\LogOn.aspx?
JeffN825
That shouldn't be happening. Does your VPP get any other requests?
SLaks
I'm not sure what you're asking... If I register my VPP before MVC, it gets all requests. If I register it after, MVC handles the request first. Also, please note that the source diredctory I want to read from is OUTSIDE of the actual web-app's base directory...specifically it's in a zip file.
JeffN825
Your views are in a zip file?
Praveen
No, I just made that up because I thought it would better illustrate what I'm actually trying to accomplish here.
JeffN825
If you override the FindView method and implement custom logic, you should be able to pull your Views from any folder, virtual or physical alike.
Praveen
A: 

As SLaks mentioned above, you need to create a Custom View Engine and add your view-finding logic in the FindView method.

public class CustomViewEngine : VirtualPathProviderViewEngine

{

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)

    {
        //Set view path
        string viewPath = GetCurrentViewPath();

        //Set master path (if need be)
        string masterPath = GetCurrentMasterPath();

        return base.FindView(controllerContext, viewPath, masterPath, useCache);
    }

}

In the Application_Start, you can register your View Engine like this:

 ViewEngines.Engines.Clear();
 ViewEngines.Engines.Add(new CustomViewEngine());
Praveen
A: 

The answer was that MVC was not finding my controller properly. If MVC does in fact find your controller properly, there should be two requests processed by the VirtualPathProvider:

  1. An initial request with the acutal url requested (ie. http://.../Account/LogOn).

  2. A subsequent FileExists check for http://.../Views/Account/LogOn.aspx, after the request in 1. returns false calling FileExists. This actually retuns the aspx content.

JeffN825