Á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 muitas estruturas 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 a estrutura faz todo resto!

No TNF usamos a estrutura do Castle Windsor para Injeção de Dependência. É um dos Frameworks de DI mais maduros. Existem muitos outros frameworks como Unity, Ninject, StructureMap, Autofac e assim por diante.   

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
{
    //...
}

 

...

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

...

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 modulomó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

...

Usando IocManager:

...

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 cria 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:

Bloco de código
languagec#
firstline1
titleInjeção do IIocResolver
linenumberstrue
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:

Bloco de código
languagec#
firstline

...

1
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" });
        }
    }
}

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
	}
}