Ninject + Auto Discovery

ironfist

Here's the deal: I want to create a C# console app. When run, this app will look in a particular folder for dll's with classes that implement a particular interface, and then run a method on those dll's.

I haven't done this before but from my reading that should be "easy enough" from an IoC/Ninject perspective. I think you can do something with kernel.Bind() to load assemblies of a certain interface in a certain directory. I think/hope I can figure that part out (if you know otherwise, please do tell!).

But here is my quandary.

Here is a visual to help first:

MainProgramFolder
-- MainProgram.exe
-- MainProgram.exe.config
-- LibraryFolder
----- Library1Folder
--------Library1.dll
--------Library1.dll.config
----- Library2Folder
--------Library2.dll
--------Library2.dll.config

The dll's that implement this interface are technically stand alone apps -- they are just libraries instead of exe's (or, rather, I'd like them to be for IoC purposes). I'd like for them to be run in their own context, with their own app.configs. So for example, MainProgram.exe would bind the ILibrary interface to classes inside Library1.dll and Library2.dll because they implement ILibrary. But inside Library1, it calls ConfigurationManager to get its settings. When I call Class.Method() for each of the bindings from MainProgram, how can I ensure they are referencing their own .config's and not MainProgram.exe.config? (Also, fwiw, these additional libraries will likely not be a part of the assembly or even namespace of the main programs -- we're basically providing a drop folder for an application to kind of "subscribe" to the main program's execution.)

IOW, I know you can attach an app.config to a class library but I wouldn't know how, after the bindings have been resolved from the IOC, to make those dll's "see" its own config rather than the main program's config.

All thoughts appreciated!

Thanks Tom

Brook

First, to load and bind all of your classes you'll need ninject.extensions.conventions, and something like this:

        var kernel = new StandardKernel();
        /*add relevant loop/function here to make it recurse folders if need be*/
        kernel.Bind(s => s.FromAssembliesMatching("Library*.dll")
            .Select(type => type.IsClass && type.GetInterfaces().Contains(typeof(ILibrary)))
            .BindSingleInterface()
            .Configure(x=>x.InSingletonScope()));

To make each instance load its configuration as if it was the entry point you will need to run it in a new app domain. Your ILibrary implementation needs to inherit MarshalByRefObject and be Serializable so that it will run correctly in the alternate appdomain

[Serializable]
    public class LibraryA :MarshalByRefObject, ILibrary

You can then add this activation strategy to your kernel that will cause it to swap out instances of ILibrary with an instance loaded in an alternate appdomain with your config file convention before they are returned.

public class AlternateAppDomainStrategy<T> : ActivationStrategy
    {
        public override void Activate(IContext context, InstanceReference reference) 
        {
            if (reference.Instance.GetType().GetInterfaces().Contains(typeof(T)))
            {
                var type = reference.Instance.GetType();

                var configFilePath = type.Assembly.GetName().Name + ".dll.config";
                var file = new FileInfo(configFilePath);
                if (file.Exists)
                {
                    var setup = new AppDomainSetup() { ConfigurationFile = file.FullName, ApplicationBase = AppDomain.CurrentDomain.BaseDirectory };
                    var domain = AppDomain.CreateDomain(type.FullName, null, setup);

                    var instance = domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);

                    reference.Instance = instance;
                }
                else
                {
                    throw new FileNotFoundException("Missing config file", file.FullName);
                }
            }
        }
    }

And Add it to your kernel

kernel.Components.Add<IActivationStrategy, AlternateAppDomainStrategy<ILibrary>>();

From there you can simply instantiate your ILibrary instances and call methods on them. They will load in their own app domains with their own configs. It gets a lot more complicated if you need to pass things in/out of the instance either via methods or constructor, but from the sound if it you don't so this should be OK.

var libs = kernel.GetAll<ILibrary>();
            foreach (var lib in libs)
            {
                lib.Method();
            }

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

elasticsearch: auto node discovery not happening, missing anything?

From Dev

Disable TypeScript files auto discovery in Visual Studio

From Dev

Auto-Proxy services with Consul Service Discovery

From Dev

Does GridGain support auto discovery on Amazon EC2?

From Dev

How to use simple-spring-memcached with AWS Auto Discovery

From Dev

NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [ASC_ID] during auto-discovery of a native-sql query

From Dev

Active MQ clustering using http auto discovery with multi cast on Amazon EC2

From Dev

Active MQ clustering using http auto discovery with multi cast on Amazon EC2

From Dev

Apache + mod_ssl intermediate CA auto discovery for X.509 client auth

From Dev

Hangfire with Ninject

From Dev

Catel with Ninject

From Dev

RepositoryFactory with Ninject

From Dev

Hangfire with Ninject

From Dev

TemplatePart discovery

From Dev

Paxos and Discovery

From Dev

Ninject - How to implement Command Pattern with Ninject?

From Dev

Ninject - How to implement Command Pattern with Ninject?

From Dev

Ninject Transient Scope with Dispose

From Dev

Ninject dynamically constructor parameters

From Dev

Ninject UserManager and UserStore

From Dev

Questions about using Ninject

From Dev

Ninject equivalent to MEF AssemblyCatalog

From Dev

Ninject Decorator not being used

From Dev

Ninject - Injecting singleton

From Dev

Bind a collection to Ninject

From Dev

Setup Ninject for WCF

From Dev

Constructor with multiple arguments with Ninject

From Dev

Automapper ninject dependencies

From Dev

Ninject Binding By Parameter Name