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.