如何替代 nuget 包的依赖项版本

How to override dependency version of a nuget package

提问人:ben yu 提问时间:3/17/2023 最后编辑:ben yu 更新时间:3/19/2023 访问量:422

问:

我有一个 .netstandard2.0 项目,假设它被称为 common,它使用 nuget.org 的 System.Configuration.ConfigurationManager 5.0.0 和 log4net 2.0.15。 此公共项目由项目 A(一个 .net5 项目)使用,也由项目 B(一个 .net Framework 4.6.1 项目)使用。 在 Common 项目中,我使用 System.Configuration.ConfigurationManagerlog4net,如下所示:

<ItemGroup>
  <PackageReference Include="log4net" Version="2.0.15" />
  <PackageReference Include="System.Configuration.ConfigurationManager" Version="5.0.0" />
</ItemGroup>

现在,当log4net尝试初始化时.dll我遇到了System.Configuration.ConfigurationManager的程序集加载问题,因为它需要System.Configuration.ConfigurationManager的4.0.1.0而不是5.0.0

错误消息如下所示:

System.IO.FileNotFoundException:无法加载文件或程序集“System.Configuration.ConfigurationManager,Version=4.0.1.0,Culture=neutral,PublicKeyToken=cc7b13ffcd2ddd51”。系统找不到指定的文件。

如何强制log4net.dll使用System.Configuration.ConfigurationManager 5.0.0.0? 我尝试添加一个log4net.dll.dll,如下所示,但不起作用。log4net 仍尝试加载旧版本的 System.Configuration.ConfigurationManager。除了从源代码重建log4net之外,还有人知道如何解决这个问题吗?

<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="System.Configuration.ConfigurationManager" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
                <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>

我检查了log4net.dll的元数据,它确实使用4.0.1.0版本System.Configuration.ConfigurationManager。我尝试使用上述语法重新绑定,但似乎被忽略了。

要重现此问题,您需要将 A 和 B 的输出文件夹设置为相同:

<OutputPath>$(SolutionDir)$(Configuraiton)$(Platform)</OutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>

另外,我发现如果我只重建A(或重建解决方案,三个项目A,B和Common在同一个解决方案中),然后通过右键单击->属性->详细信息检查输出文件夹中的log4net.dll属性,产品版本显示“2.0.15.0-NET Standard 2.0”。但是,如果我仅重建 B,它会变成“2.0.15.0-.NET 4.5”,在这种情况下,问题就消失了。仅当 log4net.dll 显示“2.0.15.0-NET Standard 2.0”时才会发生程序集加载问题。

C# .NET log4net 程序集加载

评论

1赞 jmcilhinney 3/17/2023
根据 Nuget,log4net 2.0.15 适用于 System.Configuration.ConfigurationManager v4.5.0 或更高版本。可能是其他一些专门需要 v4.0.1 的依赖包吗?不确定这是否真的解决了问题,但最好确切地知道问题是什么依赖项。
0赞 Hank 3/17/2023
目标框架是什么?此外,您通常从不手动滚动程序集绑定重定向。那里有一个问题:publicKeyToken 不正确。它应该是 .cc7b13ffcd2ddd51
0赞 ben yu 3/17/2023
@jmcilhinney log4net 2.0.15 的目标框架版本是 .netstandard2.0。此程序集在 .netstandard2.0 公共程序集中引用,该程序集由 .net 5 项目和 .net framework 4.6.1 项目使用。
0赞 ben yu 3/17/2023
@Hank我仔细检查了我的配置,publicKeyToken 与您的相同。我从某个地方复制的帖子中的那个,这是不正确的。我已经修好了。
0赞 Hank 3/17/2023
我很欣赏为提供更多背景而进行的编辑。似乎还有更多的事情发生,因为我无法用我根据您的新描述创建的代码重现这一点。加入 chat.stackoverflow.com/rooms/252571/,我可以进一步帮助你。

答:

0赞 Hank 3/19/2023 #1

一切终于与您提供的最新信息汇集在一起。

根本问题是建立两个独立的'。NET的实现到同一个文件夹中。这是有原因的。AppendTargetFrameworkToOutputPath

dll 不能依赖于类库,反之亦然。这基本上就是这里发生的事情。构建的输出相互干扰,运行的内容基本上是您最近构建的输出。.NET.NETFramework

当我按照你描述的方式设置我的项目时,我可以重新创建它。
项目A: , ProjectB: , Common: .
net5.0net461netstandard2.0

Build -> Build 。 运行良好,但无法运行。 Build -> Build 。
运行良好,但不能。
ABBABAAB

如果我将这个手卷程序集绑定重定向到 's appconfigB

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
            <assemblyIdentity name="System.Configuration.ConfigurationManager" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
        </dependentAssembly>
    </assemblyBinding>
</runtime>

Build -> Build . Both work, but this is very unreliable.BA

If the assemblies are started via reflection, then you need to be extra careful because you need to make sure the CLR is loading the config files in the same way as it naturally would when starting the EXEs. This is what sets up all the binding redirects (app.config for , for )..NETFrameworkdeps.json.NET

评论

0赞 ben yu 3/19/2023
Thank you very much @Hank. I have a question here, shouldn't be .netstandard compatible with both .net(core) and .net framework? I make the Common project .netstandard, it should be working for both .net(core) and .net framework projects. Isn't the purpose of the .netstandard? I can understand that .net framework project can't be used as a dependency of a .net (core) project. Also log4net says it supports both.
0赞 Hank 3/19/2023
.netstandard is not a platform... it is a standard. It is a common API set that other platforms must implement to be compliant. You can think of netstandard like an and the classes are implemented in either or . It will work for both projects but not when you build to the same folder and that's because the build system puts specific dlls out there depending on what final platform you are building for.interface.NETFrameork.NET
0赞 Hank 3/19/2023
You are also running into this issue: github.com/dotnet/sdk/issues/1791#issuecomment-540985034 because log4net provides a net45 implementation which gets preferred over the netstandard when you build your net46 project.
0赞 patman 10/2/2023
@benyu I think you should give Hank some credit here for his answer. Cheers!