C
C#2y ago
Foxtrek_64

Hangfire - Unable to resolve services [Answered]

Working with Hangfire. I have a plugin service which has an InitializeAsync method that looks like this:
public override ValueTask<Result> InitializeAsync(IServiceProvider serviceProvider, CancellationToken ct = default)
{
using var scope = serviceProvider.CreateAsyncScope();
_ = scope.ServiceProvider.GetRequiredService<ILogger<ReportBuilderService>>();
_ = scope.ServiceProvider.GetRequiredService<ReportBuilderContext>();
_ = scope.ServiceProvider.GetRequiredService<DataPluginContext>();
_ = scope.ServiceProvider.GetRequiredService<InContactService>();
_ = scope.ServiceProvider.GetRequiredService<IOptions<ReportBuilderConfig>>().Value;

// This job runs every minute, polling the queue table to see
// if there are new records and, if so, running them.
RecurringJob.AddOrUpdate<ReportBuilderService>
(
recurringJobId: "ExecuteQueueItems",
service => service.ProcessQueue(CancellationToken.None),
Cron.Minutely
);
RecurringJob.AddOrUpdate<ReportBuilderService>
(
recurringJobId: "AbortCancelledJobs",
service => service.CancelItems(CancellationToken.None),
Cron.Minutely
);

return ValueTask.FromResult(Result.FromSuccess());
}
public override ValueTask<Result> InitializeAsync(IServiceProvider serviceProvider, CancellationToken ct = default)
{
using var scope = serviceProvider.CreateAsyncScope();
_ = scope.ServiceProvider.GetRequiredService<ILogger<ReportBuilderService>>();
_ = scope.ServiceProvider.GetRequiredService<ReportBuilderContext>();
_ = scope.ServiceProvider.GetRequiredService<DataPluginContext>();
_ = scope.ServiceProvider.GetRequiredService<InContactService>();
_ = scope.ServiceProvider.GetRequiredService<IOptions<ReportBuilderConfig>>().Value;

// This job runs every minute, polling the queue table to see
// if there are new records and, if so, running them.
RecurringJob.AddOrUpdate<ReportBuilderService>
(
recurringJobId: "ExecuteQueueItems",
service => service.ProcessQueue(CancellationToken.None),
Cron.Minutely
);
RecurringJob.AddOrUpdate<ReportBuilderService>
(
recurringJobId: "AbortCancelledJobs",
service => service.CancelItems(CancellationToken.None),
Cron.Minutely
);

return ValueTask.FromResult(Result.FromSuccess());
}
I request and dump those services as a test to make sure that all of them are there, even though I've independently verified by examining the service collection as it's being built. All of them pass. However, when Hangfire tries to request them, it's unable to resolve some service. I cannot see which one though because the exception appears to be swallowed. I do get this exception though:
[09:52:45 FTL] [IncontactReports.Runtime.Program] [{}] Host terminated unexpectedly
System.Exception: Plugin initialization Error: One or more errors occurred.
[0]: RestResultError { Message = REST request failed. See inner error object for details., Error = RestResultError { Message = REST request failed. See inner error object for details., Error = } }
[1]: PluginInitializationFailed { Message = Initialization of ReportBuilderPlugin (ReportBuilderPlugin) failed: One or more of the plugin's dependencies failed to initialize., Descriptor = ReportBuilderPlugin }

at IncontactReports.Runtime.InContactBot.StartAsync(CancellationToken stoppingToken) in D:\Projects\apps\TAFS\InContactReports\IncontactReports.Runtime\InContactBot.cs:line 83
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 IncontactReports.Runtime.Program.Main() in D:\Projects\apps\TAFS\InContactReports\IncontactReports.Runtime\Program.cs:line 145
at IncontactReports.Runtime.Program.Main() in D:\Projects\apps\TAFS\InContactReports\IncontactReports.Runtime\Program.cs:line 146
[09:52:45 FTL] [IncontactReports.Runtime.Program] [{}] Host terminated unexpectedly
System.Exception: Plugin initialization Error: One or more errors occurred.
[0]: RestResultError { Message = REST request failed. See inner error object for details., Error = RestResultError { Message = REST request failed. See inner error object for details., Error = } }
[1]: PluginInitializationFailed { Message = Initialization of ReportBuilderPlugin (ReportBuilderPlugin) failed: One or more of the plugin's dependencies failed to initialize., Descriptor = ReportBuilderPlugin }

at IncontactReports.Runtime.InContactBot.StartAsync(CancellationToken stoppingToken) in D:\Projects\apps\TAFS\InContactReports\IncontactReports.Runtime\InContactBot.cs:line 83
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 IncontactReports.Runtime.Program.Main() in D:\Projects\apps\TAFS\InContactReports\IncontactReports.Runtime\Program.cs:line 145
at IncontactReports.Runtime.Program.Main() in D:\Projects\apps\TAFS\InContactReports\IncontactReports.Runtime\Program.cs:line 146
It's failing to initialize the ReportBuilderPlugin, an error which is returned when InitializeAsync() throws or returns an unsuccessful result.
21 Replies
Foxtrek_64
Foxtrek_642y ago
I am using this scoped job activator with Hangfire and I have confirmed that it actually uses it by stepping through.
/// <summary>
/// A simple job activator which provides a scoped IoC container.
/// </summary>
public sealed class ScopedJobActivator : JobActivator
{
private readonly IServiceScopeFactory _serviceScopeFactory;

/// <summary>
/// Initializes a new instance of the <see cref="ScopedJobActivator"/> class.
/// </summary>
/// <param name="serviceScopeFactory">A service scope factory for building new scopes.</param>
public ScopedJobActivator(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}

/// <inheritdoc />
public override JobActivatorScope BeginScope(JobActivatorContext context)
=> new ServiceJobActivatorScope(_serviceScopeFactory.CreateScope());

private sealed class ServiceJobActivatorScope : JobActivatorScope
{
private readonly IServiceScope _serviceScope;

public ServiceJobActivatorScope(IServiceScope serviceScope)
{
_serviceScope = serviceScope;
}

public override object? Resolve(Type type)
=> _serviceScope.ServiceProvider.GetService(type);

public override void DisposeScope()
{
_serviceScope.Dispose();
}
}
}
/// <summary>
/// A simple job activator which provides a scoped IoC container.
/// </summary>
public sealed class ScopedJobActivator : JobActivator
{
private readonly IServiceScopeFactory _serviceScopeFactory;

/// <summary>
/// Initializes a new instance of the <see cref="ScopedJobActivator"/> class.
/// </summary>
/// <param name="serviceScopeFactory">A service scope factory for building new scopes.</param>
public ScopedJobActivator(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}

/// <inheritdoc />
public override JobActivatorScope BeginScope(JobActivatorContext context)
=> new ServiceJobActivatorScope(_serviceScopeFactory.CreateScope());

private sealed class ServiceJobActivatorScope : JobActivatorScope
{
private readonly IServiceScope _serviceScope;

public ServiceJobActivatorScope(IServiceScope serviceScope)
{
_serviceScope = serviceScope;
}

public override object? Resolve(Type type)
=> _serviceScope.ServiceProvider.GetService(type);

public override void DisposeScope()
{
_serviceScope.Dispose();
}
}
}
reacher
reacher2y ago
I don't see anything hangfire related in the stack trace?
Foxtrek_64
Foxtrek_642y ago
So I feel like it's hangfire because my InitializeAsync method returns a successful result. It's only after hangfire starts executing its jobs that I run into any issues. But that's just an educated guess since the stack trace appears to be truncated, like something's being caught and a new exception is being thrown without the old one added as an inner
reacher
reacher2y ago
So if you never add those hangfire jobs what happens Also, what do you see in the hangfire dashboard?
Foxtrek_64
Foxtrek_642y ago
I don't have a hangfire dashboard because this is a console app Also the jobs are stored in the database so I'd have to remove explicitly remove them, but I can give it a try
reacher
reacher2y ago
Does the plugin actually do a REST request?
Foxtrek_64
Foxtrek_642y ago
This one does not, not anymore. Only my other plugin does REST requests.
reacher
reacher2y ago
That's what the stack trace says though It doesn't say a service couldn't be resolved Just that it failed because of a REST request
Foxtrek_64
Foxtrek_642y ago
The report builder plugin relies on the data plugin
reacher
reacher2y ago
Whatever is failing it seems to be something that is executing and failing, not a missing service
Foxtrek_64
Foxtrek_642y ago
Hrm... strange that it would say it's an init error then @Jax Any ideas why this would show up that way? (This is Jax's plugin system)
reacher
reacher2y ago
Because it failed to initialize because the REST request didn't work
Foxtrek_64
Foxtrek_642y ago
Hoping that this will at least tell me where to look
reacher
reacher2y ago
So figure out what REST request it's trying to do And see why it's failing Maybe it's using some wrong configuration settings or something
Foxtrek_64
Foxtrek_642y ago
At this stage the only rest request it should be making is that to authenticate So hopefully that's the one that's erroring
reacher
reacher2y ago
You can also use fiddler to see what's going on
Foxtrek_64
Foxtrek_642y ago
Aay, that was it
Foxtrek_64
Foxtrek_642y ago
reacher
reacher2y ago
Easy enough
Foxtrek_64
Foxtrek_642y ago
I think what I need to do is change the error registration type. I'll need to confer with Jax on what to use there though Thanks for helping me track that down I'll close this issue and ask in his server I think, since this bit has been resolved
Accord
Accord2y ago
✅ This post has been marked as answered!
Want results from more Discord servers?
Add your server
More Posts