如何在使用reflection加载的程序集中使用Castle.Windsor

假设我有一个库Lib.dll,它使用Castle.Windsor初始化其服务。

我有一个主应用程序App.exe,它使用reflection在运行时加载Lib.dll。 App.exe事先并不知道Lib.dll的位置,它只在运行时才知道。

在这种情况下,当App.exe加载Lib.dll和Lib.dll初始化其服务时,会抛出System.TypeInitializationExceptionexception,因为Castle.Windsor无法找到服务类型。

Castle.MicroKernel.SubSystems.Conversion.ConverterException: Could not convert from 'Lib.TheServiceClass' to System.Type - Maybe type could not be found at Castle.MicroKernel.SubSystems.Conversion.TypeNameConverter.PerformConversion(String value, Type targetType) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\SubSystems\Conversion\TypeNameConverter.cs:line 91 at Castle.MicroKernel.SubSystems.Conversion.DefaultConversionManager.PerformConversion(String value, Type targetType) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\SubSystems\Conversion\DefaultConversionManager.cs:line 134 at Castle.MicroKernel.SubSystems.Conversion.DefaultConversionManager.PerformConversion[TTarget](String value) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\SubSystems\Conversion\DefaultConversionManager.cs:line 162 at Castle.Windsor.Installer.DefaultComponentInstaller.SetUpComponents(IConfiguration[] configurations, IWindsorContainer container, IConversionManager converter) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Windsor\Installer\DefaultComponentInstaller.cs:line 196 at Castle.Windsor.Installer.DefaultComponentInstaller.SetUp(IWindsorContainer container, IConfigurationStore store) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Windsor\Installer\DefaultComponentInstaller.cs:line 52 at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers, DefaultComponentInstaller scope) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Windsor\WindsorContainer.cs:line 327 at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Windsor\WindsorContainer.cs:line 674 

显然Castle无法找到我的服务类,因为它位于Lib.dll中,不在App.exe的目录中。 当我将Lib.dll复制到App.exe目录时,问题就消失了,但不得不复制它,这不是我们想要的。

那么我的Lib.dll中的代码如何告诉Castle.Windsor将类加载到正确的位置? (在Lib.dll位置而不是在App.exe位置)

您可以尝试通过AssemblyResolve事件在代码中加载未解析的程序集

 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { string typeToLoad = args.Name; string myPath = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName; return Assembly.LoadFile(...); //or return Assembly.GetExecutingAssembly() etc. }; 

您可能会考虑将插件加载到一个单独的AppDomain中,使用不同的私有路径,查看AppDomainSetup 。 当然,你有一个缺点,你需要为你的插件一个单独的应用程序域,但有时这被认为是一个很好的做法。

如果App.exe没有为您提供Castle Windsor的容器实例来配置您的服务,您可能无法以简单而优雅的方式执行此操作。

如果没有直接暴露,也许您可​​以使用服务定位器访问它? 或者使用App.exe程序集上的reflection自己找到它?

最好的解决方案是,如果App.exe中的代码调用库中的特定方法(即它可以查找特定的接口实现,如IModuleInitializer或其他东西,创建它的实例并调用某种Initialize方法将容器实例传递给您的代码)。

您也可以考虑像MEF这样的可扩展性框架,但这可能有点矫枉过正,并对App.exe产生重大影响。