Using VirtualPathProvider to load ASP.NET MVC views from DLLs
Asked Answered
O

2

40

Based on this question here and using code found here I'm trying to load views that are embedded resources in a separate DLL project, and the original question's author says he has had success doing this - but I can't get it to work as it seems the MVC view engine is intercepting the request and still looking at the file system for the view. Exception:

Server Error in '/' Application.
The view 'Index' or its master could not be found. The following locations were searched:
~/Views/admin/Index.aspx
~/Views/admin/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/App/Views/admin/Index.aspx
~/App/Views/admin/Index.ascx
~/App/Views/Shared/Index.aspx
~/App/Views/Shared/Index.ascx 

I am using a CustomViewEngine, like Rob Connery's /App structure one as follows:

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

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

             PartialViewLocationFormats = ViewLocationFormats;
         }
    }

Here are my routes:

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute("Home", "", new {controller = "Page", action = "Index", id = "Default"});
    routes.MapRoute("Default", "Page/{id}", new { controller = "Page", action = "Index", id = "" });
    routes.MapRoute("Plugins", "plugin/{controller}/{action}", new { controller = "", action = "Index", id = "" });
    routes.MapRoute("Error", "{*url}", new { controller = "Error", action = "ResourceNotFound404" });

In my AssemblyResourceProvider I'm checking to see if the path starts ~/plugin/ and then using the dll filename convention plugin.{controller}.dll

Any suggestions?

UPDATE: By the time the routed request for say http://localhost/plugin/admin is getting to the VirtualFileProvider it doesn't have any View attached at the end. So in the VirtualFileProvider's Open method the virtual path of ~/plugin/admin is being passed in when it should be ~/plugin/admin/Index.aspx as defined in my route above. Have I messed up my routes or am I right to be expecting this to happen?

Outcurve answered 25/10, 2008 at 20:24 Comment(1)
That first FileExists call happens before the controller runs, and must return false or IIS will try to serve it as a static files. The request for the actual aspx file comes later, when the controller requests a view.Spat
O
24
  1. You must register your VirtualPathProvider within the Global.asax Application_Start handler.
  2. You must call the view in your DLL using the special path like so: return View("~/Plugin/YOURDLL.dll/FULLNAME_YOUR_VIEW.aspx");

Here's an article with downloadable code sample that demonstrates this:

http://www.wynia.org/wordpress/2008/12/aspnet-mvc-plugins/

Outcurve answered 26/10, 2008 at 17:58 Comment(2)
what is Plugin folder ? or is it just a namespace?Cawley
There is such a thing as the Internet Archive, and it has this page: web.archive.org/web/20150414200605/http://wynia.org/wordpress/…Outcurve
S
4

The built-in WebFormsViewEngine uses VirtualPathProviders, so if you write a VPP and register it, you won't need to make any changes to the view engine.

Shoon answered 26/10, 2008 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.