如何解决 NuGet 依赖地狱

How to resolve NuGet dependency hell(如何解决 NuGet 依赖地狱)
本文介绍了如何解决 NuGet 依赖地狱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开发了一个名为 CompanyName.SDK 的库,它必须集成在公司项目 CompanyName.SomeSolution

CompanyName.SDK.dll 必须通过 NuGet 包部署.CompanyName.SDK 包依赖于 3rd 方 NuGet 包.举个很好的例子,让我们以 Unity 为例.当前依赖于 Unityv3.5.1405-prerelease.

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 程序集:v3.5.1405-prerelease via bindingRedirect in app.config.

Project1Project2SDK 中的代码如何使用它们被编码、编译和测试的依赖包的完全需要的版本与?

NOTE1: Unity 只是一个例子,实际情况比 3rdparty 模块依赖于另一个 3rdparty 模块的情况要差 10 倍,而另一个 3rdparty 模块又同时具有 3-4 个版本.

注意 2: 我无法将所有软件包升级到最新版本,因为有些软件包依赖于其他软件包的 not-on-latest-version.

注意 3: 假设依赖包在版本之间有重大变化.这是我问这个问题的真正问题.

注意 4: 我知道问题 关于同一依赖程序集的不同版本之间的冲突,但那里的答案并不能解决问题的根源——他们只是隐藏它.

NOTE5: 承诺的DLL Hell"问题解决方案到底在哪里?它只是从另一个位置重新出现.

注意6:如果您认为使用 GAC 是一种选择,请编写分步指南或给我一些链接.

解决方案

您可以在编译后汇编级别工作以解决此问题...

选项 1

您可以尝试将程序集与 ILMerge

<块引用>

ilmerge/target:winexe/out:SelfContainedProgram.exe Program.exe ClassLibrary1.dll ClassLibrary2.dll

结果将是一个程序集,它是您的项目及其所需依赖项的总和.这会带来一些缺点,比如牺牲单声道支持和丢失程序集标识(名称、版本、文化等),所以当所有要合并的程序集都由您构建时,这是最好的.

所以来了……

选项 2

您可以将依赖项作为资源嵌入到您的项目中,如 这篇文章.以下是相关部分:

<块引用>

在运行时,CLR 将无法找到依赖的 DLL组件,这是一个问题.要解决此问题,当您的应用程序初始化,注册一个回调方法到 AppDomain 的ResolveAssembly 事件.代码应如下所示:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>{String resourceName = "AssemblyLoadingAndReflection."+新的 AssemblyName(args.Name).Name + ".dll";使用 (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {字节[] 组装数据 = 新字节[流.长度];流.Read(assemblyData, 0, assemblyData.Length);返回 Assembly.Load(assemblyData);}};

<块引用>

现在,第一次线程调用一个引用类型的方法一个依赖的 DLL 文件,AssemblyResolve 事件将被引发并且上面显示的回调代码将找到所需的嵌入式 DLL 资源并通过调用 Assembly 的 Load 方法的重载来加载它将 Byte[] 作为参数.

如果我在你的情况下,我认为这是我会使用的选项,牺牲一些初始启动时间.

更新

看看这里.您还可以尝试在每个项目的 app.config 中使用那些 <probing> 标记来定义一个自定义子文件夹,以便在 CLR 搜索程序集时查看.

I develop a library with some functional named CompanyName.SDK which must be integrated in company project CompanyName.SomeSolution

CompanyName.SDK.dll must be deployed via NuGet package. And CompanyName.SDK package has a dependency on 3rd party NuGet packages. For good example, let's take Unity. Current dependency is on v3.5.1405-prerelease of Unity.

CompanyName.SomeSolution.Project1 depends on Unity v2.1.505.2. CompanyName.SomeSolution.Project2 depends on Unity v3.0.1304.1.

Integrating CompanyName.SDK into this solution adds dependency on Unity v3.5.1405-prerelease. Let's take that CompanyName.SomeSolution has one runnable output project CompanyName.SomeSolution.Application that depends on two above and on CompanyName.SDK

And here problems begin. All Unity assemblies has equal names in all packages without version specifier. And in the target folder it will be only one version of Unity assemblies: v3.5.1405-prerelease via bindingRedirect in app.config.

How can code in Project1, Project2 and SDK use exactly needed versions of dependent packages they were coded, compiled and tested with?

NOTE1: Unity is just an example, real situation is 10 times worse with 3rdparty modules dependent on another 3rdparty modules which in turn has 3-4 versions simultaneously.

NOTE2: I cannot upgrade all packages to their latest versions because there are packages that have dependency not-on-latest-version of another packages.

NOTE3: Suppose dependent packages has breaking changes between versions. It is the real problem why I'm asking this question.

NOTE4: I know about question about conflicts between different versions of the same dependent assembly but answers there does not solve the root of a problem - they just hide it.

NOTE5: Where the hell is that promised "DLL Hell" problem solution? It is just reappearing from another position.

NOTE6: If you think that using GAC is somehow an option then write step-by-step guide please or give me some link.

解决方案

You can work at post-compilation assembly level to solve this issue with...

Option 1

You could try merging the assemblies with ILMerge

ilmerge /target:winexe /out:SelfContainedProgram.exe Program.exe ClassLibrary1.dll ClassLibrary2.dll

The result will be an assembly that is the sum of your project and its required dependencies. This comes with some drawbacks, like sacrificing mono support and losing assembly identities (name, version, culture etc.), so this is best when all the assemblies to merge are built by you.

So here comes...

Option 2

You can instead embed the dependencies as resources within your projects as described in this article. Here is the relevant part:

At run-time, the CLR won’t be able to find the dependent DLL assemblies, which is a problem. To fix this, when your application initializes, register a callback method with the AppDomain’s ResolveAssembly event. The code should look something like this:

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

   }

};

Now, the first time a thread calls a method that references a type in a dependent DLL file, the AssemblyResolve event will be raised and the callback code shown above will find the embedded DLL resource desired and load it by calling an overload of Assembly’s Load method that takes a Byte[] as an argument.

I think this is the option i would use if I were in your shoes, sacrificing some initial startup time.

Update

Have a look here. You could also try using those <probing> tags in each project's app.config to define a custom sub-folder to look in when the CLR searches for assemblies.

这篇关于如何解决 NuGet 依赖地狱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)