Pessoal,
Na primeira parte desse post, procurei demonstrar de forma mais simples possível uma situação onde seria interessantes aplicarmos o pattern Dependency Injection.
O foco deste post é demonstrar como é fácil fazer a configuração do Ninject em uma aplicação ASP.NET MVC 3, graças à Interface IDependencyResolver e à classe DependencyResolver, mas principalmente pelo NuGet, que são novidades lançadas junto ao ASP.NET MVC 3. Caso você também não conheça o NuGet, existem muitas informações a respeito por aí. Mais uma vez, não vou entrar em detalhes sobre o NuGet aqui, vou somente indicar algumas referências:
http://nuget.codeplex.com
http://haacked.com
http://www.hanselman.com
Somente relembrando do exemplo utilizado na primeira parte:
Interface:
public Interface ICategoryRepository { IList GetAll(); }
Repositório “verdadeiro”:
public class CategoryRepository : ICategoryRepository { public IList GetAll() { DataContext ctx = new DataContext(); return ctx.Categories; } }
Repositório “fake”:
public class CategoryRepositoryFake : ICategoryRepository { public IList GetAll() { var category1 = new Category() { Id = 1, Name = "Cat 1" }; var category2 = new Category() { Id = 2, Name = "Cat 2" }; var category3 = new Category() { Id = 3, Name = "Cat 3" }; return new List() { category1, category2, category3 }; } }
Controller:
public class StoreController : Controller { ICategoryRepository categoryRepository; public StoreController() : this(new CategoryRepository()) { } public StoreController(ICategoryRepository repository) { this.categoryRepository = repository; } public ActionResult Index() { var categories = this.categoryRepository.GetAll(); return View(categories); } }
Como dito no outro post, isso funciona, mas temos alguns problemas. Imagine a situação de utilizarmos vários repositórios no nosso Controller… Teríamos que ter vários parâmetros no nosso construtor. Além disso, ainda temos um dependência “incômoda” do construtor sem parâmetros com a implementação do repositório “verdadeiro”.
O que fazer então? É aí que entram os containeres de IoC (Inversion of Control). Eles ficam “esperando” que “alguém peça” algum objeto de determinado tipo, e então se encarregam de instanciar e disponibilizar o objeto para nós, provendo o objeto com todas as suas dependências. Confuso? Vamos ver como fazer isso na prática, usando o container Ninject.
Primeiramente, vamos incluir o Ninject no nosso projeto, utilizando o NuGet. Simples, muito simples:
Abra o NuGet (View > Other Windows > Package Manager Console):
Liste os pacotes disponíveis no repositório oficial do NuGet:
Instale o pacote Ninject.MVC3, que é um wrapper da interface IDependencyResolver para o Ninject. O próprio Ninject será instalado junto, pois trata-se de uma dependência do Ninject.MVC3:
O próximo passo é “informar” ao Ninject quais classes ele deverá instanciar quando lhe for “solicitado” uma instância de determinada Interface. No nosso caso, queremos que o Ninject instancie o ICategoryRepository pra gente. Assim, primeiro vamos remover os construtores do Controller e decorar a propriedade “Repository” com o atributo Inject (linha 3):
public class StoreController : Controller { [Inject] public ICategoryRepository Repository { get; set; } public ActionResult Index() { var categories = this.Repository.GetAll(); return View(categories); } }
O atributo Inject é o responsável por informar ao Ninject que o elemento decorado deve ser instanciado por ele (pode ser um campo, uma propriedade, o parâmetro de um método, entre outros. Veja mais sobre esse atributo aqui).
Em seguida configuramos o Ninject. Para isso, o Ninject.MVC3 cria no diretório raiz da aplicação uma classe chamada AppStart_NinjectMVC3…
… que possui um método chamado RegisterServices. É exatamente esse método que utilizamos para fazer a tal “configuração” do Ninject:
public static void RegisterServices(IKernel kernel) { kernel.Bind(ICategoryRepository).To(CategoryRepository); }
No exemplo acima, estamos informando ao Ninject para, sempre que ele “encontrar” algum elemento cujo tipo seja a Interface ICategoryRepository decorado com o atributo Inject, o container deverá instanciar um CategoryRepository e atribuí-lo a esse elemento.
Uma vez feito isso, no nosso exemplo quando o framework ASP.NET MVC instanciar o seu Controller, “magicamente” a propriedade “Repository” do mesmo estará devidamente instanciada, removendo totalmente a dependência do Controller das implementações de ICategoryRepository.
Forte abraço.