Back to MVC land! This time, I wanted to be able to load controllers and views from an assembly other than my application. I know about the extensibility mechanisms that ASP.NET and MVC give provides, such as Virtual Path Providers and Controller Factories, so I thought I could use them.
First things first: we need a controller factory that can load a controller from another assembly:
Next, we need to be able to load view files from an assembly, and a virtual path provider is just what we need for that:
These three classes inherit from VirtualPathProvider, VirtualFile and CacheDependency and just override some of its methods. AssemblyVirtualPathProvider first checks with other virtual path providers if a file exists, and only if it doesn’t does it create the AssemblyVirtualFile. This looks up the virtual file name in the assembly’s resources, using a convention that translates slashes (/) per dots (.) and returns it. As for the AssemblyCacheDependency, we need it because otherwise ASP.NET MVC will think that the file exists in a directory and will try to monitor it, and because the directory and file do not exist, it will throw an exception at runtime.
We also need a bootstrapping class for setting up everything:
Finally, for this to work, we need three things:
- The controller must be public, have a parameterless constructor, and its name must end with Controller (the default convention);
- View files must be compiled as embedded resources in the assembly:
- And finally, we need to set this up in Global.asax.cs or RouteConfig.cs:
By the way, the AssemblyVirtualPath provider, AssemblyVirtualFile and AssemblyCacheDependency are pretty generic, so you can use them in other scenarios.
That’s all, folks!