制作支持多框架多架构的LibB nupkg遇依赖加载错误求助
我有一个依赖LibA的类库LibB,其中LibA是依赖静态库NativeLibA的C++/CLI类库。我希望发布同时支持.NET Framework 4.7.2、.NET 8.0以及x86、x64架构的LibB NuGet包。由于LibA作为C++/CLI类库无法编译为NetStandard2.0,因此NuGet包中需要包含四个不同版本的LibA。我已经编写了如下csproj文件用于生成NuGet包:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFrameworks>netstandard2.0</TargetFrameworks> <PackageId>LibB</PackageId> <Title>Library B</Title> <Version>1.2.3.4</Version> <Authors>ACME</Authors> <Company>ACME</Company> <Description>Library B.</Description> <Copyright>Copyright © ACME 2025</Copyright> </PropertyGroup> <ItemGroup> <Reference Include="LibA"> <HintPath>..\LibA\install\$(TargetFramework)\$(Platform)\LibA.dll</HintPath> </Reference> </ItemGroup> <ItemGroup> <!-- .NET Framework 4.7.2 x86 --> <None Include="..\LibA\install\net472\x86\LibA.dll" Pack="true" PackagePath="runtimes\win-x86\net472"/> <!-- .NET Framework 4.7.2 x64 --> <None Include="..\LibA\install\net472\x64\LibA.dll" Pack="true" PackagePath="runtimes\win-x64\net472"/> <!-- .NET Core 8.0 x86 --> <None Include="..\LibA\install\net8.0\x86\LibA.dll" Pack="true" PackagePath="runtimes\win-x86\net8.0"/> <None Include="..\LibA\install\net8.0\x86\Ijwhost.dll" Pack="true" PackagePath="runtimes\win-x86\net8.0"/> <!-- .NET Core 8.0 x64 --> <None Include="..\LibA\install\net8.0\x64\LibA.dll" Pack="true" PackagePath="runtimes\win-x64\net8.0"/> <None Include="..\LibA\install\net8.0\x64\Ijwhost.dll" Pack="true" PackagePath="runtimes\win-x64\net8.0"/> </ItemGroup> </Project>
使用该文件生成NuGet包后,无论搭配何种框架或架构使用,都会出现如下错误:
Could not load file or assembly 'LibA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
in Calculator.Calculator.Add(Int32 a, Int32 b)
in App.Program.Main(String[] args) in C:\Users\Marco\source\repos\multiarch-nuget\Test\App.cs:riga 13
1. 修正NuGet包文件布局
当前的PackagePath不符合.NET运行时自动加载规则,需要调整路径结构,让.NET能根据运行环境自动匹配对应的LibA:
修改后的文件打包配置:
<ItemGroup> <!-- .NET Framework 4.7.2 x86 --> <None Include="..\LibA\install\net472\x86\LibA.dll" Pack="true" PackagePath="runtimes\win-x86\lib\net472"/> <!-- .NET Framework 4.7.2 x64 --> <None Include="..\LibA\install\net472\x64\LibA.dll" Pack="true" PackagePath="runtimes\win-x64\lib\net472"/> <!-- .NET 8.0 x86 --> <None Include="..\LibA\install\net8.0\x86\LibA.dll" Pack="true" PackagePath="runtimes\win-x86\lib\net8.0"/> <None Include="..\LibA\install\net8.0\x86\Ijwhost.dll" Pack="true" PackagePath="runtimes\win-x86\lib\net8.0"/> <!-- .NET 8.0 x64 --> <None Include="..\LibA\install\net8.0\x64\LibA.dll" Pack="true" PackagePath="runtimes\win-x64\lib\net8.0"/> <None Include="..\LibA\install\net8.0\x64\Ijwhost.dll" Pack="true" PackagePath="runtimes\win-x64\lib\net8.0"/> </ItemGroup>
2. 为LibB添加程序集解析逻辑
由于LibB基于NetStandard2.0,无法直接绑定特定架构的LibA,需要手动注册程序集解析事件,根据当前运行环境加载对应版本:
在LibB中添加初始化类:
using System; using System.IO; using System.Reflection; namespace LibB { public static class LibInitializer { static LibInitializer() { AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } private static Assembly? CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { if (!args.Name.StartsWith("LibA,")) return null; // 获取当前运行架构 string arch = Environment.Is64BitProcess ? "x64" : "x86"; // 判断当前运行框架 string frameworkDir = Type.GetType("System.Runtime.Loader.AssemblyLoadContext") != null ? "net8.0" : "net472"; // 拼接LibA的路径 string libPath = Path.Combine(AppContext.BaseDirectory, $"runtimes\\win-{arch}\\lib\\{frameworkDir}\\LibA.dll"); return File.Exists(libPath) ? Assembly.LoadFrom(libPath) : null; } // 确保初始化逻辑被触发 public static void Initialize() {} } }
使用LibB的项目需要在启动时调用初始化:
// 应用入口处添加 LibB.LibInitializer.Initialize();
3. 调整LibB的编译目标(可选但推荐)
将LibB的编译目标从仅NetStandard2.0改为同时支持net472和net8.0,避免跨框架的兼容性问题:
修改csproj中的TargetFrameworks:
<PropertyGroup> <TargetFrameworks>net472;net8.0</TargetFrameworks> <!-- 其他属性保持不变 --> </PropertyGroup>
同时调整LibA的引用路径,适配不同编译目标:
<ItemGroup> <Reference Include="LibA"> <HintPath>..\LibA\install\$(TargetFramework)\$(PlatformTarget)\LibA.dll</HintPath> <Private>false</Private> </Reference> </ItemGroup>
这样编译后会生成对应框架的LibB版本,NuGet包会自动为不同框架分发匹配的LibA引用。
内容的提问来源于stack exchange,提问作者Marco Giglio

