You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 5项目dotnet publish后Newtonsoft.Json加载失败问题排查

.NET 5 Newtonsoft.Json 程序集加载异常排查记录

在.NET 5环境下开发项目时遇到Newtonsoft.Json程序集加载异常,具体场景为:将应用打包为Docker容器运行时,Newtonsoft.Json库抛出如下错误:

System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified

项目依赖结构

  • 类库MyLibrary.A显式引用Newtonsoft.Json 13.0.1实现JSON序列化/反序列化功能
  • 类库MyLibrary.B封装了MassTransit.AmazonSQS库,该MassTransit库默认依赖Newtonsoft.Json 11.0.2,若在MyLibrary.B中显式引用Newtonsoft.Json 13.0.1,MassTransit可正常适配该高版本
  • 上层Web应用MyApp同时依赖MyLibrary.A和MyLibrary.B,本地作为Kestrel AspNetCore应用运行正常,但通过CI/CD生成Docker镜像后,本地用Docker Compose启动容器时抛出如下错误:
Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified.

注:错误提示找不到的Newtonsoft.Json 13.0.0.0版本实际不存在,该库的版本是从12.0.3直接迭代到13.0.1。


更新1:统一版本方案无效

尝试全项目统一显式引用Newtonsoft.Json 13.0.1,甚至直接在Web应用项目中添加该版本引用,问题仍未解决。Docker运行的完整错误堆栈如下:

docker run -p 8080:80 \
>     -e ASPNETCORE_ENVIRONMENT=Production \
>     registry.gitlab.com/sample/foo-integration-service:latest
Unable to find image 'registry.gitlab.com/sample/foo-integration-service:latest' locally
latest: Pulling from sample/foo-integration-service
07aded7c29c6: Pull complete 
97aff7269a5a: Pull complete 
633b89d569a5: Pull complete 
bd0e639a2ac9: Pull complete 
a9a5571a369e: Pull complete 
9569d825ee3a: Pull complete 
Digest: sha256:5499b40392512f1731890ccf1ee13507769b733ee2f30c95d281f0550f7a892e
Status: Downloaded newer image for registry.gitlab.com/sample/foo-integration-service:latest
Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified.

File name: 'Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at foo.ItgService.Program.Main(String[] args) in /builds/sample/foo-integration-service/src/foo.ItgService/Program.cs:line 10

更新2:匹配MassTransit依赖版本仍无效

将全项目的Newtonsoft.Json版本统一为MassTransit依赖的11.0.2,错误变为:

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified.

所有依赖已统一为11.0.2仍报错,将该版本显式添加到Web应用主程序集依赖中,问题依旧。


更新3:添加.dockerignore后仍未解决

添加了.dockerignore文件,内容如下:

bin/
obj/

使用GitLab+Kaniko构建镜像,流程为先执行dotnet build、dotnet publish,再将publish目录内容复制到Docker镜像中,Dockerfile内容如下:

FROM mcr.microsoft.com/dotnet/aspnet:5.0
COPY publish/ .
EXPOSE 80
ENTRYPOINT ["dotnet", "MyCompany.ItgService.dll"]

对应的.gitlab-ci.yml配置如下:

image: mcr.microsoft.com/dotnet/sdk:5.0

variables:
  GIT_DEPTH: 1000
  PUBLISH_OUTPUT_DIR: publish
  ENTRYPOINT_DLL: ReplaceMe.dll
  CLUSTER_NAME: ReplaceMe
  SERVICE_NAME: ReplaceMe

stages:
  - build
  - test
  - publish
  - delivery

build:
  stage: build
  script:
    - dotnet restore --no-cache --force
    - dotnet build --configuration Release --no-restore
  artifacts:
    paths:
    - test
    expire_in: 8 hour
  rules:
    - if: $CI_COMMIT_TAG
      when: never  
    - when: always

test:
  stage: test
  services:
    - name: localstack/localstack:0.12.17.5
      alias: localstack
  variables:
    # Localstack with SNS and SQS
    AWS_DEFAULT_REGION: "us-east-1"
    EDGE_PORT: "4566"
    SERVICES: "sns,sqs"
  before_script:
    - rounds=10;
      while [ $rounds -gt 0 ]; do
        curl http://localstack:4566 && echo OK && break || echo FAIL
        rounds=$rounds - 1;
        sleep 5;
      done;
  script: dotnet test --blame --configuration Release
  rules:
    - if: $CI_COMMIT_TAG
      when: never  
    - exists:
      - test/**/*Tests.csproj

publish:
  stage: publish
  before_script:
    - export PATH=$PATH:/root/.dotnet/tools
    - dotnet tool install --global GitVersion.Tool --version 5.7.0
    - dotnet gitversion
    - SEMVER=$(dotnet gitversion -showvariable semver)
    - mkdir version
    - echo "${SEMVER}" > ./version/semver
    - APP_VERSION=$(cat ./version/semver)
  script:
    - dotnet publish -c Release -o $PUBLISH_OUTPUT_DIR -p:Version=$APP_VERSION
  artifacts:
    paths: 
      - $PUBLISH_OUTPUT_DIR/
      - version/
    expire_in: 8 hour
  rules:
    - if: $CI_COMMIT_TAG
      when: never  
    - when: always

container_registry:
  stage: delivery
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  before_script:
    - IMAGE_TAG=$(cat ./version/semver)
    - echo "bin/" > $CI_PROJECT_DIR/.dockerignore
    - echo "obj/" > $CI_PROJECT_DIR/.dockerignore
    - echo "FROM mcr.microsoft.com/dotnet/aspnet:5.0" > $CI_PROJECT_DIR/Dockerfile
    - echo "COPY $PUBLISH_OUTPUT_DIR/ ." >> $CI_PROJECT_DIR/Dockerfile
    - echo "EXPOSE 80" >> $CI_PROJECT_DIR/Dockerfile
    - echo "ENTRYPOINT [\"dotnet\", \"$ENTRYPOINT_DLL\"]" >> $CI_PROJECT_DIR/Dockerfile
    - cat $CI_PROJECT_DIR/Dockerfile
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - cat /kaniko/.docker/config.json
  script:
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:latest --destination $CI_REGISTRY_IMAGE:$IMAGE_TAG
  rules:
    - if: $CI_COMMIT_TAG
      when: never
    - when: always

已确认dotnet publish生成的目录中存在Newtonsoft.Json.dll,且.deps.json中所有Newtonsoft.Json引用均为11.0.2,无版本冲突,该构建流程对其他服务均正常。


更新4:清理NuGet缓存未解决

清理了本地所有NuGet缓存,命令如下:

dotnet nuget locals all --clear
Clearing NuGet HTTP cache: /home/diegosasw/.local/share/NuGet/v3-cache
Clearing NuGet global packages folder: /home/diegosasw/.nuget/packages/
Clearing NuGet Temp cache: /tmp/NuGetScratch
Clearing NuGet plugins cache: /home/diegosasw/.local/share/NuGet/plugins-cache
Local resources cleared.

恢复依赖后发现NuGet缓存中存在Newtonsoft.Json 9.0.1版本,后续排查确认该版本是测试项目的依赖,来自coverlet.collector,不影响主程序。通过docker export命令也验证了容器内确实存在Newtonsoft.Json.dll文件。


更新6:确认问题与Docker无关,出在dotnet publish环节

排除Docker影响,单独执行dotnet publish -c Release -o publish后直接运行publish目录的程序可复现异常,但执行dotnet run -c Release --project src/Rubiko.ItgService运行正常。

核心疑问

  1. 为什么dotnet publish没有生成应用运行所需的全部依赖?
  2. 为什么运行时会提示已存在的程序集找不到?
$ ls publish/ | grep Newtonsoft
Newtonsoft.Json.Bson.dll*
Newtonsoft.Json.dll*

最终结论

问题已解决,根因是使用了不同版本Newtonsoft.Json的测试项目也发布了产物,覆盖了正确的依赖程序集,确保测试项目不发布产物即可解决。


内容的提问来源于stack exchange,提问作者diegosasw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 19:36:04