0
Hello,
I am starting studies on Ddds and delimited contexts and would like to avoid the use of Service Locator to access my repositories through the Unit of Work.
I am currently using Mediatr to receive a Query message and resolve it (it is an API project):
[HttpGet]
public async Task<ActionResult<UsuarioDTO>> Get([FromQuery]PegarUsuarioPorNomeDeUsuarioQuery nomeDeUsuarioQuery)
{
try
{
UsuarioDTO usuario = await _Mediator.Send(nomeDeUsuarioQuery);
if (usuario == null)
return NotFound("Usuário não encontrado");
else
return Ok(usuario);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
Handler for this Query is in my Security Context (a library class):
namespace SegurancaBC.Handlers.Queries
{
public class PegarUsuarioPorNomeDeUsuarioHandler : IRequestHandler<PegarUsuarioPorNomeDeUsuarioQuery, UsuarioDTO>
{
private readonly IUnitOfWork _UoW;
public PegarUsuarioPorNomeDeUsuarioHandler(IUnitOfWork uow)
{
_UoW = uow;
}
public async Task<UsuarioDTO> Handle(PegarUsuarioPorNomeDeUsuarioQuery request, CancellationToken cancellationToken)
{
IUsuarioRepository usuarioRepository = _UoW.PegarRepositorio<IUsuarioRepository>(); // implementado com Service Locator internamente
UsuarioDTO usuario = await usuarioRepository.CarregarUsuario(new Email(request.NomeDeUsuario));
return usuario;
}
}
}
This makes me worried, because "Pegarrepositorio" uses a Locator service to invoke the correct implementation of Iusuariorepository that I have defined in the Infrastructure layer.
Right now I have a project Sharedkernel with an interface to the Uow:
namespace SharedKernel.Repositories
{
public interface IUnitOfWork
{
void Begin();
void Commit();
void RollBack();
TRepositorio PegarRepositorio<TRepositorio>() where TRepositorio : IRepository;
IDbConnection Connection { get; }
IDbTransaction Transaction { get; }
}
}
Below the specific implementation with Service Locator:
public TRepositorio PegarRepositorio<TRepositorio>() where TRepositorio : IRepository
{
Type tipoRepositorio = typeof(TRepositorio);
return (TRepositorio)_ServiceProvider.GetService(tipoRepositorio);
}
In each Context I have different Repositories, such as:
namespace SegurancaBC.Domain.Repositories
{
public interface IUsuarioRepository : IRepository
{
Task<UsuarioDTO> CarregarUsuario(Email nomeDeUsuario);
Task InserirUsuario(Usuario usuario);
Task AtivarUsuario(Email nomeDeUsuario);
Task InativarUsuario(Email nomeDeUsuario);
}
}
And their due implementations in an Infrastructure layer (I’m not creating an infrastructure for each context).
If I didn’t care about class separation in contexts, I could simply dictate that my Uow interface had a get for Iusuariorepository, but in this scenario, it would cause a circular dependency, since my "Security" context also depends on the "Shared Kernel".
Seeing another scenario, creating an infrastructure and an API for each context, this problem would also be avoided as it could specialize my Uow for each Infra, but I believe that this would lead to a more complex path than I wish to address at the moment (Micro services?).
I always see that Service Locator is an anti-Pattern, but at the moment, I can’t see a solution without this approach.
many thanks for the cordiality and the indication, I will follow in the studies!
– diego.dona