Introdução à Injeção de Dependência no ASP.NET MVC

Veja neste artigo a importância da injeção de dependência através da inversão de controle no desenvolvimento de software. Será mostrado um exemplo prático de como aplicar os conceitos em um projeto ASP.NET MVC 4 utilizando o componente Ninject.

A cultura de desenvolvimento com ASP.NET MVC

É notável a rápida aceitação e popularização do ASP.NET MVC entre a comunidade .NET, não só pelas suas óbvias vantagens comparadas com o Web Forms (modelo mais simples, controle total sobre a marcação e separação clara de responsabilidades), como também pela grande sensação passada pelo framework de que estamos “desenvolvendo da forma correta”.

Desenvolver de forma correta é algo muito relativo, por exemplo, considerando que um desenvolvedor irá utilizar o ASP.NET MVC como plataforma para criar uma aplicação, poderíamos dizer que ele está fazendo tudo certo caso siga as regras abaixo:

As regras acima são suficientes para assegurar que o padrão MVC está sendo seguido, mas será que elas respondem a pergunta: “Estou desenvolvendo da forma correta?”.

Para responder a pergunta acima, é necessário entender se existem algumas necessidades para a aplicação, entre elas podemos citar:

Os dois requisitos citados acima podem mudar drasticamente o modo como a aplicação deverá ser desenvolvida, o padrão MVC não garante que o objetivo será cumprido. Para entender melhor vejamos o exemplo abaixo:

Listagem 1: Exmplo de modelo e controlador

namespace Models { public class Pessoa { public int PessoaID { get; set; } public string Nome { get; set; } public DateTime DataNascimento { get; set; } } } namespace Controllers { public class PessoaController : Controller { readonly Pessoa _pessoa; public PessoaController(Pessoa pessoa) { _pessoa = pessoa; } public ActionResult Index() { return View(); } } }

Existe um grande problema no código mostrado, note que o construtor do controle está instanciando um objeto do tipo Pessoa. Isso cria um forte acoplamento entre as duas classes, dificultando o processo de manutenção, isso porque caso a classe Pessoa precise ser substituída, teremos que alterar todos os controles que fazem referência a essa classe.

Para resolver esse problema temos um padrão de desenvolvimento chamado de Inversão de Controle, que basicamente permite retirarmos a responsabilidade dos controles de instanciar objetos do modelo, centralizando essa ação em um “container” que irá injetar as dependências quando necessário.

Resumindo, a responsabilidade de instanciar objetos é retirada do desenvolvedor e delegada para um componente.

É aí que entra o Ninject, um container para injeção de dependência que pode ser configurado facilmente no ASP.NET MVC.

Ninject

Vamos começar a fazer algumas alterações no código para poder utilizar o Ninject. A primeira coisa que vamos fazer é criar uma Interface IPessoa que a classe Pessoa irá implementar como mostrado abaixo:

Listagem 2: Interface IPessoa implementada pela classe Pessoa

public interface IPessoa { int PessoaID { get; set; } string Nome { get; set; } DateTime DataNascimento { get; set; } } public class Pessoa : IPessoa { public int PessoaID { get; set; } public string Nome { get; set; } public DateTime DataNascimento { get; set; } }

Agora podemos fazer o desacoplamento da classe Pessoa no nosso controle fazendo o mesmo trabalhar com a interface:

Listagem 3: Desacomplando o controlador da classe Pessoa

public class PessoaController : Controller { readonly IPessoa _pessoa; public PessoaController(IPessoa pessoa) { _pessoa = pessoa; } public ActionResult Index() { return View(); } }

O próximo passo é configurar o Ninject para injetar as dependências em nosso controle.

O Ninject contém um pacote NuGet que já adiciona todas as referências necessárias em nosso projeto, para utilizá-lo execute o comando abaixo no Package Manager Console:

Listagem 4: Baixando o Ninject para o projeto

install-package Ninject

O ASPNET MVC 4 trabalha com uma forma muito simples para adicionarmos injeção de dependência na aplicação, basta criarmos uma classe que implementa a interface System.Web.Mvc.IdependencyResolver e registra-la, nenhuma configuração adicional é necessária.

Crie um arquivo chamado IocConfig na pasta App_Start e adicione as referências abaixo:

Listagem 5: Referências necessárias para uso do Ninject

using Ninject; using Ninject.Syntax;

Crie a classe abaixo no mesmo arquivo sem apagar a classe IocConfig:

Listagem 6: Classe NinjectDependencyResolver

public class NinjectDependencyResolver : IDependencyResolver { private readonly IResolutionRoot _resolutionRoot; public NinjectDependencyResolver(IResolutionRoot kernel) { _resolutionRoot = kernel; } public object GetService(Type serviceType) { return _resolutionRoot.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return _resolutionRoot.GetAll(serviceType); } }

Agora temos que configurar os tipos que o Ninject irá resolver e registrá-lo no ASP.NET, para isso vamos criar o seguinte método na classe IocConfig:

Listagem 7: Método ConfigurarDependencias

public static void ConfigurarDependencias() { //Cria o Container IKernel kernel = new StandardKernel(); //Instrução para mapear a interface IPessoa para a classe concreta Pessoa kernel.Bind<IPessoa>().To<Pessoa>(); //Registra o container no ASP.NET DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel)); }

O método acima cria e registra o Ninject, é importante notar a linha onde é configurado o mapeamento da interface para a classe que será utilizada para injetar a dependência, nesse local pode ser configurado todos os tipos necessários que o Ninject terá que manipular no projeto.

Para terminar basta chamar o método no arquivo Global.asax da seguinte forma:

Listagem 8: Método Aplication_Start

protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); IocConfig.ConfigurarDependencias(); }

Agora basta executar a aplicação, coloque um breakpoint no construtor da classe PessoaController e você verá que o Ninject inseriu um objeto do tipo Pessoa no parâmetro do construtor como mostrado abaixo:


Figura 1: Depurando a aplicação

Podemos observar que com o mínimo de esforço tornamos nossa aplicação facilmente alterável, centralizando a construção de instâncias, permitindo futuras modificações sem a necessidade de reestruturações complexas.


Artigos relacionados