C# 无法加载类型';Hangfire.HangfireEndpointRouteBuilderExtensions';来自组件';当作为docker容器运行时,Hangfire.AspNetCore
我无法使用使用Hangfire的.NET5应用程序运行docker容器。 在当地,一切都很好。 但随后我使用Azure管道构建映像,保存在Azure容器注册表中,并尝试在本地运行它。我得到的例外是:C# 无法加载类型';Hangfire.HangfireEndpointRouteBuilderExtensions';来自组件';当作为docker容器运行时,Hangfire.AspNetCore,c#,docker,containers,hangfire,C#,Docker,Containers,Hangfire,我无法使用使用Hangfire的.NET5应用程序运行docker容器。 在当地,一切都很好。 但随后我使用Azure管道构建映像,保存在Azure容器注册表中,并尝试在本地运行它。我得到的例外是: Starting app for environment Production crit: Microsoft.AspNetCore.Hosting.Diagnostics[6] Application startup exception System.TypeLoadExc
Starting app for environment Production
crit: Microsoft.AspNetCore.Hosting.Diagnostics[6]
Application startup exception
System.TypeLoadException: Could not load type 'Hangfire.HangfireEndpointRouteBuilderExtensions' from assembly 'Hangfire.AspNetCore, Version=1.7.18.0, Culture=neutral, PublicKeyToken=null'.
at MyCompany.Platform.Scheduler.WebApi.Startup.<>c.<Configure>b__5_1(IEndpointRouteBuilder endpoints)
at Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints(IApplicationBuilder builder, Action`1 configure)
at MyCompany.Platform.Scheduler.WebApi.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in /home/vsts/work/1/s/src/WebApi/Startup.cs:line 56
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Unhandled exception. System.TypeLoadException: Could not load type 'Hangfire.HangfireEndpointRouteBuilderExtensions' from assembly 'Hangfire.AspNetCore, Version=1.7.18.0, Culture=neutral, PublicKeyToken=null'.
at MyCompany.Platform.Scheduler.WebApi.Startup.<>c.<Configure>b__5_1(IEndpointRouteBuilder endpoints)
at Microsoft.AspNetCore.Builder.EndpointRoutingApplicationBuilderExtensions.UseEndpoints(IApplicationBuilder builder, Action`1 configure)
at MyCompany.Platform.Scheduler.WebApi.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in /home/vsts/work/1/s/src/WebApi/Startup.cs:line 56
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
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 MyCompany.Platform.Scheduler.WebApi.Program.Main(String[] args) in /home/vsts/work/1/s/src/WebApi/Program.cs:line 10
这是我的天蓝色管道
trigger:
- master
pool:
vmImage: ubuntu-20.04
variables:
imageName: 'my-scheduler'
stages:
- stage:
displayName: 'Build'
jobs:
- job: 'Build'
displayName: 'Restore and compile'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core sdk 5.0.x'
inputs:
version: '5.0.x'
includePreviewVersions: true
- script: dotnet restore --no-cache --force
displayName: 'Restore dependencies'
- script: dotnet build --configuration Release --no-restore
displayName: 'Build with Release Configuration'
- script: dotnet vstest test/*FunctionalTests/bin/Release/**/*FunctionalTests.dll
displayName: 'Run functional tests'
- script: dotnet publish -c Release -o out
displayName: 'Publish to folder'
- task: Docker@2
inputs:
containerRegistry: 'saswcr-service-connection'
command: 'login'
- task: Docker@2
inputs:
containerRegistry: 'saswcr-service-connection'
repository: $(imageName)
command: 'buildAndPush'
dockerfile: './Dockerfile'
tags: |
latest
$(Build.BuildNumber)
这就是我在登录ACR后在本地运行容器的方式
docker run --name my-scheduler -p 8080:80 saswcr.azurecr.io/my-scheduler:20201124.4
我的点子快用完了。我使用的hangfire版本:
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.18" />
<PackageReference Include="Hangfire.Core" Version="1.7.18" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
导致问题的原因似乎是:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints
.MapHangfireDashboard(HangfireConstants.DashboardUrl)
.RequireAuthorization(PolicyConstants.DashboardPolicy);
});
原因可能是什么?为什么它发生在docker容器中而不是外部
更新1 2020-11-24:
有趣的发现。我已经为相同的代码生成了一个docker映像,只是这次使用了GitLab CI、GitLab容器存储库和kaniko(我比Azure DevOps更熟悉这种方法),如下所示:
default:
image: mcr.microsoft.com/dotnet/sdk:5.0
variables:
PUBLISH_OUTPUT_DIR: publish
ENTRYPOINT_DLL: WebApi.dll
WEB_APP_HOOK: $WEB_APP_HOOK
stages:
- build
- test
- publish
- delivery
- release
build:
stage: build
script:
- dotnet restore --no-cache --force
- dotnet build -c Release --no-restore
artifacts:
paths:
- test
expire_in: 1 hour
unit_tests:
stage: test
script: dotnet vstest test/*UnitTests/bin/Release/**/*UnitTests.dll --Blame
rules:
- exists:
- test/*UnitTests/*UnitTests.csproj
functional_tests:
stage: test
script: dotnet vstest test/*FunctionalTests/bin/Release/**/*FunctionalTests.dll --Blame
rules:
- exists:
- test/*FunctionalTests/*FunctionalTests.csproj
publish:
stage: publish
script:
- dotnet publish -c Release -o $PUBLISH_OUTPUT_DIR
artifacts:
paths:
- publish/
expire_in: 1 hour
build_image:
stage: delivery
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
before_script:
- echo "Generating $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG"
- 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
# @see https://github.com/GoogleContainerTools/kaniko/issues/1227
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- echo "Displaying files.."
- cat $CI_PROJECT_DIR/Dockerfile
- cat /kaniko/.docker/config.json
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
然后,我以如下方式运行容器:
docker run --name cubic-scheduler -p 8080:80 registry.gitlab.com/cubictelecom/my-scheduler
这一次,使用这种创建docker图像的方法,效果很好。因此,问题似乎确实在于如何创建docker图像但到底是什么问题?为什么它会对hangfire产生如此大的影响?
更新2 2020-11-24:
依赖项如下所示:
default:
image: mcr.microsoft.com/dotnet/sdk:5.0
variables:
PUBLISH_OUTPUT_DIR: publish
ENTRYPOINT_DLL: WebApi.dll
WEB_APP_HOOK: $WEB_APP_HOOK
stages:
- build
- test
- publish
- delivery
- release
build:
stage: build
script:
- dotnet restore --no-cache --force
- dotnet build -c Release --no-restore
artifacts:
paths:
- test
expire_in: 1 hour
unit_tests:
stage: test
script: dotnet vstest test/*UnitTests/bin/Release/**/*UnitTests.dll --Blame
rules:
- exists:
- test/*UnitTests/*UnitTests.csproj
functional_tests:
stage: test
script: dotnet vstest test/*FunctionalTests/bin/Release/**/*FunctionalTests.dll --Blame
rules:
- exists:
- test/*FunctionalTests/*FunctionalTests.csproj
publish:
stage: publish
script:
- dotnet publish -c Release -o $PUBLISH_OUTPUT_DIR
artifacts:
paths:
- publish/
expire_in: 1 hour
build_image:
stage: delivery
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
before_script:
- echo "Generating $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG"
- 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
# @see https://github.com/GoogleContainerTools/kaniko/issues/1227
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- echo "Displaying files.."
- cat $CI_PROJECT_DIR/Dockerfile
- cat /kaniko/.docker/config.json
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
WebApi
<ItemGroup>
<PackageReference Include="Microsoft.Identity.Web" Version="1.3.0" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
<ProjectReference Include="..\Infra.Hangfire\Infra.Hangfire.csproj" />
</ItemGroup>
次火
<ItemGroup>
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.18" />
<PackageReference Include="Hangfire.Core" Version="1.7.18" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
<PackageReference Include="Hangfire.SqlServer" Version="1.7.18" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
</ItemGroup>
正如您所看到的,版本之间没有冲突,因为它使用了一种干净的体系结构方法,其中所有第三方依赖项都位于底层(和web api)。在任何情况下,它都可以在本地正常工作,在使用kaniko和gitlab创建它时,它可以作为docker容器正常工作。问题一定是我如何为Azure DevOps创建它。请尝试在解决方案中引用的所有项目中调整程序包Hangfire.AspNetCore的版本。感谢您的建议。它是一致的,事实上我使用的是干净的架构方法,只有一个包依赖于hangfire。我将在问题上更新它。在这种情况下,为了确认问题属于构建/部署过程,我建议将容器中部署的内容下载到本地,并尝试使用dotnet运行命令直接运行dll文件。(可能容器中的某些文件访问权限有问题,因此这将是检查的最佳解决方案)尝试在解决方案中引用的所有项目中对齐Hangfire.AspNetCore包的版本谢谢您的建议。它是一致的,事实上我使用的是干净的架构方法,只有一个包依赖于hangfire。我将在问题上更新它。在这种情况下,为了确认问题属于构建/部署过程,我建议将容器中部署的内容下载到本地,并尝试使用dotnet运行命令直接运行dll文件。(容器中的某些文件访问权限可能有问题,因此这是检查该权限的最佳解决方案)
no dependencies.
<ItemGroup>
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.18" />
<PackageReference Include="Hangfire.Core" Version="1.7.18" />
<PackageReference Include="Hangfire.MemoryStorage" Version="1.7.0" />
<PackageReference Include="Hangfire.SqlServer" Version="1.7.18" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
</ItemGroup>