Using Transient service within a Singleton Service

Viewed 1432

I am using ASP.Net Core 3.1 Web API. I have a need to perform an additional activity in the background, when I get a call to a controller action method, without adding too much delay in the processing of current action. Additional activity that I am performing is prepping some data into Cache so its available before user performs next step. So I want to simply trigger that activity, without waiting for it to complete. But at the same time, I don't want task to be disposed without completing, just because the action method completed it processing, returned response back to caller and the transient controller was disposed.

So I plan to use a Singleton service injected into controller to perform the task. But the task itself may involve needing to use a transient service. So instead of directly injecting transient service into Singleton Service, I am thinking injecting transient service into Controller. And then in the action method, I will pass the transient service as parameter to an async method on Singleton service and then within that method, call the required service.

public IActionResult GetSomething(string input1)
{
  var resp = await _transientService1.GetSomethingElse(input1);
  // I am not awaiting this task
  var backgroundTask = _singletonService1.DoSomethingAsync(_transientService2, resp.someattr);
  return Ok(resp);
}

Now within the singleton service, I will get the required data and write it into cache.

public async Task DoSomethingAsync(ITransientService2 myTransientService2, string someParam)
{
   var temp1 = await myTransientService2.GetSomethingNew(someParam);
   var temp2 = await _SingletonService2.WriteCache(temp1);
}

So I wanted to know first of all, if this approach will work. If it works, what are the pitfalls or gotchas, that I need to be aware of.

Currently, this is all conceptual. Else I would have tried it out directly:) Hence the questions.

1 Answers

That can work as long as you're happy with passing the dependency as an argument.

If you don't want to pass the transient dependency in as an argument, another option is to inject the IServiceProvider into the singleton service, and instantiate the transient service when it's needed.

class MySingleton
{
    private readonly IServiceProvider _serviceProvider;

    public MySingleton(IServiceProvider serviceProvider)
    {
         _serviceProvider = serviceProvider;
    }

    public async Task ExecuteAsync()
    {
        // The scope informs the service provider when you're
        // done with the transient service so it can be disposed
        using (var scope = _serviceProvider.CreateScope())
        {
            var transientService = scope.ServiceProvider.GetRequiredService<MyTransientService>();
            await transientService.DoSomethingAsync();
        }
    }
}
Related