Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make JobActivatorScope instance available in the PerformContext #2492

Open
jvmlet opened this issue Jan 2, 2025 · 14 comments
Open

Make JobActivatorScope instance available in the PerformContext #2492

jvmlet opened this issue Jan 2, 2025 · 14 comments

Comments

@jvmlet
Copy link

jvmlet commented Jan 2, 2025

Please release the latest Hangfire.Autofac.
Need the configure action callback API that was recently added.
Thanks.

@jvmlet
Copy link
Author

jvmlet commented Jan 6, 2025

Also, please change the AutofacScope::Resolve implementation to

public override object Resolve(Type type) {
       return ActivatorUtilities.GetServiceOrCreateInstance( _lifetimeScope.Resolve<IServiceProvider>(), type);
 }

@odinserj
Copy link
Member

odinserj commented Jan 7, 2025

Could you share more details regarding the new callback API that's missing? E.g. what's the current behavior, what's expected behavior, what compiler error or exception you see with the current implementation?

@jvmlet
Copy link
Author

jvmlet commented Jan 7, 2025

The new API was added after the latest release.

@odinserj
Copy link
Member

odinserj commented Jan 8, 2025

May I ask you to be more specific regarding the new API, e.g. which type, method and parameters are required in your case? Otherwise it's not possible to even test the resulting changes.

@jvmlet
Copy link
Author

jvmlet commented Jan 8, 2025

Sorry for confusion, what I'm asking is just to release the latest version of Hangfire.Autofac with this commit that is not included in 2.6.0
Also, please change the AutofacScope::Resolve implementation to

public override object Resolve(Type type) {
       return ActivatorUtilities.GetServiceOrCreateInstance( _lifetimeScope.Resolve<IServiceProvider>(), type);
 }

Another feature request, would you please add IServiceProvider optional getter to PerformContext to allow HF filters to resolve dependencies from current DI scope.

@odinserj
Copy link
Member

Hello, I have released Hangfire.Autofac 2.7.0 yesterday with the new scope configuration action feature. However, we can't add ActivatorUtilities usage currently, because should reconsider dependencies first (as it requires Microsoft.Extensions.DependencyInjection one). As I understand, this is to support activating non-registered services, right?

I will also think about PerformContext-related change as this feature will make it simpler to use dependency injection in filters.

@odinserj odinserj added this to the Hangfire 1.8.18 milestone Jan 10, 2025
@jvmlet
Copy link
Author

jvmlet commented Jan 12, 2025

Thanks
I think you can add Microsoft.Extensions.DependencyInjection because currently, Hangfire.Autofac can't be used without AspCore's JobActivator, which already has it as dependency.

@odinserj
Copy link
Member

Not quite, Hangfire.Autofac doesn't depend on ASP.NET Core at all, that JobActivator class is Hangfire.Core's abstraction that doesn't have any references to ASP.NET Core. I think that some other kind of abstraction is required here.

@odinserj
Copy link
Member

Hm, just realized that JobActivator class is simply not available in the Worker class, where a PerformContext class is created, and it's treated as an implementation detail of the CoreBackgroundJobPerformer class. Actually, it's possible to pass the IServiceProvider instance in the following way:

public sealed class DependencyInjectionExample : IServerFilter
{
    private readonly IServiceProvider _serviceProvider;

    public DependencyInjectionExample(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
        
    public void OnPerforming(PerformingContext context)
    {
        var service = _serviceProvider.GetRequiredService<IMyService>();
    }

    public void OnPerformed(PerformedContext context)
    {
    }
}
services.AddHangfire((provider, configuration) => configuration
    .UseFilter(new DependencyInjectionExample(provider))

@jvmlet
Copy link
Author

jvmlet commented Jan 13, 2025

Not quite, Hangfire.Autofac doesn't depend on ASP.NET Core at all, that JobActivator class is Hangfire.Core's abstraction that doesn't have any references to ASP.NET Core. I think that some other kind of abstraction is required here.

You are right, it doesn't depend (in .csproj), but you haven't provided Autofac Module to register Hangfire, only via IServiceCollection extension. And it already has the reference to ActivatorUtilities.

@jvmlet
Copy link
Author

jvmlet commented Jan 13, 2025

Hm, just realized that JobActivator class is simply not available in the Worker class, where a PerformContext class is created, and it's treated as an implementation detail of the CoreBackgroundJobPerformer class. Actually, it's possible to pass the IServiceProvider instance in the following way:

public sealed class DependencyInjectionExample : IServerFilter
{
    private readonly IServiceProvider _serviceProvider;

    public DependencyInjectionExample(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
        
    public void OnPerforming(PerformingContext context)
    {
        var service = _serviceProvider.GetRequiredService<IMyService>();
    }

    public void OnPerformed(PerformedContext context)
    {
    }
}
services.AddHangfire((provider, configuration) => configuration
    .UseFilter(new DependencyInjectionExample(provider))

The filter here uses new DependencyInjectionExample(provider), where provider is a root scope, but with Hangfire.Autofac you can register services with newly created scope. They won't be resolvable from the provider. (link to Action ), I'm registering services with ContainerBuilder based on JobActivatorContext

@odinserj
Copy link
Member

Good point, @jvmlet! Unfortunately, the activator scope is created after IServerFilter.OnPerforming method is already finished and has a very narrow scope, so we can't implement this in the current version.

@odinserj odinserj changed the title Hangfire.Autofac Make JobActivatorScope instance available in the PerformContext Jan 16, 2025
@odinserj odinserj changed the title Make JobActivatorScope instance available in the PerformContext Make JobActivatorScope instance available in the PerformContext Jan 16, 2025
@odinserj
Copy link
Member

The goal here is to make it accessible also in IServerFilter implementations, as a property in the PerformContext class to allow them resolving the same services as the background job itself. While it doesn’t make much sense with regular IoC containers, some advanced ones, like Autofac that allows registering custom services for created scopes, can receive big improvements. Also, ASP.NET Core’s IoC container implementation should also reach this point sooner or later, given the importance of this feature.

@jvmlet
Copy link
Author

jvmlet commented Jan 16, 2025

OK, so if scope will be created before executing IServerFilter, resolution of services from PerformingContext registered as scoped will be working as expected , right (and not from root scope)? This should work even with simple DI implementations as MS's one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants