Dependency Injection com StructureMap e Asp.Net MVC

Ok, então você começou a usar o Dependency Injection e viu que dava muito trabalho. A boa notícia é que existem vários frameworks por aí que ajudam a diminuir o trabalho e ainda a ter um código muito mais limpo.

Particularmente, eu gosto muito do StructureMap, principalmente porque ele nos permite utilizar o “Convention over Configuration”. Vamos ver jajá como isso funciona.

Bom, dando sequência no post anterior, vamos modificar aquele código para utilizar o StructureMap. A primeira coisa a fazer obviamente é baixar o framework e adicionar uma referência para o assembly StructureMap.dll.

O próximo passo é configurar o StructureMap, para isso vamos criar uma classe:

public class StructureMapConfiguration
{
    public static void Configure()
    {
        ObjectFactory.Initialize(InitializeStructureMap);
    }

    private static void InitializeStructureMap(IInitializationExpression x)
    {
        x.Scan(y =>
        {
            y.Assembly("MvcApplication1");
            y.With();
        });
    }
}

O que fazemos nesse código e dizer para o ScrutureMap buscar no Assembly MvcApplication1 usando a convenção padrão. E o que é a convenção padrão? Geralmente quando criamos uma interface, como no nosso caso criamos a interface IClienteService criamos uma classe com a implementação padrão da interface chamada ClienteService. Essa é a convenção padrão, dessa forma, toda vez que precisarmos de um objeto que implemente a interface IClienteService o StructureMap buscará nos assemblies informados para ele, a classe de mesmo nome só que sem o I. Prático não? Nada de configurar XMLs e afins (embora o StructureMap permita isso).

Outra coisa que precisamos fazer é criar uma classe que será responsável pela criação dos nosso controllers. Isso é necessário porque por padrão o Asp.Net MVC cria os controllers apenas com o construtor padrão, sem parâmetros. Nossa classe fica assim:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        if (controllerType == null) return null;
        try
        {
            return ObjectFactory.GetInstance(controllerType) as Controller;

        }
        catch (StructureMapException)
        {

            System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
            throw;
        }
    }
}

Pronto, agora vamos alterar a inicialização da aplicação no Global.asax, que deve ficar assim:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    StructureMapConfiguration.Configure();
    ControllerBuilder.Current.SetControllerFactory(new
        StructureMapControllerFactory());
}

Uma última coisa, no nosso controller ClienteController tínhamos dois construtores, agora vamos deixar apenas um com o parâmetro necessário para funcionar:

public IClienteService _service;
public ClienteController(IClienteService service)
{
    _service = service;
}

Pronto, isso é tudo o que é necessário. Mas se você quiser utilizar um XML para configurar suas classes, é possível. Dentro da classe de configuração, logo abaixo do método Scan, adicione:

x.AddConfigurationFromXmlFile("structuremap.config.xml");

Isso fará que com que o StructureMap procure na raiz do site por um arquivo chamado structuremap.config.xml. Segue um exemplo de como deve ser esse arquivo:


  
    PluginType="MinhaLibrary.Business.IClasseNegocio, MinhaLibrary.Business"
    PluggedType="MinhaLibrary.Business.ImplementacaoClasseNegocio, MinhaLibrary.Business"
    Scope="Singleton" />
  

É isso! E viva o Convention over Configuration!!!!