C# 无法加载类型';Hangfire.HangfireEndpointRouteBuilderExtensions';来自组件';当作为docker容器运行时,Hangfire.AspNetCore

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

我无法使用使用Hangfire的.NET5应用程序运行docker容器。 在当地,一切都很好。 但随后我使用Azure管道构建映像,保存在Azure容器注册表中,并尝试在本地运行它。我得到的例外是:

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>