Orchardcore: Hangfire: Not able to resolve services from the OrchardCore

Created on 29 Oct 2020  路  4Comments  路  Source: OrchardCMS/OrchardCore

Problem

I use Hangfire package to fire background job.
However, It's not able to resolve services from the OrchardCore. In this case, It's IUserService

Actual: My Hangfire's jobs can't resolve IUserService
Expect: My Hangfire's jobs should be able to resolve IUserService

Importance notes:

  • It's able to resolves my custom services (that is not in the OrchardCore CMS or modules)
  • The API controller is able to resolve IUserService,
  • However, It's my Hangfire jobs can't resolve services from OrchardCore

About OC

  • OC Version: 1.0.0-rc2-14350

Steps

Checkout my source code to preproduce the issue here: https://github.com/hung-doan/OCHangFireIssue
NOTE: Before running the code, you should

  • Have SQL Server installed.
  • Create two empty database: OCHangFire-CMS, OCHangFire-Hangfire

Step 1: Fire a job via https://localhost:44342/api/test/new-job

Step 2: Access the dashboard at https://localhost:44342/hangfire
Step 3: Got execution error from the hangfire history
Exception:
image

System.InvalidOperationException
Unable to resolve service for type 'OrchardCore.Users.Services.IUserService' while attempting to activate 'OCHangFire.Jobs.MyBackgroundJob'.

System.InvalidOperationException: Unable to resolve service for type 'OrchardCore.Users.Services.IUserService' while attempting to activate 'OCHangFire.Jobs.MyBackgroundJob'.
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
   at Hangfire.AspNetCore.AspNetCoreJobActivatorScope.Resolve(Type type)
   at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context)
   at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass9_0.<PerformJobWithFilters>b__0()
   at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func`1 continuation)
   at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass9_1.<PerformJobWithFilters>b__2()
   at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable`1 filters)
   at Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext context)
   at Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId)

Any idea/direction to resolve the problem are appreciated. Thanks everyone.

Most helpful comment

Yes through a module startup so that there are not registered at the app level, but when we compose a tenant container

Without using a module you can do the same from the app but by using our OrchardCoreBuilder helpers

services.AddOrchardCms()
    .ConfigureServices(tenantServices =>
    {
        ...
    })
    .Configure((tenantAppBuilder, ...) =>
    {
        ...
    })
    ;

Also don't use app.UseRouting(); in you main app startup, it is done when we built a tenant pipeline (per tenant)

All 4 comments

I鈥檓 not an expert on this but I did get it to work. One thing that helped was to put all of the Hangfire and my custom services in the same Orchard Core module.

Yes through a module startup so that there are not registered at the app level, but when we compose a tenant container

Without using a module you can do the same from the app but by using our OrchardCoreBuilder helpers

services.AddOrchardCms()
    .ConfigureServices(tenantServices =>
    {
        ...
    })
    .Configure((tenantAppBuilder, ...) =>
    {
        ...
    })
    ;

Also don't use app.UseRouting(); in you main app startup, it is done when we built a tenant pipeline (per tenant)

thanks @mattobox , @jtkech.
I implemented your suggestion here (without module): https://github.com/hung-doan/OCHangFireIssue/compare/bugfix/7437-workaround?expand=1
It seems to work on my basic test. But let me check in more complex scenarios and get back later.

Btw, I think it's just a workaround. From my point of view, OrchardCore should not override the standard behavior of service containers from the .NET Core Framework.

Yes i understand ;)

But OrchardCore is multi tenants (multi sites), we have at least the Default tenant, and each tenant (composed of modules / features) run in an isolated container with their own services, startup filters, configured pipeline and so on.

We have app level services that we pass to tenant containers, but to make things working, e.g. app level routing sevices are not passed. You can still use app level routing but no tenant is aware of it, and the related code is not executed in a tenant context, e.g. we use at the app level app.UseStaticFiles() even we also have tenant level static file providers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ns8482e picture ns8482e  路  4Comments

lzw5399 picture lzw5399  路  3Comments

szilardcsere89 picture szilardcsere89  路  3Comments

superluminalK picture superluminalK  路  4Comments

mobinzk picture mobinzk  路  4Comments