2013-11-15 83 views
2

这里的交易:我想创建一个C#控制台应用程序。运行时,这个应用程序将在特定的文件夹中查找dll的实现特定接口的类,然后在这些dll上运行一个方法。Ninject +汽车发现

我之前没有这样做过,但是从我的阅读中看,应该从IoC/Ninject的角度来说“够简单”。我想你可以用kernel.Bind()来做一些事情来加载特定目录中某个接口的程序集。我想/我希望我能把那部分弄清楚(如果你知道的话,请告诉你!)。

但这里是我的窘境。

这里是一个可视化,以帮助第一:

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

DLL的实现这个接口在技术上独立的应用程序 - 它们只是库而不是exe文件的(或者说,我想他们喜欢为了IoC的目的)。我希望他们能够在自己的环境中运行,并拥有自己的app.configs。因此,例如,MainProgram.exe会将ILibrary接口绑定到Library1.dll和Library2.dll中的类,因为它们实现了ILibrary。但里面的库1,它调用ConfigurationManager来获得它的设置。当我为MainProgram的每个绑定调用Class.Method()时,如何确保它们引用自己的.config而不是MainProgram.exe.config? (另外,fwiw,这些额外的库可能不是程序集的一部分,甚至是主程序的命名空间的一部分 - 我们基本上为应用程序提供了一个drop文件夹,用于“订阅”主程序的执行。)

IOW,我知道你可以附加一个app.config到一个类库,但我不知道在从IOC解析绑定之后,如何让这些DLL“看到”它自己的配置而不是主程序的配置。

所有的想法都很感谢!

感谢 汤姆

回答

3

首先,加载和绑定所有的类的,你需要ninject.extensions.conventions,和这样的事情:

 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())); 

为了让每个实例加载其配置就好像它是您需要在新的应用程序域中运行它的入口点一样。你ILibrary实现需要继承MarshalByRefObject的和可序列化,使其在交替的AppDomain正确运行

[Serializable] 
    public class LibraryA :MarshalByRefObject, ILibrary 

您可以在此激活策略,然后添加到您的内核,这将导致其换出ILibrary的情况下,用一个实例在返回之前,使用您的配置文件惯例在备用appdomain中加载。

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); 
       } 
      } 
     } 
    } 

并将其添加到您的内核

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

从那里,你可以简单的实例化你对它们的ILibrary实例和调用方法。他们会用自己的配置加载他们自己的应用程序域。如果你需要通过方法或构造函数传入或传出实例,那么它会变得更加复杂,但如果你不这样做,那么声音就会变好。

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