Search code examples
asp.net-corebackground-processfire-and-forget

How to start an ASP.NET Core BackgroundService on demand?


I want to be able to start fire-and-forget jobs in ASP.NET Core 2.2. I have tried the following:

services.AddHostedService<TestHostedService>();


public class TestHostedService : BackgroundService
{
    private readonly ILogger _logger;

    public TestHostedService(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<TestHostedService>();
    }

    public IBackgroundTaskQueue TaskQueue { get; }

    protected async override Task ExecuteAsync(
        CancellationToken cancellationToken)
    {
        _logger.LogInformation("TestHostedService is starting.");

        _logger.LogInformation("TestHostedService is stopping.");
    }
}

However, this automatically starts and I want to be able to start it on demand, similarly to how Hangfire allows:

BackgroundJob.Enqueue<TestJob>(x => x.DoWork());

This also allows the job to naturally use ASP.NET CORE DI.

Question: How to start an ASP.NET Core BackgroundService on demand?


###Background information

I am dealing with an application that needs to fire-and-forget various methods. The already written code looks like this:

 Task.Run(() => RunSomething(_serviceScopeFactory));

This means that each method must explicitly deal with getting a scope and retrieving the dependencies which is quite ugly.


Solution

  • If you want to run the BackgroundService in the MVC controller or other service. You could try to inject the IServiceProvider to that class and then loop all the hosted service and find the background service, at last you could call the startasync method.

    More details, you could refer to below codes:

    Register the service in Startup.cs

            services.AddHostedService<TestHostedService>();
    

    Execute the background service in the controller:

        public class HomeController : Controller
        {
            private readonly IServiceProvider _serviceProdiver;
            public HomeController(IServiceProvider serviceProdiver) {
    
                _serviceProdiver = serviceProdiver;
    
            }
    
            public async Task<IActionResult> Index()
            {
                
                var allBackgroundServices = _serviceProdiver.GetServices<IHostedService>();
                foreach (var hostedService in allBackgroundServices)
                {
                    if (hostedService.GetType() == typeof(TestHostedService))
                    {
                        await hostedService.StartAsync(CancellationToken.None);
    
                    }
    
                }
    
                return View();
            }
     }
    

    Result:

    enter image description here