我开发了一个名为CompanyName.SDK的函数库,它必须集成到公司项目CompanyName.SomeSolution中。
CompanyName.SDK.dll必须通过NuGet包部署。CompanyName.SDK包依赖于第三方NuGet包。举个好例子,让我们以Unity为例。当前依赖于v3.5.1405-prerelease of Unity。
CompanyName.SomeSolution.Project1依赖于Unity v2.1.505.2。CompanyName.SomeSolution.Project2依赖于Unity v3.0.1304.1。
将CompanyName.SDK集成到此解决方案中会增加对Unity v3.5.1405-prerelease的依赖。假设CompanyName.SomeSolution有一个可运行的输出项目CompanyName.SomeSolution.Application,它依赖于上面的两个和CompanyName.SDK
现在问题开始了。所有Unity程序集在没有版本说明符的所有包中都具有相同的名称。在目标文件夹中,它将仅是Unity程序集的一个版本:通过bindingRedirect在app.config中的v3.5.1405-prerelease。
Project1**,** Project2 和 SDK 中的代码如何使用经过编码、编译和测试的依赖包的精确版本?
NOTE1:Unity只是一个例子,实际情况要糟糕10倍,3 3rdparty模块依赖于另一个3 3rdparty模块,而后者又同时有3-4个版本。
NOTE2:我不能将所有的软件包升级到它们的最新版本,因为有些包依赖于其他软件包的最新版本。
NOTE3:假设依赖包在不同版本之间发生了破坏性的更改。这才是我问这个问题的真正原因。
NOTE4:我知道关于同一依赖程序集的不同版本之间的冲突问题,但答案并不能解决问题的根源--他们只是把它隐藏起来。
NOTE5:承诺的"DLL地狱“问题解决方案到底在哪里?它只是从另一个位置重新出现。
NOTE6:如果你认为使用GAC是一种选择,那么请一步一步地编写指南,或者给我一些链接。
发布于 2015-09-28 11:59:32
Unity包不是一个很好的例子,因为您应该只在一个名为成分根的地方使用它。Composition Root应该尽可能接近应用程序入口点。在您的示例中,它是CompanyName.SomeSolution.Application
除此之外,我现在工作的地方,也出现了同样的问题。据我所见,这个问题通常是由横切的问题引起的,比如伐木。您可以应用的解决方案是将第三方依赖项转换为第一方依赖项。您可以通过为这些概念引入抽象来做到这一点。实际上,这样做还有其他好处,比如:
CompanyName.SDK的每个客户端真的需要Unity依赖?)因此,让我们以一个虚构的.NET Logging库为例:
CompanyName.SDK.dll依赖于.NET Logging 3.0
CompanyName.SomeSolution.Project1依赖于.NET Logging 2.0
CompanyName.SomeSolution.Project2依赖于.NET Logging 1.0
.NET Logging的不同版本之间会有不同的变化。
通过引入ILogger接口,您可以创建自己的第三方依赖关系:
public interface ILogger
{
void LogWarning();
void LogError();
void LogInfo();
} CompanyName.SomeSolution.Project1和CompanyName.SomeSolution.Project2应该使用ILogger接口。它们依赖于ILogger接口、第三方依赖关系.现在,您将这个.NET Logging库保存在一个地方之后,执行更新很容易,因为您必须在一个地方进行更新。另外,中断不同版本之间的更改不再是一个问题,因为使用了一个版本的.NET Logging库。
ILogger接口的实际实现应该在不同的程序集中,并且应该是您引用.NET Logging库的地方。在编写应用程序的CompanyName.SomeSolution.Application中,您现在应该将ILogger抽象映射到具体实现。
我们正在使用这种方法,我们也使用NuGet来分发我们的抽象和实现。不幸的是,版本问题可能会出现在您自己的包中。为了避免这种问题,将语义版本化应用于您通过NuGet为公司部署的包中。如果您的代码库中有一些通过NuGet分发的更改,那么您应该更改通过NuGet分发的所有包。例如,我们在本地NuGet服务器中拥有:
DomainModelServices.Implementation.SomeFancyMessagingLibrary (引用DomainModel和SomeFancyMessagingLibrary)此包之间的版本是同步的,如果版本在DomainModel中更改,则相同版本在Services.Implementation.SomeFancyMessagingLibrary中。如果我们的应用程序需要更新我们的内部包,那么所有依赖项都会更新到相同的版本。
发布于 2015-09-28 12:32:50
您可以在编译后的程序集级别使用.
备选案文1
您可以尝试将程序集与ILMerge合并。
ilmerge /target:winexe /out:SelfContainedProgram.exe Program.exe ClassLibrary2.dll 1.dll ClassLibrary2.dll 2.dll
结果将是一个程序集,它是项目及其所需依赖项的总和。这会带来一些缺点,比如牺牲单点支持和丢失程序集标识(名称、版本、区域性等),所以当所有要合并的程序集都由您构建时,这是最好的。
所以来了..。
选项2
您可以将依赖项作为资源嵌入到项目中,如这篇文章所述。以下是有关部分:
在运行时,CLR将无法找到依赖的DLL程序集,这是一个问题.要解决这个问题,当您的应用程序初始化时,使用AppDomain的ResolveAssembly事件注册一个回调方法。代码应该如下所示:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};现在,当线程第一次调用引用依赖DLL文件中的类型的方法时,将引发事件,上面所示的回调代码将找到所需的嵌入资源,并通过调用以Byte[]为参数的程序集加载方法的重载来加载该资源。
我认为,如果我处于你的位置,我会选择这一选择,而牺牲一些最初的启动时间。
更新
看看这里。您还可以尝试在每个项目的<probing>中使用这些app.config标记来定义自定义子文件夹,以便在CLR搜索程序集时查找。
https://stackoverflow.com/questions/32739610
复制相似问题