Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.net core How to Register IHostedService which also Contains a Custom Interface

How do I property register an class which contains both the IHostedService and a custom interface like IMyInterface?

As in

class BackgroundTaskScheduler : BackgroundService, ITaskScheduler {...}

If it is configure like:

services.AddHostedService<BackgroundTaskScheduler>();

And then try to have it inject into a client, like so:

public class Foo
{
    Foo(ITaskScheduler taskScheduler) {...}
}

An error is generated stating that ASP.net can't resolve BackgroundTaskScheduler, why?

like image 462
Kabuo Avatar asked Oct 16 '25 18:10

Kabuo


1 Answers

After reading lots of ideas, including:

  • AddHostedService() registers service as Transient - which I agree with most of the complains, since most hosted services don't live and/or run in isolation.
  • How to inject a reference to a specific IHostedService implementation? - which suggested a unique concept of using a hidden HostedServicewrapping class which forward the start and stop calls to the real hosted service.

But how to get it to work without requiring a wrapper class? I combined the ideas discussed above into the following two extension methods.

Interface Dependency Injection

If you like using interface DI, as in Bar.Bar(IFoo foo) then use this one:

        /// <summary>
        /// Used to register <see cref="IHostedService"/> class which defines an referenced <typeparamref name="TInterface"/> interface.
        /// </summary>
        /// <typeparam name="TInterface">The interface other components will use</typeparam>
        /// <typeparam name="TService">The actual <see cref="IHostedService"/> service.</typeparam>
        /// <param name="services"></param>
        public static void AddHostedApiService<TInterface, TService>(this IServiceCollection services)
            where TInterface : class
            where TService : class, IHostedService, TInterface
        {
            services.AddSingleton<TInterface, TService>();
            services.AddSingleton<IHostedService>(p => (TService) p.GetService<TInterface>());
        }

Usage:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHostedApiService<ITaskScheduler, BackgroundTaskScheduler>();
        }

Concrete class Dependency Injection

If you like to use concrete class injection, as in Bar.Bar(Foo foo) then use:

        /// <summary>
        /// Used to register <see cref="IHostedService"/> class which defines an interface but will reference the <typeparamref name="TService"/> directly.
        /// </summary>
        /// <typeparam name="TService">The actual <see cref="IHostedService"/> service.</typeparam>
        public static void AddHostedApiService<TService>(this IServiceCollection services)
            where TService : class, IHostedService
        {
            services.AddSingleton<TService>();
            services.AddSingleton<IHostedService>(p => p.GetService<TService>());
        }

Usage:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHostedApiService<BackgroundTaskScheduler>();
        }

Enjoy!

like image 181
Kabuo Avatar answered Oct 19 '25 08:10

Kabuo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!