Simplificando a injeção de dependência para Serviços e Repositórios
Quantas vezes estamos escrevendo código e nos deparamos com aquela velha implementação de injeção de dependência na aplicação, definindo interface x serviço, ou interface x repositório, como abaixo ?
Primeiramente já vemos que a implementação está no nosso “program.cs” da aplicação (classe que é acessada na inicialização), além de torná-lo cada vez maior conforme seu projeto cresce, fica muito ruim de validar, além do que as dependências podem ser configuradas no seu projeto específico, facilitando a análise do código.
De cara, vamos criar uma classe estática dentro do projeto onde estão os repositórios e realizar a implementação de um Extension Method (não sabe o que é veja nesse artigo meu) que irá isolar a injeção de dependência em uma classe específica para aquele projeto.
Normalmente eu utilizo o nome “DependencyInjectorHelper” mas isso não é uma regra, pode usar qualquer nome.
Neste arquivo vamos implementar a injeção em um método que será um Extension Method da interface “IServiceCollection” que é o objeto onde os códigos eram feitos manualmente!
Observem que nesse método fazemos o uso do “this” transformando-o num método de extensão da interface “IServicesCollection’ então desta forma poderemos utilizar como foi feito agora no program.cs.
Tudo aquilo foi substituído por uma única linha, referenciando o método que criamos e levando a implementação para o seu projeto original.
Ficou muito mais bonito o program.cs ! Mas a classe continua com as mesmas linhas, só mudou de lugar ! Perto de alguns projetos que já vi, já está bem melhor, mas vamos tornar as coisas mais simples ainda !
Podemos implementar na nossa classe estas linhas e resolver o problema.
var types = Assembly.GetExecutingAssembly().GetTypes()
.Where(x => x.GetInterfaces().Any(i => i.Name.EndsWith("Repository")));
foreach (var type in types)
{
var interfaces = type.GetInterfaces();
foreach (var inter in interfaces)
services.AddScoped(inter, type);
}
Mas o que este código faz na prática ? ele vai escanear o Assembly (bibliotecas compiladas do seu projeto) procurando as classes que estão declaradas, e além disso, classes onde a sua interface tenha o sufixo “Repository”.
Observe que ao inspecionar a variável “types” ela possui todas as classes que estavam descritas uma a uma nas linhas de código substituídas.
Então assim, serão mapeadas as injeções de dependência deste projeto e resolvido o problema.
Dentro do comando foreach, ele vai implementar uma a uma as classes que mapeou !
Mas…. ainda tá complexo, imagine numa “solution” que eu tenha muitos projetos, e em cada projeto eu tenha que replicar estas linhas para escanear o Assembly? vou ter mais linhas de código em alguns casos do que ir direto à descrição de cada classe/repositório !
Qual a solução? criar um método que faça tudo isso e eu possa utilizá-lo em toda a solução executando a mesma lógica.
Então vamos criar esse método e utilizá-lo em todos os outros projetos onde eu precise fazer a injeção de dependência baseada em Interface / Classe.
Com a criação do método acima, podemos eliminar todas as nossas linhas anteriores ! Olha como ficou abaixo:
Agora substituímos todas aquelas linhas por uma única linha, acionando o método de extensão criado ! (lembre-se de adicionar o using do seu namespace no topo senão ele não será exibido associado como um método de “services”.
Um ponto muito importante é que o nosso “Assembly” é passado como um parâmetro dentro do método de extensão, pois se o método pertencer à outro projeto (como eu fiz aqui) não teremos problemas de não encontrar as classes que queremos, pois o assembly da extensão pode ser outro !
Pronto, agora você pode utilizá-lo em qualquer parte da sua solução para resolver problemas de injeção de dependência, eliminando muitas linhas e aquele trabalho chato de olhar classe por classe e fazer tudo manualmente.
Quais os benefícios de escanear o Assembly ?
- não preciso toda vez que criar uma classe e um repositório ou serviço, realizar a inserção de uma linha para declarar essa dependência (aliás, quem nunca rodou a aplicação e percebeu que esqueceu disso?).
- Não é preciso remover uma linha lá no startup quando remover uma classe e interface.
O que pode dar errado? ter alguma implementação com nomes similares que não obedeça a dependência interface / classe, caso isto acontecer, faça a injeção dos itens conflitantes da forma anterior ou mude o nome das classes para evitar conflitos.
Com certeza isso vai eliminar várias linhas do seu código e também você não vai precisar ficar inserindo uma linha nova a cada nova classe criada.
Gostou do artigo? clique no ícone👏e também me siga para ver as próximas publicações !!