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:

  • Inserir lógica de negócio/domínio e camada de acesso a dados no Modelo;
  • Criar a interface do usuário, não vinculando regras de negócio, através das Visões;
  • Efetuar o tratamento de requisições buscando objetos no modelo e selecionando Visões através do Controle.

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:

  • Facilidade de manutenção;
  • Extensível de forma simples (sem traumas).

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:

Depurando a aplicação

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.