为何类库引用Newtonsoft.Json会导致控制台应用抛文件未找到异常?
我正在开发一个.NET控制台应用,引用了外部类库,简化后的代码结构如下:
LibraryA (LibraryA.dll)
项目文件:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> </Project>
代码:
namespace LibraryA { public class LibraryA { public static int GetAnswer() { return 42; } } }
LibraryB (LibraryB.dll)
项目文件:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> </ItemGroup> <ItemGroup> <Reference Include="LibraryA"> <HintPath>..\LibraryA\bin\Release\netstandard2.0\LibraryA.dll</HintPath> </Reference> </ItemGroup> </Project>
代码:
namespace LibraryB { public class LibraryB { public void UseLibraryA() { _ = LibraryA.LibraryA.GetAnswer(); } public void UseNewtonsoft() { _ = Newtonsoft.Json.JsonConvert.SerializeObject("Hello World!"); } } }
控制台应用
项目文件:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <Reference Include="LibraryB"> <HintPath>..\LibraryB\bin\Release\netstandard2.0\LibraryB.dll</HintPath> </Reference> </ItemGroup> </Project>
代码:
var lib = new LibraryB.LibraryB(); lib.UseLibraryA(); Console.WriteLine("Use Library A."); lib.UseNewtonsoft(); Console.WriteLine("Used Newtonsoft.");
三个项目相互独立:LibraryB通过本地DLL引用LibraryA,通过NuGet添加Newtonsoft.Json作为包依赖;控制台应用仅引用LibraryB的DLL,未添加LibraryA或Newtonsoft.Json的引用。运行控制台应用时,UseLibraryA()可正常执行,但UseNewtonsoft()抛出错误:
Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified.
为什么UseLibraryA()正常,而UseNewtonsoft()执行失败?
1. LibraryA能正常加载的原因
LibraryB通过<Reference>标签以本地DLL的方式引用LibraryA时,编译阶段Visual Studio会自动将LibraryA.dll复制到LibraryB的输出目录(LibraryB/bin/Release/netstandard2.0)。当控制台应用引用LibraryB.dll时,构建工具会将LibraryB输出目录下的所有关联文件(包括LibraryA.dll)复制到控制台应用的输出目录。运行时,CLR会在应用程序基目录(控制台输出目录)中查找依赖的程序集,因此能顺利找到并加载LibraryA.dll。
2. Newtonsoft.Json加载失败的原因
LibraryB使用<PackageReference>引用NuGet包Newtonsoft.Json时,NuGet的依赖管理逻辑是:类库项目不会自动将NuGet包的DLL复制到自身输出目录,而是由最终的可执行项目(这里的控制台应用)负责解析并下载这些依赖包。但你的控制台应用并没有添加Newtonsoft.Json的PackageReference,也没有手动将Newtonsoft.Json.dll复制到控制台输出目录,因此运行时CLR无法找到该程序集,从而抛出加载失败的异常。
简单来说:本地DLL引用会随主类库一起被复制到最终应用的输出目录,而NuGet包依赖需要最终应用显式引用才能被正确加载。
内容的提问来源于stack exchange,提问作者JasonC

