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?

Community
  • 1
  • 1
jmcd
  • 4,269
  • 5
  • 36
  • 36
  • 3
    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. – Tom Clarkson Jan 01 '11 at 11:08

2 Answers2

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/

superjos
  • 12,189
  • 6
  • 89
  • 134
jmcd
  • 4,269
  • 5
  • 36
  • 36
  • what is Plugin folder ? or is it just a namespace? – Mou Oct 20 '16 at 10:29
  • 1
    There is such a thing as the Internet Archive, and it has this page: https://web.archive.org/web/20150414200605/http://wynia.org/wordpress/2008/12/aspnet-mvc-plugins – jmcd Mar 06 '19 at 21:06
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.

Brad Wilson
  • 67,914
  • 9
  • 74
  • 83