Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.
Índice

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 lida com o 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 faz todo resto!

No TNF usamos a estrutura do Castle Windsor para Injeção de Dependência. É um dos Frameworks de DI mais maduros. 

Para suporte a injeção de dependência instale o Tnf via nuget em nosso package source: https://www.myget.org/F/tnf/api/v3/index.json

Abaixo temos um exemplo de utilização do Castle Windsor para registro da dependência fazendo seu uso através de injeção via construtor e utilizando o container para resolver a dependência manualmente.

Bloco de código
languagec#
firstline1
titleExemplo manual
linenumberstrue
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.

Registro de dependências por convenções

O TNF registra automaticamente todos os Repositórios (IRepository), Serviços de Domínio (IDomainService), Serviços de Aplicação (IApplicationService), Controladores MVC e Controladores da Web API (TnfController) por convenção.

Por exemplo, você pode ter uma interface IPersonAppService e uma classe PersonAppService que implementa:

Bloco de código
languagec#
firstline1
titleConveções para serviços de aplicação
linenumberstrue
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)A injeção através de convenção acontece pela herança da interface IApplicationService. Essa dependência é registrada como transient (instância criada por uso).

Quando você injeta (usando a injeção do construtor) IPersonAppService interface 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:

Bloco de código
languagec#
firstline1
titleConfiguração de módulo
linenumberstrue
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 especifica (instancia) fazendo o uso de convenções através da herança das interfaces ITransientDependency e ISingletonDependency:

Bloco de código
languagec#
firstline1
titleInjeção via convenção
linenumberstrue
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. 

No método Initialize de nosso módulo podemos fazer o registro da depedência:

Usando IocManager

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

Bloco de código
languagec#
firstline1
titleRegistrando manualmente dependências
linenumberstrue
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:

Bloco de código
languagec#
firstline1
titleRegistrando manualmente pelo Windsor API
linenumberstrue
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 de uma classe ou usando o objeto de IocManager do TNF:

Bloco de código
languagec#
firstline1
titleSingleton IocManager
linenumberstrue
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 objeto de IocManager possui métodos de extensão que possibilitam a criação e a liberação desses recursos:

...

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:

Bloco de código
languagec#
firstline1
titleResolvendo dependências manualmente
linenumberstrue
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" });
        }
    }
}
IShouldInitialize interface

Note que o IocManager foi acessado desta forma neste exemplo: IocManager.Instance. Isso se dá porque este objeto implementa o pattern Singleton e está acessivel em qualquer ponto de sua aplicação.

IShouldInitialize interface

As vezes precisamos executar determinada tarefa (ação) ao criar um objeto.

 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() é que se implementado será chamado automaticamente apenas após a criação do objeto (antes de ser usado).

Bloco de código
languagec#
firstline1
titleIShouldInitialize.cs
linenumberstrue
using Tnf;
 
public interface IMyService : IShouldInitialize
{
}

public class MyService : IMyService
{
	public void Initialize()
	{
		// After initialization
	}
}