Hi am using stashbox with aspnet core 2.2 and Hangfire.
It is a multi tenant solution, where I spawn one hangfire instance for each tenant, and I hand each hangfire instance their own child container with their own specific registrations.
However when the hangfire server tries to start a job, and resolve a service, I get the following exception.
System.InvalidOperationException: variable '' of type 'System.IServiceProvider' referenced from scope '', but it is not defined
at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
at System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda)
at System.Linq.Expressions.ExpressionExtensions.CompileDelegate(Expression expression, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\Extensions\ExpressionExtensions.cs:line 42
at Stashbox.Lifetime.SingletonLifetime.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Lifetime\SingletonLifetime.cs:line 21
at Stashbox.Registration.ServiceRegistration.ConstructExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 169
at Stashbox.Registration.ServiceRegistration.GetExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 116
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Resolution.ParentContainerResolver.GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Resolution\ParentContainerResolver.cs:line 18
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Expressions.ConstructorSelector.TryBuildResolutionConstructor(ConstructorInformation constructor, ResolutionContext resolutionContext, IContainerContext containerContext, IServiceRegistration serviceRegistration, TypeInformation& failedParameter, Expression[]& parameterExpressions, Boolean skipUknownResolution) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 93
at Stashbox.BuildUp.Expressions.ConstructorSelector.SelectConstructor(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, ConstructorInformation[] constructors) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 46
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateInitExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 138
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type serviceType) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 91
at Stashbox.BuildUp.DefaultObjectBuilder.GetExpressionInternal(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\DefaultObjectBuilder.cs:line 32
at Stashbox.BuildUp.ObjectBuilderBase.BuildDisposalTrackingAndFinalizerExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 52
at Stashbox.BuildUp.ObjectBuilderBase.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 21
at Stashbox.Lifetime.SingletonLifetime.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType)
at Stashbox.Registration.ServiceRegistration.ConstructExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 169
at Stashbox.Registration.ServiceRegistration.GetExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 116
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Resolution.ParentContainerResolver.GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Resolution\ParentContainerResolver.cs:line 18
at Stashbox.ResolutionScope.Activate(ResolutionContext resolutionContext, Type type, Object name) in C:\projects\stashbox-0vuru\src\ResolutionScope.cs:line 272
at Stashbox.ResolutionScope.Resolve(Type typeFrom, Boolean nullResultAllowed, Object[] dependencyOverrides) in C:\projects\stashbox-0vuru\src\ResolutionScope.cs:line 94
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.DataProtectionServiceCollectionExtensions.<>c.<AddDataProtectionServices>b__2_0(IServiceProvider s)
at (DT1 , IResolutionScope )
at Stashbox.ResolutionScope.GetOrAddScopedItem(Int32 key, Object sync, Func`2 factory) in C:\projects\stashbox-0vuru\src\ResolutionScope.cs:line 180
at Stashbox.Lifetime.SingletonLifetime.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Lifetime\SingletonLifetime.cs:line 21
at Stashbox.Registration.ServiceRegistration.ConstructExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 169
at Stashbox.Registration.ServiceRegistration.GetExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 116
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Resolution.ParentContainerResolver.GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Resolution\ParentContainerResolver.cs:line 18
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Expressions.ConstructorSelector.TryBuildResolutionConstructor(ConstructorInformation constructor, ResolutionContext resolutionContext, IContainerContext containerContext, IServiceRegistration serviceRegistration, TypeInformation& failedParameter, Expression[]& parameterExpressions, Boolean skipUknownResolution) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 93
at Stashbox.BuildUp.Expressions.ConstructorSelector.SelectConstructor(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, ConstructorInformation[] constructors) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 46
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateInitExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 138
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type serviceType) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 91
at Stashbox.BuildUp.DefaultObjectBuilder.GetExpressionInternal(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\DefaultObjectBuilder.cs:line 32
at Stashbox.BuildUp.ObjectBuilderBase.BuildDisposalTrackingAndFinalizerExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 52
at Stashbox.BuildUp.ObjectBuilderBase.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 21
at Stashbox.Lifetime.SingletonLifetime.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType)
at Stashbox.Registration.ServiceRegistration.ConstructExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 169
at Stashbox.Registration.ServiceRegistration.GetExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 116
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Resolution.ParentContainerResolver.GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Resolution\ParentContainerResolver.cs:line 18
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Expressions.ConstructorSelector.TryBuildResolutionConstructor(ConstructorInformation constructor, ResolutionContext resolutionContext, IContainerContext containerContext, IServiceRegistration serviceRegistration, TypeInformation& failedParameter, Expression[]& parameterExpressions, Boolean skipUknownResolution) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 93
at Stashbox.BuildUp.Expressions.ConstructorSelector.SelectConstructor(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, ConstructorInformation[] constructors) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 46
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateInitExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 138
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type serviceType) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 91
at Stashbox.BuildUp.DefaultObjectBuilder.GetExpressionInternal(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\DefaultObjectBuilder.cs:line 32
at Stashbox.BuildUp.ObjectBuilderBase.BuildDisposalTrackingAndFinalizerExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 52
at Stashbox.BuildUp.ObjectBuilderBase.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 21
at Stashbox.Lifetime.ScopedLifetimeBase.GetFactoryExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Lifetime\ScopedLifetimeBase.cs:line 38
at Stashbox.Lifetime.ScopedLifetime.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Lifetime\ScopedLifetime.cs:line 27
at Stashbox.Registration.ServiceRegistration.ConstructExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 169
at Stashbox.Registration.ServiceRegistration.GetExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 116
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Resolution.ParentContainerResolver.GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Resolution\ParentContainerResolver.cs:line 18
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Expressions.ConstructorSelector.TryBuildResolutionConstructor(ConstructorInformation constructor, ResolutionContext resolutionContext, IContainerContext containerContext, IServiceRegistration serviceRegistration, TypeInformation& failedParameter, Expression[]& parameterExpressions, Boolean skipUknownResolution) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 93
at Stashbox.BuildUp.Expressions.ConstructorSelector.SelectConstructor(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, ConstructorInformation[] constructors) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ConstructorSelector.cs:line 46
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateInitExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 138
at Stashbox.BuildUp.Expressions.ExpressionBuilder.CreateExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type serviceType) in C:\projects\stashbox-0vuru\src\BuildUp\Expressions\ExpressionBuilder.cs:line 91
at Stashbox.BuildUp.DefaultObjectBuilder.GetExpressionInternal(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\DefaultObjectBuilder.cs:line 32
at Stashbox.BuildUp.ObjectBuilderBase.BuildDisposalTrackingAndFinalizerExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 52
at Stashbox.BuildUp.ObjectBuilderBase.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\BuildUp\ObjectBuilderBase.cs:line 21
at Stashbox.Lifetime.ScopedLifetimeBase.GetFactoryExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Lifetime\ScopedLifetimeBase.cs:line 38
at Stashbox.Lifetime.ScopedLifetime.GetExpression(IContainerContext containerContext, IServiceRegistration serviceRegistration, IObjectBuilder objectBuilder, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Lifetime\ScopedLifetime.cs:line 27
at Stashbox.Registration.ServiceRegistration.ConstructExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 169
at Stashbox.Registration.ServiceRegistration.GetExpression(IContainerContext containerContext, ResolutionContext resolutionContext, Type resolveType) in C:\projects\stashbox-0vuru\src\Registration\ServiceRegistration.cs:line 116
at Stashbox.Resolution.ResolutionStrategy.BuildResolutionExpression(IContainerContext containerContext, ResolutionContext resolutionContext, TypeInformation typeInformation, InjectionParameter[] injectionParameters, Boolean forceSkipUnknownTypeCheck) in C:\projects\stashbox-0vuru\src\Resolution\ResolutionStrategy.cs:line 51
at Stashbox.BuildUp.Resolution.ParentContainerResolver.GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionContext resolutionContext) in C:\projects\stashbox-0vuru\src\BuildUp\Resolution\ParentContainerResolver.cs:line 18
at Stashbox.ResolutionScope.Activate(ResolutionContext resolutionContext, Type type, Object name) in C:\projects\stashbox-0vuru\src\ResolutionScope.cs:line 272
at Stashbox.ResolutionScope.Resolve(Type typeFrom, Boolean nullResultAllowed, Object[] dependencyOverrides) in C:\projects\stashbox-0vuru\src\ResolutionScope.cs:line 94
at Proplan.API.Common.Extensions.HangfireActivatorScope.Resolve(Type type) in C:\Users\furie\source\repos\PPBS\Proplan.API\Common\Extensions\ApplicationBuilderHangfireExtensions.cs:line 112
--- End of inner exception stack trace ---
at Proplan.API.Common.Extensions.HangfireActivatorScope.Resolve(Type type) in C:\Users\furie\source\repos\PPBS\Proplan.API\Common\Extensions\ApplicationBuilderHangfireExtensions.cs:line 116
at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context)
at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass8_0.<PerformJobWithFilters>b__0()
at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func`1 continuation)
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)
public static class ServiceCollectionHangfireExtensions
{
public static IServiceCollection AddHangfire(this IServiceCollection services)
{
services.AddScoped<JobStorage>(_ => new SqlServerStorage(
_.GetService<IHttpContextAccessor>().HttpContext?.RequestServices.GetRequiredService<Tenant>().ConnectionString ??
_.GetRequiredService<Tenant>().ConnectionString,
new SqlServerStorageOptions { PrepareSchemaIfNecessary = false }
));
services.AddScoped<JobActivator>(_ => new HangfireActivator(_.GetRequiredService<IDependencyResolver>(),
$"RequestActivator:{_.GetService<IHttpContextAccessor>().HttpContext?.RequestServices.GetService<Tenant>()?.Name ?? _.GetService<Tenant>()?.Name}"));
services.AddScoped<IBackgroundJobFactory>(x => new BackgroundJobFactory(x.GetRequiredService<IJobFilterProvider>()));
services.AddScoped<IBackgroundJobStateChanger>(x => new BackgroundJobStateChanger(x.GetRequiredService<IJobFilterProvider>()));
services.AddScoped<IBackgroundJobPerformer>(x => new BackgroundJobPerformer(x.GetRequiredService<IJobFilterProvider>(), x.GetRequiredService<JobActivator>()));
services.AddScoped<IBackgroundJobClient>(x => new BackgroundJobClient(x.GetRequiredService<JobStorage>(), x.GetRequiredService<IBackgroundJobFactory>(), x.GetRequiredService<IBackgroundJobStateChanger>()));
services.AddScoped<IRecurringJobManager>(x => new RecurringJobManager(x.GetRequiredService<JobStorage>(), x.GetRequiredService<IBackgroundJobFactory>()));
return services.AddHangfire(configuration => { });
}
}
public static class ApplicationBuilderHangfireExtensions
{
public static IApplicationBuilder UseHangfire(this IApplicationBuilder appBuilder)
{
var lifetime = appBuilder.ApplicationServices.GetRequiredService<IApplicationLifetime>();
var rootContainer = appBuilder.ApplicationServices.GetRequiredService<IStashboxContainer>();
using (var serviceScope = appBuilder.ApplicationServices.CreateScope())
{
var catalogContext = serviceScope.ServiceProvider.GetRequiredService<ICatalogContext>();
foreach (var tenant in catalogContext.Tenants.Where(x => x.AutomaticMigrationEnabled).AsNoTracking().ToList().Distinct(Tenant.ConnectionStringComparer))
{
var childContainer = InitializeChildContainer(rootContainer.CreateChildContainer(), tenant);
CreateBackgroundJobServer(childContainer, lifetime);
var recurringJobManager = childContainer.Resolve<IRecurringJobManager>();
recurringJobManager.AddOrUpdate("TERRA", Job.FromExpression<ITerraService>(x => x.SyncTerrestrialDataAsync()), Cron.Weekly());
}
}
return appBuilder;
}
private static IStashboxContainer InitializeChildContainer(IStashboxContainer container, Tenant tenant)
{
// Have tried both with and without this line of code, with no difference.
container.RegisterInstance(container.Resolve<IServiceScopeFactory>().CreateScope().ServiceProvider);
container.Register<BackgroundJobServer>(x => x.WithSingletonLifetime());
container.Register<JobStorage>(x => x.WithFactory(y => new SqlServerStorage(tenant.ConnectionString)).WithSingletonLifetime());
container.Register<JobActivator>(x => x.WithFactory(y => new HangfireActivator(y, tenant.Name)).WithSingletonLifetime());
container.Register<BackgroundJobServerOptions>(x
=> x.WithFactory(y => new BackgroundJobServerOptions { ServerName = tenant.Name, WorkerCount = 1 }).WithSingletonLifetime()); // TODO: WorkerCount should probably be configurable
container.Register<IProplanContext, ProplanContext>(x => x.WithInjectionParameters(
new InjectionParameter { Name = "tenant", Value = tenant },
new InjectionParameter { Name = "options", Value = new DbContextOptionsBuilder<ProplanContext>().UseSqlServer(tenant.ConnectionString).Options }
).WithScopedLifetime()
);
return container;
}
private static BackgroundJobServer CreateBackgroundJobServer(IDependencyResolver dependencyResolver, IApplicationLifetime lifetime)
{
var server = dependencyResolver.Resolve<BackgroundJobServer>();
lifetime.ApplicationStopping.Register(() => server.SendStop());
lifetime.ApplicationStopped.Register(() => server.Dispose());
return server;
}
}
public class HangfireActivator : JobActivator
{
private readonly IDependencyResolver _dependencyResolver;
private readonly string _scopeName;
private int _scopeCount;
public HangfireActivator(IDependencyResolver dependencyResolver, string scopeName = "")
{
_dependencyResolver = dependencyResolver;
_scopeName = scopeName;
}
public override JobActivatorScope BeginScope(JobActivatorContext context)
{
var scopeName = $"{_scopeName}({_scopeCount++})";
return new HangfireActivatorScope(_dependencyResolver.BeginScope(scopeName, true), context, scopeName);
}
}
public class HangfireActivatorScope : JobActivatorScope
{
private readonly IDependencyResolver _scope;
private readonly JobActivatorContext _context;
private readonly string _scopeName;
public HangfireActivatorScope(IDependencyResolver dependencyResolver, JobActivatorContext context, string scopeName)
{
_scope = dependencyResolver;
_context = context;
_scopeName = scopeName;
}
public override object Resolve(Type type)
{
try
{
return _scope.Resolve(type, true);
}
catch (Exception ex)
{
throw new Exception($"[Scope: {_scopeName}][Job: {_context.BackgroundJob.Id}] failed to resolve dependency of type: {type.Name}.", ex);
}
}
public override void DisposeScope() => _scope?.Dispose();
}