7

我发现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

当将应用程序作为 Docker 容器运行时,我想知道为什么会发生这种情况以及为什么依赖项管理无法顺利运行。

我使用 .NET 5

我有一个MyLibrary.A明确Newtonsoft.Json 13.0.1用于序列化和反序列化 json 的库。

我有一个MyLibrary.B包装库的不同MassTransit.AmazonSQS库。这个 MassTransit 库也使用 Newtonsoft.Json,但可能是不同的版本。如果我没有做任何明确的事情,似乎 MassTransit 依赖项显示Newtonsoft.Json 11.0.2. 如果在MyLibrary.B我明确添加Newtonsoft.Json 13.0.1,即使我没有明确使用它,那么 MassTransit 似乎很高兴使用这个最新的Newtonsoft.Json 13.0.1

现在,我有一个MyApp使用MyLibrary.AMyLibrary.B. 它在本地运行良好,但我使用 CI/CD 服务器生成 Docker 映像。

现在我将这个 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.

它抱怨甚至不存在的版本。没有 13.0.0.0,这个库好像是从 12.0.3 到 13.0.1。

我现在正在浏览我所有的库,并确保它们都Newtonsoft.Json 13.0.1明确使用。当我检测到其中一些使用依赖于Newtonsoft.Json我的第三方时,我明确添加了相同的版本,这样我就可以在任何地方获得该13.0.1版本。


更新 1:我的解决方法不起作用。我不知道还能尝试什么。

我什至已经Newtonsoft.Json 13.0.1明确地将它添加到我的 web 应用程序中,所以我希望至少在运行时它可以使用。

此外,如果我将我的网络作为标准红隼 AspNetCore 应用程序 (.NET 5) 在本地运行,它会正确启动。到底是怎么回事?为什么我的 docker 容器抱怨Newtonsoft.Json 13.0.0.0找不到?

这些是尝试作为 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:我决定Newtonsoft.Json 11.0.2在我的库中到处匹配 MassTransit 依赖项。 问题依然存在。 现在的错误是

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.

我不明白。我所有的依赖Newtonsoft.Json现在都11.0.2在抱怨。我将在 Web 应用程序主程序集中显式添加此版本(即使我不直接需要它),看看它是否仍然抱怨它。


更新 3Newtonsoft.Json 11.0.2 :在添加到我的所有库并在我的 Web 应用程序程序集中添加相同的依赖项作为依赖项之后仍然存在同样的问题。

根据克里斯的评论,我现在有一个.dockerignore.

bin/
obj/

我构建映像的方式是,使用 GitLab,使用标准dotnet builddotnet publish然后将发布文件夹的所有内容复制到 Docker 映像中,如下所示

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

更具体地说,我使用 Kaniko,这是我的.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 publishdocker 带来了麻烦,或者我的流程中是否存在一些缺陷(它适用于所有其他服务)。可能是什么问题?

我可以看到由以及所有其他Newtonsoft.Json.dll文件生成的文件,这些文件应该被正确复制到 Docker 映像中。dotnet publishMassTransit.AmazonSqsTransport

另外,如果我打开,.deps.json我可以看到所有对Newtonsoft.Jsonare 的引用11.0.2,所以不再有版本冲突(我想!)。

我没主意了。


更新 4 我刚刚清除了所有本地 nuget 包(使用 Ubuntu)

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.

有趣的是,当我在项目之后恢复依赖项时

dotnet restore

我可以看到/home/diegosasw/.nuget/packages/newtonsoft.json 有版本11.0.29.0.1

所以我猜想某处某个子依赖项正在使用 Newtonsoft 9.0.1,即使Newtonsoft.Json 9.0.1在我的*.deps.json生成中没有 a 的痕迹,dotnet publish我想知道这是否与我的问题有关,也许是因为那是程序集加载并且11被忽略?


更新 5 我刚刚看到Newtonsoft.Json 9.0.1一些测试项目正在使用它,因为我可以在coverlet.collector.deps.json下面coverlet.core 1.0.0Microsoft.Extensions.DependencyModel 2.1.0

我想这不是我问题的原因。

此外,我已验证docker export $(docker ps -lq) -o foo.tar容器具有Newtonsoft.Json.dll.

我想了解为什么会发生这种情况,并了解如何更好地解决此类问题。


更新 6(10 月 4 日)

我认为问题不在于 Docker。我认为问题可能与dotnet publish我遗漏或做错的事情有关。

我把 Docker 留在了外面,因为我没有发现任何问题。我试图简单地做一个

dotnet publish -c Release -o publish

并在该发布文件夹中执行应用程序dotnet MyCompany.ItgService.dll以重现异常。

但是在发布之前,当我使用

dotnet run -c Release --project src/Rubiko.ItgService

我没有得到那个例外。

有关完整详细信息、跟踪、树结构等,请参阅https://github.com/dotnet/sdk/issues/21716 。

概括

问题是:

  • 为什么dotnet publish似乎没有产生我的应用程序运行所需的一切?

  • 为什么它在运行时抱怨存在的程序集?

    $ ls publish/ | grep Newtonsoft
    Newtonsoft.Json.Bson.dll*
    Newtonsoft.Json.dll*
    

最后更新:问题解决了。请参阅我自己的回复,其中有关如何正确解决此类问题以及我如何通过确保我的测试项目(使用不同版本的库)不发布工件并覆盖所需的依赖程序集来解决它的信息。

4

2 回答 2

6

我解开了这个谜。它与 Docker 无关。这有点关系,dotnet publish但 SDK 运行良好。

正如最初所怀疑的那样,问题在于版本冲突。与我一起发布时,dotnet publish -c Release -o publish我可以看到Newtonsoft.Json.dll那里。但以下让我怀疑

ls publish/ -al | grep Newtonsoft
-rwxrw-r-- 1 diegosasw  89K mar 22  2017 Newtonsoft.Json.Bson.dll*
-rwxrw-r-- 1 diegosasw 641K mar 24  2018 Newtonsoft.Json.dll*

对于那个版本来说,2018 年似乎有点老了。如果..发布的程序集毕竟Newtonsoft.Json不是版本怎么办?11.0.2

我更新了我的所有库以匹配 MassTransit 依赖项,Newtonsoft 11.0.2但我在 Update 4 上的发现让我认为还有一些其他项目间接依赖于Newtonsoft.Json 9.0.1,这就是为什么我可以看到 nuget 包在本地缓存的原因。

如果以某种方式发布的程序集不是预期的,Newtonsoft.Json 11.0.2而是Newtonsoft.Json 9.0.1,则在抱怨找不到程序集时该错误是有意义的Newtonsoft.Json 11.0.2

答对了!

我安装exiftool在我的 Ubuntu 中以检查 dll 和 exe 版本。

sudo apt install libimage-exiftool-perl

我运行以下

$ exiftool publish/Newtonsoft.Json.dll
ExifTool Version Number         : 11.88
File Name                       : Newtonsoft.Json.dll
Directory                       : publish
File Size                       : 465 kB
File Modification Date/Time     : 2021:07:19 19:52:18+02:00
File Access Date/Time           : 2021:10:04 12:53:14+02:00
File Inode Change Date/Time     : 2021:10:04 12:44:39+02:00
File Permissions                : rwxrw-r--
File Type                       : Win32 DLL
File Type Extension             : dll
MIME Type                       : application/octet-stream
Machine Type                    : Intel 386 or later, and compatibles
Time Stamp                      : 2016:06:13 13:05:00+02:00
Image File Characteristics      : Executable, Large address aware, DLL
PE Type                         : PE32
Linker Version                  : 48.0
Code Size                       : 465920
Initialized Data Size           : 2048
Uninitialized Data Size         : 0
Entry Point                     : 0x738b6
OS Version                      : 4.0
Image Version                   : 0.0
Subsystem Version               : 4.0
Subsystem                       : Windows command line
File Version Number             : 9.0.1.19813
Product Version Number          : 9.0.1.0
File Flags Mask                 : 0x003f
File Flags                      : (none)
File OS                         : Win32
Object File Type                : Dynamic link library
File Subtype                    : 0
Language Code                   : Neutral
Character Set                   : Unicode
Comments                        : Json.NET is a popular high-performance JSON framework for .NET
Company Name                    : Newtonsoft
File Description                : Json.NET .NET Standard 1.0
File Version                    : 9.0.1.19813
Internal Name                   : Newtonsoft.Json.dll
Legal Copyright                 : Copyright © James Newton-King 2008
Legal Trademarks                : 
Original File Name              : Newtonsoft.Json.dll
Product Name                    : Json.NET
Product Version                 : 9.0.1
Assembly Version                : 9.0.0.0

如您所见,已发布的程序集是Newtonsoft.Json 9.0.1. 我感到一阵解脱。

我去了我的测试项目并将以下内容添加到*.csproj

<IsPublishable>false</IsPublishable>

rm -rd publish
dotnet publish -c Release -o publish

关键时刻

$ exiftool publish/Newtonsoft.Json.dll
ExifTool Version Number         : 11.88
File Name                       : Newtonsoft.Json.dll
Directory                       : publish
File Size                       : 641 kB
File Modification Date/Time     : 2018:03:24 18:44:14+01:00
File Access Date/Time           : 2021:10:04 12:44:38+02:00
File Inode Change Date/Time     : 2021:10:04 12:57:29+02:00
File Permissions                : rwxrw-r--
File Type                       : Win32 DLL
File Type Extension             : dll
MIME Type                       : application/octet-stream
Machine Type                    : Intel 386 or later, and compatibles
Time Stamp                      : 2098:12:14 20:33:48+01:00
Image File Characteristics      : Executable, Large address aware, DLL
PE Type                         : PE32
Linker Version                  : 48.0
Code Size                       : 653824
Initialized Data Size           : 2048
Uninitialized Data Size         : 0
Entry Point                     : 0xa16b6
OS Version                      : 4.0
Image Version                   : 0.0
Subsystem Version               : 4.0
Subsystem                       : Windows command line
File Version Number             : 11.0.2.21924
Product Version Number          : 11.0.2.0
File Flags Mask                 : 0x003f
File Flags                      : (none)
File OS                         : Win32
Object File Type                : Dynamic link library
File Subtype                    : 0
Language Code                   : Neutral
Character Set                   : Unicode
Comments                        : Json.NET is a popular high-performance JSON framework for .NET
Company Name                    : Newtonsoft
File Description                : Json.NET .NET Standard 2.0
File Version                    : 11.0.2.21924
Internal Name                   : Newtonsoft.Json.dll
Legal Copyright                 : Copyright © James Newton-King 2008
Legal Trademarks                : 
Original File Name              : Newtonsoft.Json.dll
Product Name                    : Json.NET
Product Version                 : 11.0.2
Assembly Version                : 11.0.0.0

现在发布的程序集是预期的11.0.2

我验证从发布文件夹运行我的应用程序现在可以正常工作!

cd publish
dotnet MyCompany.ItgService.dll
于 2021-10-04T10:59:45.127 回答
2

只需使用 MassTransit 所依赖的版本,它比 v13 早得多。在没有正确程序集重定向的情况下升级过去可能会导致您的问题。

于 2021-10-01T16:29:58.743 回答