I believe you’re confusing the two ways and injecting dependencies.
Parameter in the constructor
As you yourself mentioned, placing a parameter in the constructor is the silver receive an instance of the repository you expect. To make this instance available to a class method we normally create a field in the class to store this received parameter in the constructor.
This form of DI is possible the most common in ASP.net applications:
public class MyController : Controller // ou ApiController
{
// campo para guardar o repositório injetado
// usando "readonly" somente prata deixar explícito
// que ele só será setado uma vez no construtor
private readonly IMyRepository myRepo;
public MyController(IMyRepository repo)
{
// o construtor sempre será executado então podermos considerar
// que myRepo sempre terá o valor esperado quando qualquer um
// dos métodos é executado.
this.myRepo = repo;
}
public List<string> GetRecords()
{
return this.myRepo.GetRecords().ToList();
}
}
Parameter in the action (method)
Actions, which are public methods of a controller, can also receive DI instances directly with the attribute [FromService]
. It is important to note that actions are not normally invoked via code, but rather by the framework when a request is made to a specific Url. That is, the responsibility to invoke actions is from the framework and he knows how to handle dependencies via attributes.
Injection of dependencies outside the controller
Another thing you commented on is to isolate the controller’s business rule. The vast majority of dependency injection libraries. Net will automatically inject the dependencies (which have been registered) into the "object tree" that are created.
A simple example, imagine that you want to run some validations before adding a new object to your database. You could do something like:
public class PedidosController : ApiController
{
private readonly IPedidoService pedidoService;
public PedidosController(IPedidoService pedidoService)
{
// Se pedidoService for null, gera exceção
this.pedidoService = pedidoService ?? throw new ArgumentNullException(nameof(pedidoService));
}
[HttpPost]
public ActionResult Finalizar(PedidoDto pedidoDto)
{
var pedido = new Pedido { // extrai propriedades de "pedidoDto" };
this.pedidoService.FinalizarPedido(pedido);
}
}
public class PedidoService : IPedidoService
{
private readonly IEstoqueRepository estoqueRepository;
private readonly IDescontoService descontoService;
private readonly IPedidoRepository pedidoRepository;
// Essa classe será instanciado pelo sistema de DI com as dependências necessárias
public PedidoService(IPedidoRepository pedidoRepository, IEstoqueRepository estoqueRepository, IDescontoService descontoService)
{
this.pedidoRepository = pedidoRepository ?? throw new ArgumentNullException(nameof(pedidoRepository));
this.estoqueRepository = estoqueRepository ?? throw new ArgumentNullException(nameof(estoqueRepository));
this.descontoService = descontoService ?? throw new ArgumentNullException(nameof(descontoService));
}
public void FinalizarPedido(Pedido pedido)
{
// Aqui você pode usar uma regra de negócio mais complexa,
// e o melhor de duto é que essa código pode ser facilmente executado de qualquer lugar, não somente de um controller.
this.descontoService.ValidarDescontos(pedido);
if (!this.estoqueRepositor.IsProdutoEmEstoque(pedido.ProdutoId))
{
// Colocar em espera ou mandar e-mail?
}
else
{
var pedidoCriado = this.pedidoRepository.CriarPedido(pedido);
// enviar e-mail com numero do pedido
}
}
}
Update for your specific case
Based on the discussion in the comments, the WsEstoque
is a service that should be injected into your controller directly by the dependency injection system. For this you need to register this dependency along with the others:
// Normalmente interfaces são geradas para desacoplar consumidores da implementação de um dependência
// e também para facilitar na criação de testes unitários.
services.AddScoped<IWsEstoque, WsEstoque>();
It is common to have dozens of services registered in this way. More complex systems use more robust dependency injection libraries to facilitate the process of registering dependencies and also to generate "modules" separating different areas of the system in shape (example: Autofac, Simple Injector).
There is also a library to help you register multiple dependencies at once with the default . net core DI system, the Netcoreautoregisterdi. With it you can register all classes in your Assembly/project with a single command:
// Registra todas as classes públicas onde o nome começa com
// a string "Ws" para a sua respectiva interface.
service.RegisterAssemblyPublicNonGenericClasses()
.Where(c => c.Name.StartsWith("Ws"))
.AsPublicImplementedInterfaces();
Ipvalverde, perfect, I understood the logic, the problem is that I tried to inject by the constructor of the Class, as well as method that you made example, but, the . Net doesn’t understand my context.. The message when I instantiate in Controller (example): var wmsestoque = new Wmsestoque, it returns asking for Repository - "message": "There is no provided argument that matches the required formal parameter "Wmsestoquerepository" from "Wmsestoque.Wmsestoque(Wmsestoquerepository)"
– Jd3 Tecnologia
If the
WmsEstoque
for a service/repository with dependencies in the constructor you should not be creating an instance of it manually. You just need to register it in the dependency injection system and receive it in your controller’s constructor already initialized.– IPValverde
Ipvalverde the
WmsEstoque
is my class where I need to do the Complex method, and within this method, I need to access theWmsEstoqueRepository
, which is my data access repository.. What I’m struggling with is that even passing theWmsEstoqueRepository
which was previously registered as Addscoped in Startup, and instantiating it in the Controller Builder where I call the Class methodWmsEstoque
, when I urge the Wmsestoque class, it asks to pass the instance of theWmsEstoqueRepository
, which makes no sense to me, the instance should come injected by . Net– Jd3 Tecnologia
It compiles just like this:
var wmsestoque =new WmsEstoque(this._WmsEstoqueRepository);
var listaestoque = await wmsestoque.PreencheGrid();
How I am instantiating Wmsestoquerepository, in the Controller Constructor, and tb in the Class Constructor, the . Net would not pass the instance by context?– Jd3 Tecnologia
Your
wsEstoque
would be the equivalent ofPedidoSdrvice
example. You don’t need to create an instance of it, let it be injected into your Controller’s constructor– IPValverde
Thanks Ipvalderde, so I need to do the dependency injection of Wmsestap Class in Startup tb, now or for another matter, since I will have 20, 30, 40 classes in this condition maybe, and would not need to instantiate all as Scoped, since maybe the user can only use one of these... Thank you!
– Jd3 Tecnologia