Stanley
Stanley

Reputation: 2794

Hangfire & Autofac.Core.Registration.ComponentNotRegisteredException: The requested service has not been registered

I'm trying to set up Hangfire to execute a method in a service on a recurring basis. However, the AutoFac is complaining that the service is not registered:

program.cs

var serviceCollection = new ServiceCollection()
    .AddScoped<BlobService>()
    .AddSingleton<IConfiguration>(configuration)
    .AddDbContext<RedactedDbContext>(opt =>
    {
        opt.UseNpgsql(connectionString);
    })
    .AddScoped<ActivityChangeInfoCh>()
    .AddScoped<SpecificConditionsCh>()
    .AddScoped<CardIdentificationCh>()
    .AddScoped<UploadInfoCh>()
    .AddScoped<CardEventDataCh>()
    .AddScoped<CardFaultDataCh>()
    .AddScoped<CardVehiclesUsedCh>()
    .AddScoped<GNSSPlacesCh>()
    .AddScoped<HangfireService>()
    .AddTransient<FileReader>()
    .AddScoped<ExplorerService>()
    .AddScoped<DriverFileService>();
GlobalConfiguration.Configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseColouredConsoleLogProvider()
    .UseRecommendedSerializerSettings()
    .UsePostgreSqlStorage(config.GetConnectionString("Hangfire"))
    .UseAutofacActivator(builder.Build());

var serviceProvider = serviceCollection.BuildServiceProvider();
DriverFileService driverFileService = serviceProvider.GetService<DriverFileService>();
driverFileService.TestAvailability();


var options = new BackgroundJobServerOptions { WorkerCount = 1 };
using (var server = new BackgroundJobServer(options))
{
    Console.WriteLine("Hangfire Server started. Press any key to exit...");
    var manager = new RecurringJobManager();
    manager.AddOrUpdate(
        "process2",
        () => serviceProvider.GetService<DriverFileService>().Test(),
        "*/50 * * * * *"
    );

    Console.ReadKey();
}

As you can see this code works:

driverFileService.TestAvailability();

however the code inside the backgroundjobserver complains about unregistered services

enter image description here

ERROR:

2024-02-08 07:10:35 [INFO]  (Hangfire.PostgreSql.PostgreSqlStorage) Start installing Hangfire SQL objects...
2024-02-08 07:10:35 [INFO]  (Hangfire.PostgreSql.PostgreSqlStorage) Hangfire SQL objects installed.
Removing recurring jobs....
Removing recurring jobs in connection....
CONNECTION: Hangfire.PostgreSql.PostgreSqlConnection
JOBS: 0
Started DriverFileService: TestAvailability()
Exiting DriverFileService: TestAvailability()
2024-02-08 07:10:35 [INFO]  (Hangfire.BackgroundJobServer) Starting Hangfire Server using job storage: 'PostgreSQL Server: Host: redacted.postgres.database.azure.com, DB: hangfire_development, Schema: hangfire'
2024-02-08 07:10:35 [INFO]  (Hangfire.BackgroundJobServer) Using the following options for SQL Server job storage:
2024-02-08 07:10:35 [INFO]  (Hangfire.BackgroundJobServer)     Queue poll interval: 00:00:15.
2024-02-08 07:10:35 [INFO]  (Hangfire.BackgroundJobServer)     Invisibility timeout: 00:30:00.
2024-02-08 07:10:35 [INFO]  (Hangfire.BackgroundJobServer) Using the following options for Hangfire Server:
    Worker count: 1
    Listening queues: 'default'
    Shutdown timeout: 00:00:15
    Schedule polling interval: 00:00:15
Hangfire Server started. Press any key to exit...
2024-02-08 07:10:35 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server stianhave:261704:bb1c7ac3 successfully announced in 13.4146 ms
2024-02-08 07:10:35 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server stianhave:261704:bb1c7ac3 is starting the registered dispatchers: ServerWatchdog, ServerJobCancellationWatcher, ExpirationManager, CountersAggregator, Worker, DelayedJobScheduler, RecurringJobScheduler...
2024-02-08 07:10:36 [INFO]  (Hangfire.Server.ServerWatchdog) 4 servers were removed due to timeout
2024-02-08 07:10:36 [INFO]  (Hangfire.Server.BackgroundServerProcess) Server stianhave:261704:bb1c7ac3 all the dispatchers started
2024-02-08 07:10:51 [WARN]  (Hangfire.AutomaticRetryAttribute) Failed to process the job '2171': an exception occurred. Retry attempt 1 of 10 will be performed in 00:00:18.
Autofac.Core.Registration.ComponentNotRegisteredException
The requested service 'Redacted.Services.DriverFileService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType)
   at Hangfire.AutofacJobActivator.AutofacScope.Resolve(Type type) in C:\projects\hangfire-autofac\src\Hangfire.Autofac\AutofacJobActivator.cs:line 69
   at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context)
   at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass10_0.<PerformJobWithFilters>b__0()
   at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func`1 continuation)
   at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass10_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, BackgroundJob backgroundJob, IReadOnlyDictionary`2& customData)
2024-02-08 07:11:06 [WARN]  (Hangfire.AutomaticRetryAttribute) Failed to process the job '2172': an exception occurred. Retry attempt 1 of 10 will be performed in 00:00:37.

DriverFileService.cs

        public DriverFileService(
            ExplorerService explorerService,
            ActivityChangeInfoCh aciCh,
            SpecificConditionsCh scCh,
            CardIdentificationCh ciCh,
            UploadInfoCh uiCh,
            CardEventDataCh cedCh,
            CardFaultDataCh cfdCh,
            CardVehiclesUsedCh cvuCh,
            GNSSPlacesCh gnssCh
        )
        {
            this.explorerService = explorerService;
            this.aciCh = aciCh;
            this.scCh = scCh;
            this.ciCh = ciCh;
            this.uiCh = uiCh;
            this.cedCh = cedCh;
            this.cfdCh = cfdCh;
            this.cvuCh = cvuCh;
            this.gnssCh = gnssCh;
        }

        public void UploadFileContent(DriverFileInfo file) { }

        public void TestAvailability()
        {
            System.Console.WriteLine("Started DriverFileService: TestAvailability()");
            System.Console.WriteLine("Exiting DriverFileService: TestAvailability()");
        }

        public void Test()
        {
            System.Console.WriteLine("Started DriverFileService: Test()");
            List<DriverFileInfo> files = explorerService.GetFiles();
            System.Console.WriteLine("Exiting DriverFileService: Test()");
        }

Upvotes: 0

Views: 453

Answers (3)

Stanley
Stanley

Reputation: 2794

After reading @J.Memisevic's answers I read up on the documentation. Turns out my registration of autoFac was not set correctly:


1. register services

string baseDirectory = Directory.GetParent(AppContext.BaseDirectory).Parent.Parent.FullName;
Log.Logger = new LoggerConfiguration().WriteTo
    .Console()
    .WriteTo.File(Path.Combine(baseDirectory, "logs/logfile.txt"))
    .CreateLogger();

var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddSerilog();
    builder.AddConsole();
});
builder.RegisterInstance(loggerFactory).As<ILoggerFactory>().SingleInstance();
builder.RegisterGeneric(typeof(CustomLogger<>)).AsSelf().SingleInstance();
builder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).SingleInstance();

2. Set configuration

var container = builder.Build();
GlobalConfiguration.Configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseColouredConsoleLogProvider()
    .UseRecommendedSerializerSettings()
    .UsePostgreSqlStorage(config.GetConnectionString("Hangfire"))
    .UseAutofacActivator(container);

3. use lifetime scope and use instances

using (var scope = container.BeginLifetimeScope())
{
    var driverFileService = scope.Resolve<DriverFileService>();

    var options = new BackgroundJobServerOptions { WorkerCount = 1 };
    using (var server = new BackgroundJobServer(options))
    {
        Console.WriteLine("Hangfire Server started. Press any key to exit...");
        var manager = new RecurringJobManager();
        driverFileService.TestAvailability();
        manager.AddOrUpdate("process4", () => driverFileService.Test(), "*/50 * * * * *");
        Console.ReadKey();
    }
}

References:

Upvotes: 0

J.Memisevic
J.Memisevic

Reputation: 1454

Insted of :

manager.AddOrUpdate(
    "process2",
    () => serviceProvider.GetService<DriverFileService>().Test(),
    "*/50 * * * * *"
);

Can you try :

RecurringJob.AddOrUpdate<DriverFileService>( "process2", job => job.Test(), "*/50 * * * * *");

Upvotes: 0

J.Memisevic
J.Memisevic

Reputation: 1454

Recuring job manager just saves job definition to database. JobActivator is resposible for creating an instance of the job. If you are using Autofac as DI you gonna need to setup JobActivator, you can use Hangife.Autofac

    var builder = new ContainerBuilder();
   // builder.Register...

   GlobalConfiguration.Configuration.UseAutofacActivator(builder.Build());

GlobalConfiguration.Configuration.UseAutofacActivator(builder.Build());

Upvotes: 1

Related Questions