Árvore de páginas

Você está vendo a versão antiga da página. Ver a versão atual.

Comparar com o atual Ver Histórico da Página

« Anterior Versão 8 Atual »

Framework de DI

Existem muitos frameworks de injeção de dependência que automatizam a resolução de dependências. Eles podem criar objetos com todas as dependências (e dependências de dependências recursivamente). Então, basta escrever sua classe com padrões de injeção de construtor e/ou propriedades que o framework de DI faz todo resto! Em uma boa aplicação, suas classes são independentes mesmo do framework DI. Haverá algumas linhas de código ou classes que interagem explicitamente com o framework DI em toda a sua aplicação. O TNF usa a estrutura do Castle Windsor para Injeção de Dependência. 

O suporte a essa estrutura pode ser obtido pela instalação do pacote Tnf via nuget em nosso package source disponível em: https://www.myget.org/F/tnf/api/v3/index.json

Exemplo manual
public class PersonAppService
{
    private IPersonRepository _personRepository;

    public PersonAppService(IPersonRepository personRepository)
    {
        _personRepository = personRepository;
    }

    public void CreatePerson(string name, int age)
    {
        var person = new Person { Name = name, Age = age };
        _personRepository.Insert(person);
    }
}

var container = new WindsorContainer();
container.Register(
        Component.For<IPersonRepository>().ImplementedBy<PersonRepository>().LifestyleTransient(),
        Component.For<IPersonAppService>().ImplementedBy<PersonAppService>().LifestyleTransient()
    );

var personService = container.Resolve<IPersonAppService>();
personService.CreatePerson("Yunus Emre", 19);

O TNF quase torna invisível o uso da estrutura de injeção de dependência ao escrever sua aplicação seguindo as práticas recomendadas e algumas convenções.

Essas convenções são explicadas a seguir nos próximos tópicos.

Registro de dependências por convenções

O TNF registra automaticamente todos os Repositórios, Serviços de Domínio, Serviços de Aplicação, Controladores MVC e Controladores da Web API por convenção. Por exemplo, você pode ter uma interface IPersonAppService e uma classe PersonAppService que implementa:

Conveções para serviços de aplicação
using Tnf.Dependency;
 
public interface IPersonAppService : IApplicationService
{
    //...
}

public class PersonAppService : IPersonAppService
{
    //...
}

O TNF registra automaticamente a classe que implementa a interface IApplicationService (É apenas uma interface vazia). Essa dependência é registrada como transient (instância criada por uso).

Quando você injeta (usando a injeção do construtor) IPersonAppService para uma classe, um objeto PersonAppService é criado e passado para o construtor automaticamente.

O registro de dependência por convenções se dá pela configuração do módulo, onde no método Initialize conterá o seguinte trecho de código:

Configuração de módulo
public class AppModule : TnfModule
{
    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

Para mais detalhes sobre criação e configuração de módulos no TNF.

Helper Interfaces

Você pode registrar uma classe (instancia) fazendo o uso de convenções através da herança das interfaces ITransientDependency e ISingletonDependency:

Injeção via convenção
public interface IPersonManager
{
    //...
}

public class MyPersonManager : IPersonManager, ISingletonDependency
{
    //...
}

A interface ITransientDependency registra os objetos no container como transientes (que poderiamos definir como instancia por utilização, pois é criada e finalizada ao final do processo).

A interface ISingletonDependency registra os objetos no container como singletons tendo apenas uma instancia em todo ciclo de vida da sua aplicação.

Registro de tipos de forma direta em módulos

Quando criamos uma módulo no TNF temos disponível o objeto IocManager para registrar as dependências daquele assembly. 

Usando IocManager

No exemplo a seguir registramos um serviço de forma transiente passando seu enum com o Life Scope desejado.

Registrando manualmente dependências
IocManager.Register<IMyService, MyService>(DependencyLifeStyle.Transient);

Usando o Castle Windsor API

Voce pode usar a propriedade IIocManager.IocContainer para acessar o Castle Windsor Container e registrar as dependências:

Registrando manualmente pelo Windsor API
IocManager.IocContainer.Register(Classes.FromThisAssembly().BasedOn<IMySpecialInterface>().LifestylePerThread().WithServiceSelf());

Resolvendo dependências

Toda classe registrada no injetor de DI pode ser resolvida automaticamente através da injeção pelo construtor ou usando o objeto de IocManager do TNF:

Singleton IocManager
IMyService instance = IocManager.Resolve<IMyService>();

Existem cenários onde é necessário criar uma instancia e após seu uso realizar sua liberação. Para esses casos o IocManager possui métodos de extensão que possibilitam a criação e a liberação desses recursos:

Injeção do IIocResolver
public class MySampleClass : ITransientDependency
{
    private readonly IIocResolver _iocResolver;

    public MySampleClass(IIocResolver iocResolver)
    {
        _iocResolver = iocResolver;
    }

    public void DoIt()
    {
        // Resolving, using and releasing manually
        var personService1 = _iocResolver.Resolve<PersonAppService>();
        personService1.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });
        _iocResolver.Release(personService1);

        // Resolving and using in a safe way
        using (var personService2 = _iocResolver.ResolveAsDisposable<PersonAppService>())
        {
            personService2.Object.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });
        }
    }
}

No cenário acima foi realizada a injeção do objeto IIocResolver para resolver o serviço e após finalizar sua instancia, usando manualmente o método Release e também utilizando a estrutura de using do C#

O mesmo cenário pode ser criado usando diretamente o objeto IocManager como no exemplo abaixo:

Resolvendo dependências manualmente
using Tnf.Dependency;

public class MySampleClass : ITransientDependency
{
    public void DoIt()
    {
        // Resolving, using and releasing manually
        var personService1 = IocManager.Instance.Resolve<PersonAppService>();
        personService1.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });
        _iocResolver.Release(personService1);

        // Resolving and using in a safe way
        using (var personService2 = IocManager.Instance.ResolveAsDisposable<PersonAppService>())
        {
            personService2.Object.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });
        }
    }
}

Note que o IocManager foi acessado desta forma neste exemplo: IocManager.Instance. Isso se dá porque este objeto implementa o pattern Singleton.

IShouldInitialize interface

Algumas classes precisam ser inicializadas antes da primeira utilização. A interface IShouldInitialize tem um método Initialize().

Se você implementá-lo, então o método Initialize() é chamado automaticamente apenas após a criação do objeto (antes usado).

IShouldInitialize.cs
using Tnf;
 
public interface IMyService : IShouldInitialize
{
}

public class MyService : IMyService
{
	public void Initialize()
	{
		// After initialization
	}
}
  • Sem rótulos