我发现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.A
和MyLibrary.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 build
,dotnet 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 publish
docker 带来了麻烦,或者我的流程中是否存在一些缺陷(它适用于所有其他服务)。可能是什么问题?
我可以看到由以及所有其他Newtonsoft.Json.dll
文件生成的文件,这些文件应该被正确复制到 Docker 映像中。dotnet publish
MassTransit.AmazonSqsTransport
另外,如果我打开,.deps.json
我可以看到所有对Newtonsoft.Json
are 的引用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.2
和9.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.0
和Microsoft.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*
最后更新:问题解决了。请参阅我自己的回复,其中有关如何正确解决此类问题以及我如何通过确保我的测试项目(使用不同版本的库)不发布工件并覆盖所需的依赖程序集来解决它的信息。