Search code examples
.netasp.net-mvcdependency-injectionasp.net-mvc-4simple-injector

Simple Injector with asp.net mvc 4, load controller from another assembly


I'm developing an asp.net mvc 4 site, using Simple Injector as a Ioc tool. It would be a pluggable architecture. Some controllers and views are in another assembly (another mvc4 application, Plugin.Web.dll). And from the main application, I know the path of Plugin.Web.dll, loading the plugin.

container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

container.RegisterMvcAttributeFilterProvider();

container.Options.AllowOverridingRegistrations = true;

var appPath = AppDomain.CurrentDomain.BaseDirectory;

string[] files = Directory.GetFiles(appPath + "\\Plugins", "*",
    SearchOption.AllDirectories);

foreach (var fileName in files)
{
    Console.WriteLine(fileName);

    var assembly = Assembly.LoadFrom(fileName);

    container.RegisterMvcControllers(assembly);

    var controllerTypes =
        from type in assembly.GetExportedTypes()
        where type.Name.EndsWith("Controller",
            StringComparison.Ordinal)
        where typeof(IController).IsAssignableFrom(type)
        where !type.IsAbstract
        select type;

    // Instead of verify:
    foreach (var type in controllerTypes)
    {
        container.GetInstance(type);
    }
}            

container.Options.AllowOverridingRegistrations = false;       

container.Verify();

DependencyResolver.SetResolver(
    new SimpleInjectorDependencyResolver(container));

It gives no errors.

But when I click this click, in view:

@Html.ActionLink("plugin page","PluginPage","Plugin")

It gives 'The resource cannot be found., http 404'

thanks in advance


Solution

  • I'm afraid you'll have to do some more research, since your question is a bit vague at the moment, but here are some pointers:

    Check if System.Web.Compilation.BuildManager.GetReferencedAssemblies() returns your plugin assemblies. The MVC DefaultControllerFactory searches for Controller types in all assemblies returned from that method. Best is to place your plugin folder inside the /bin directory. If I'm not mistaken GetReferencedAssemblies() also looks in sub directories of /bin. You'll probably need to write a custom controller factory if plugins must be loaded more dynamically.

    Also take a look at this article, as it describes how to force the BuildManager to know about your plugin assemblies.

    Your configuration seems overly complex. The following configuration should do the trick as well:

    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    
    container.RegisterMvcAttributeFilterProvider();
    
    var appPath = AppDomain.CurrentDomain.BaseDirectory;
    
    string[] files = Directory.GetFiles(appPath + "\\bin\\Plugins", "*",
        SearchOption.AllDirectories);
    
    container.RegisterMvcControllers(
        from fileName in files
        select Assembly.LoadFrom(fileName)
    );    
    
    container.Verify();
    

    You can query the container's configuration to look what it contains. For instance, this will query all registered controllers:

    var registeredControllerTypes = (
        from registration in container.GetCurrentRegistrations()
        where typeof(IController).IsAssignableFrom(registration.ServiceType)
        select registration.ServiceType)
        .ToArray();