2013-11-15 81 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(); 
      }