Injeção de dependências no ASP.NET MVC
![Injeção de dependências no ASP.NET MVC](https://www.alura.com.br/artigos/assets/code/injecao-de-dependencias-no-asp-net-mvc.1725754358.png)
Para melhorar a manutenibilidade de um sistema, devemos programar voltados para interface. Assim, nos preocupamos apenas com o contrato definido pela interface, não com sua implementação, diminuindo o acoplamento do código. Uma das formas de facilitar essa prática é utilizar a injeção de dependências. Dessa forma, nossas classes não precisam conhecer a lógica de instanciação, ciclo devida e nem implementação dos componente do sistema, podendo mudar facilmente a implementação de suas dependências.
Quando escrevemos um controller no ASP.NET MVC, é interessante que a classe não precise se preocupar com a instanciação de suas dependências. Queremos, por exemplo, receber todas essas dependências no construtor. Vamos usar como exemplo um UserController
que precisa de um IUserDao
:
class UserController { private IUserDao userDao; public UserController(IUserDao userDao) { this.userDao = userDao; } }
Porém, o ASP.NET MVC não consegue instanciar um controller escrito dessa forma. Ele não sabe como instanciar um IUserDao
! Por esse motivo, apenas controllers que tenham um construtor sem argumentos podem ser instanciados. Para mudar esse comportamento, precisamos ensinar o ASP.NET MVC a instanciar controladores que recebem parâmetros no construtor.
Unity Container
Para que possamos criar instâncias de classes que recebam as dependências pelo construtor, precisamos primeiro guardar as instâncias dessas dependências em algum lugar. Precisamos, por exemplo, ter um IUserDao
em mãos para passar para o construtor do UserController
.
Existem diversos frameworks que nos ajudam nessa tarefa. Eles são conhecidos como frameworks de injeção de dependência. Nesse post utilizaremos o framework de injeção de dependências da Microsoft, o Unity.
O Unity nos oferece uma classe chamada UnityContainer
, classe na qual podemos registrar tipos que serão injetados. Para registrar uma dependência, utilizamos o método RegisterType
do container, passando a interface, a implementação que deve ser injetada e um nome para ela.
No exemplo, queremos registrar o UserController
como uma implementação de IController
e o UserDao
como uma implementação de IUserDao
. Além disso, para seguir a convenção de nomes do ASP.NET MVC, registraremos o UserController
com o nome User.
Container.RegisterType(typeof(IUserDao), typeof(UserDao)); Container.RegisterType(typeof(IController), typeof(UserController), “User”);
Agora que temos registrado no Unity tanto o Dao quanto o Controller, podemos pedir instâncias dessas classes para ele! Ao pedirmos uma instância de UserController
, o Unity se encarregará de enviar o UserDao
para o construtor dele:
IController controller = Container.Resolve<IController>("User");
![Banner da Escola de Inovação e Gestão: Matricula-se na escola de Inovação e Gestão. Junte-se a uma comunidade de mais de 500 mil estudantes. Na Alura você tem acesso a todos os cursos em uma única assinatura; tem novos lançamentos a cada semana; desafios práticos. Clique e saiba mais!](assets/alura-matricula-maior-escola-tecnologia-brasil-mais-500-mil-estudantes/matricula-escola-inovacao-gestao-alura-saiba-mais-versao-mobile.png)
ControllerFactory com Injeção de Dependências
Agora precisamos ensinar o ASP.NET MVC a utilizar o Unity para instanciar os controllers. Para fazer isso, precisamos criar uma classe que implementa IControllerFactory
. Implementações dessa interface devem fornecer três métodos: CreateController
, ReleaseController
e GetControllerSessionBehavior
.
CreateController
recebe uma String
com o nome do controller que precisa ser criado e deve devolver uma instância de IController
. ReleaseController
recebe um IController
e deve liberar os recursos utilizados. A String
com o nome do controller segue a convenção do ASP.NET MVC, ou seja, quando recebemos a String
"User", devemos criar uma instância de UserController
.
class UnityFactory : IControllerFactory { public UnityFactory() { this.Container = new UnityContainer(); this.Container.RegisterType(typeof(IUserDao), typeof(UserDao)); this.Container.RegisterType(typeof(IController), typeof(UserController), “User”); }
public IController CreateController (RequestContext context, String controllerName) { IController controller = this.Container.Resolve<IController>(controllerName); return controller; } // ... }
Precisamos também ensinar o ASP.NET MVC a destruir nosso controller e liberar quaisquer recursos que alocamos. Para isso, vamos implementar o método ReleaseController
:
public void ReleaseController(IController controller) { this.Container.Teardown(controller); }
O GetControllerSessionBehavior
deve retornar o valor de um enum que define o comportamento da session do ASP.NET MVC. Como queremos que a Session tenha o mesmo comportamento da Session padrão, esse método vai retornar System.Web.SessionState.SessionStateBehavior.Default
.
public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(RequestContext ctx, string controllerName) { return System.Web.SessionState.SessionStateBehavior.Default; }
Estamos quase lá. Resta apenas substituir o mecanismo padrão do ASP.NET MVC pelo que acabamos de criar. Essa substituição é feita no arquivo Global.asax
do projeto, através do método SetControllerFactory
. Para manter a organização do arquivo Global.asax
, o registro do ControllerFactory
ficará junto com as configurações globais dentro do método Application_Start()
:
protected void Application\_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); UnityFactory factory = new UnityFactory(); ControllerBuilder.Current.SetControllerFactory(factory); }
Agora que a aplicação está utilizando a fábrica customizada, o ASP.NET MVC é capaz de instanciar o UserController
, passando o UserDao
para ele! Essa factory ainda pode ser melhorada. Poderíamos, por exemplo, registrar automaticamente no Unity todos os controllers e componentes que serão injetados. Você pode ver essa implementação, um pouco mais complicada, aqui. Além disso, você pode ver a implementação da factory utilizando o container Windsor no projeto agile-tickets-csharp, projeto utilizado no curso PM-87 da Caelum.
Pronto! Nossos controllers agora podem declarar suas dependências no construtor, deixando o código mais claro e mais fácil de ser testado. Aprenda a desenvolver com ASP.NET MVC em nosso curso online.