2

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.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
Jeff
  • 35,755
  • 15
  • 108
  • 220

3 Answers3

4

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.

Community
  • 1
  • 1
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Can you please be more specific? Thanks. – Jeff Aug 18 '10 at 17:52
  • Thanks. And how do I get from these format strings to have my VirtualPathProvider to know where to read the file from? – Jeff Aug 18 '10 at 18:25
  • 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? – Jeff Aug 18 '10 at 19:10
  • That shouldn't be happening. Does your VPP get any other requests? – SLaks Aug 18 '10 at 19:19
  • 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. – Jeff Aug 18 '10 at 19:41
  • Your views are in a zip file? – Praveen Aug 18 '10 at 23:01
  • No, I just made that up because I thought it would better illustrate what I'm actually trying to accomplish here. – Jeff Aug 19 '10 at 05:33
  • 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 Aug 19 '10 at 19:31
0

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
  • 772
  • 2
  • 9
  • 25
0

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.

Jeff
  • 35,755
  • 15
  • 108
  • 220
  • 1
    After the first one (which must return false to stop IIS trying to serve it as a static file instead of running the controller action) FileExists gets called with both "~/Views/Account/LogOn.aspx" and "/AppName/Views/Account/LogOn.aspx" - both of these need to return true. – Tom Clarkson Jan 01 '11 at 10:07