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
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.
Comments