假设我有一个库Lib.dll,它使用Castle。温莎初始化服务。
我有一个主应用程序App.exe,它在运行时使用反射加载Lib.dll。App.exe事先不知道Lib.dll的位置,它只在运行时知道。
在这种情况下,当App.exe加载Lib.dll和Lib.dll初始化它的服务时,一个System. exeTypeInitializationException异常被抛出,因为Castle。
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.CodeCastle.WindsorsrcCastle.WindsorMicroKernelSubSystemsConversionTypeNameConverter.cs:line 91
at Castle.MicroKernel.SubSystems.Conversion.DefaultConversionManager.PerformConversion(String value, Type targetType) in e:OSS.CodeCastle.WindsorsrcCastle.WindsorMicroKernelSubSystemsConversionDefaultConversionManager.cs:line 134
at Castle.MicroKernel.SubSystems.Conversion.DefaultConversionManager.PerformConversion[TTarget](String value) in e:OSS.CodeCastle.WindsorsrcCastle.WindsorMicroKernelSubSystemsConversionDefaultConversionManager.cs:line 162
at Castle.Windsor.Installer.DefaultComponentInstaller.SetUpComponents(IConfiguration[] configurations, IWindsorContainer container, IConversionManager converter) in e:OSS.CodeCastle.WindsorsrcCastle.WindsorWindsorInstallerDefaultComponentInstaller.cs:line 196
at Castle.Windsor.Installer.DefaultComponentInstaller.SetUp(IWindsorContainer container, IConfigurationStore store) in e:OSS.CodeCastle.WindsorsrcCastle.WindsorWindsorInstallerDefaultComponentInstaller.cs:line 52
at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers, DefaultComponentInstaller scope) in e:OSS.CodeCastle.WindsorsrcCastle.WindsorWindsorWindsorContainer.cs:line 327
at Castle.Windsor.WindsorContainer.Install(IWindsorInstaller[] installers) in e:OSS.CodeCastle.WindsorsrcCastle.WindsorWindsorWindsorContainer.cs:line 674
显然城堡找不到我的服务类,因为它在Lib.dll中,不在App.exe的目录中。当我复制Lib.dll到App.exe目录时,问题消失了,但必须复制这不是我们想要的。
那么我在Lib.dll中的代码如何告诉Castle。温莎加载类在正确的位置?(在Lib.dll位置而不是在App.exe位置)
您可以尝试通过AssemblyResolve event
在代码中加载未解析的程序集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程序集上使用反射来找到它?
最好的解决方案是如果App.exe中的代码调用库中的特定方法(即它可以寻找特定的接口实现,如IModuleInitializer
或其他东西,创建它的实例并调用某种Initialize
方法将容器实例传递给您的代码)。
你也可以考虑像MEF这样的可扩展性框架,但这可能有点过度,并对App.exe产生很大的影响。