I did something similar some time ago regarding a plugin system where plugins, where pages and controls were stored in separate assemblies.
As a result, we finished:
Register your custom VirtualPathProvider at Application_Start:
void Application_Start(object sender, EventArgs e) { System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider( new YourCustomVirtualPathProvider()); }
Override the necessary methods in VirtualPathProvider (based on your logic):
public class YourCustomVirtualPathProvider : System.Web.Hosting.VirtualPathProvider { private const string RESERVED_PATH = "/components/external"; public override bool FileExists(string virtualPath) { if (virtualPath.StartsWith(RESERVED_PATH)) return true; else return base.FileExists(virtualPath); } public override VirtualFile GetFile(string virtualPath) { if (virtualPath.StartsWith(RESERVED_PATH)) return new MyCustomVirtualFile(virtualPath); else return base.GetFile(virtualPath); }
Now create the MyCustomVirtualFile
class to load files from the assembly:
public class MyCustomVirtualFile : System.Web.Hosting.VirtualFile { private string _virtualPath; public MyCustomVirtualFile(string virtualPath) { _virtualPath = virtualPath } public override System.IO.Stream Open() {
The ASPX / ASCX or resource files that you want to load this way must be added as a built-in resource for the assembly. You can do this by changing the "Create action" property of the file:

The back code will be compiled into the assembly, and if you use the shared bin
folder, you no longer need to do anything. If they are not available, you will need to join the AssemblyResolve
and TypeResolve
in the global application (more on this here ).
In the end, we abandoned this idea due to security concerns and ended up working with MEF contracts, but if all of your other builds are the first to party, then this should be quick and easy. Hope this helps.
source share