In my ASP.NET Core application, I have a scenario where I need to dynamically resolve scoped services within a factory to handle different operations. Here’s an overview of my current setup and the issue I’m facing:
I have a controller MyController
that relies on a handler MyHandler
to perform create and get operations. The MyHandler
class has dependencies on two scoped services: IDatabaseService
and IThirdPartyService
.
However, the MyHandler.Get()
method does not require IThirdPartyService
. Despite this, when using dependency injection, an instance of IThirdPartyService
is still injected into the handler.
public class MyController
{
private readonly IMyHandler _handler;
public MyController(IMyHandler handler)
{
_handler = handler;
}
public ActionResult Create(MyModel model)
{
_handler.Create(model);
return Ok();
}
public ActionResult Get(int id)
{
var model = _handler.Get(id);
return Ok(model);
}
}
public class MyHandler : IHandler
{
private readonly IDatabaseService _dbService;
private readonly IThirdPartyService _service;
public MyHandler(IDatabaseService dbService, IThirdPartyService service)
{
_dbService = dbService;
_service = service;
}
public void Create(MyModel model)
{
_dbService.Create(model);
_service.Create(model);
}
public MyModel Get(int id)
{
_dbService.Get(id);
}
}
MyHandler
is registred as scoped service with DI.
To address this issue, I’m considering creating a factory (HandlerFactory) that dynamically resolves scoped services. This factory would be registered as a singleton and used to resolve the appropriate handler instance based on the operation. I’m considering creating two new handlers: MyHandlerCreate
and MyHandlerGet
. Each handler would be responsible for its specific operations, and only the required dependencies would be injected.
Then, I would use the HandlerFactory to resolve the appropriate handler instance in the controller action methods.
public class HandlerFactory : IHandlerFactory
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public HandlerFactory(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}
public T Get<T>() where T : IHandler
{
using (var scope = _serviceScopeFactory.CreateScope())
{
return scope.ServiceProvider.GetRequiredService<T>();
}
}
}
public class MyHandlerGet:IHandler
{
private IDatabaseService _dbService;
public MyHandlerGet(IDatabaseService dbService)
{
_dbService= dbService;
}
public MyModel Get(int id)
{
_dbService.Get(id);
}
}
public class MyHandlerCreate:IHandler
{
private IDatabaseService _dbService;
provate IThirdPartyService _service;
public MyHandlerCreate(IDatabaseService dbService, IThirdPartyService service)
{
_dbService= dbService;
_service = service;
}
public void Create(MyModel model)
{
_dbService.Create(model);
_service.Create(model);
}
}
Both MyHandlerGet
and MyHandlerCreate
will be register as scoped services with DI.
then in controller action method I can simply resolve the instance of handler that is specific to the request, for example
public async Task<IActionResult> Get(int id)
{
var handler = _factory.Get<MyHandlerGet>();
var model= await handler.Get(id);
return Ok(model);
}
My questions are:
- Is injecting IServiceScopeFactory into another factory considered an anti-pattern?
- Is there a better alternative solution to dynamically resolve scoped services?
- Am I on the right track with my proposed solution, or is there a more optimal approach to handle this scenario?
Any advice or insights would be greatly appreciated!