Search code examples
c#autofachangfirehangfire-autofac

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()");
        }

Solution

  • 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: