Simplificando a injeção de dependência para Serviços e Repositórios

Marcio Nizzola
5 min readJan 30, 2023

--

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 ?

código de exemplo de injeção de dependência em program.cs

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.

exemplo de criação de classe para manter a injeção de dependência de um projeto.

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!

exemplo de classe que tem um extension method que faz a injeção de dependência de um projeto

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.

exemplo do program.cs com a injeção de dependência refatorada para arquivos separados

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.

exemplo de dados contidos no escaneamento do assembly

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.

Extension method criado para realizar o escaneamento de classes e interfaces no Assembly

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:

exemplo de código utilizando o método que fez escaneamento do Assembly

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 !!

--

--

Marcio Nizzola
Marcio Nizzola

Written by Marcio Nizzola

Microsoft MVP | Software Architect na CI&T | Prof. da Etec Itu | Membro Fundador da Comunidade Itu Developers.

Responses (2)