My goal is to modify asp.net mvc's controller registery so that I can create controllers and views in a separate (child) assembly, and just copy the View files and the DLLs to the host MVC application and the new controllers are effectively "Plugged In" to the host app.
Obviously, I will need some sort of IoC pattern, but I'm at a loss.
My thought was to have a child assembly with system.web.mvc referenced and then to just start building controller classes that inherited from Controller
:
Separate Assembly:
using System.Web;
using System.Web.Mvc;
namespace ChildApp
{
public class ChildController : Controller
{
ActionResult Index()
{
return View();
}
}
}
Yay all fine and dandy. But then I looked into modifying the host application's Controller registry to load my new child controller at runtime, and I got confused. Perhaps because I need a deeper understanding of C#.
Anyway, I thought I needed to create a CustomControllerFactory
class. So I started writing a class that would override the GetControllerInstance()
method. As I was typing, intellisence popped this up:
Host MVC Application:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
Now, at this point I'm at a loss. I don't know what that does. Originally, I was going to write a "Controller Loader" class like a Service Locator like this:
Host MVC Application:
public class ControllerLoader
{
public static IList<IController> Load(string folder)
{
IList<IController> controllers = new List<IController>();
// Get files in folder
string[] files = Directory.GetFiles(folder, "*.plug.dll");
foreach(string file in files)
{
Assembly assembly = Assembly.LoadFile(file);
var types = assembly.GetExportedTypes();
foreach (Type type in types)
{
if (type.GetInterfaces().Contains(typeof(IController)))
{
object instance = Activator.CreateInstance(type);
controllers.Add(instance as IController);
}
}
}
return controllers;
}
}
And then I was planning on using my list of controllers to register them in the controller factory. But ... how? I feel like I'm on the edge of figuring it out. I guess it all bois down to this question: How do I hook into return base.GetControllerInstance(requestContext, controllerType);
? Or, should I use a different approach altogether?
Reference the other assembly from the 'root' ASP.NET MVC project. If the controllers are in another namespace, you'll need to modify the routes in global.asax, like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { typeof(HomeController).Namespace }
);
}
Notice the additional namespaces
argument to the MapRoute
method.