Quando falamos de camada de aplicação estamos falando da camada responsável por coordenar a entrada de informações, controlar acesso a funcionalidades, interligando ao nosso domínio de negocio e devolvendo a resposta em um formato que a aplicação espera.
Ela ainda pode fazer o controle de transação, além de poder enviar notificações para outros softwares, Injeção da dependência de determinadas fontes de dados.
Essa camada é a principal responsável por fazer a ligação de nossas regras de negocio com nossa infraestrutura de dados: Bancos relacionais, NoSQL, Serviços externos, etc.
Podemos defini-la como uma camada coordenadora de operações de negócio.
Pensa que poderíamos ter todas as nossas regras de negócio centralizadas em um único assembly, mas N camada de aplicação para N aplicações.
Nos tópicos a seguir vamos abordar alguns aspectos quando trabalhamos com essa camada:
Índice |
---|
Serviços de aplicação são usados para expor a lógica de domínio para a camada de apresentação.
Essa camada tem como principal objetivo aplicar todas as regras definidas para uma entidade ou para um processo, mantendo o domínio do negocio isolado fazendo a ligação da lógica do negocio com sua infraestrutura de dados.
No TNF a interface de um serviço de aplicação deve implementar IApplicationService. Essa interface já será registrada automaticamente no container de injeção de dependência através das convenções:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface ITaskAppService : IApplicationService
{
void CreateTask(CreateTaskInput input);
} |
Um serviço de aplicação deveria implementar a interface declarada acima. Toda implementação de um serviço de aplicação deve derivar da classe ApplicationService.
Essa classe expõe funcionalidades pré-definidas dentro da aplicação que facilitam seu uso como logging, localization:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public class TaskAppService : ApplicationService, ITaskAppService
{
public TaskAppService()
{
LocalizationSourceName = "SimpleTaskSystem";
}
public void CreateTask(CreateTaskInput input)
{
// Write some logs (Logger is defined in ApplicationService class)
Logger.Info("Creating a new task with description: " + input.Description);
// Get a localized text (L is a shortcut for LocalizationHelper.GetString(...), defined in ApplicationService class)
var text = L("SampleLocalizableTextKey");
// TODO: Add new task to database...
}
} |
Se você precisa criar um serviço de aplicação que terá uma operação de CRUD (acrônimo de Create, Read, Update e Delete) para uma entidade especifica, o TNF contém duas classes para agilizar esses processo: CrudAppService e AsyncCrudAppService.
Como essas classes são facilitadores, neste modelo não possui nenhuma implementação na camada de domínio. As validações são geradas em cima dos objetos que fazem o mapeamento com o banco de dados (Country) e DTOs (CountryDto).
A entidade abaixo realiza o mapeamento da tabela Countries para o Entity Framework Core:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
[AutoMap(typeof(CountryDto))]
[Table("Countries")]
public class Country : Entity
{
public const int MaxNameLength = 256;
[Required]
[MaxLength(MaxNameLength)]
public string Name { get; set; }
public Country()
{
}
public Country(int id, string name)
{
Id = id;
Name = name;
}
} |
Abaixo a definição do DTO usando uma validação customizada:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public class CountryDto : CustomValidate
{
public string Name { get; set; }
public override void AddValidationErrors(CustomValidationContext context)
{
if (string.IsNullOrWhiteSpace(Name))
{
context.Results.Add(new ValidationResult("Name is required"));
}
}
} |
Definição da interface do serviço de aplicação:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public interface ICountryAppService : IAsyncCrudAppService<CountryDto>
{
} |
Implementação do serviço de aplicação informando qual a entidade, DTO e realizando a herança da classe AsyncCrudAppService que irá definir que este serviço contem as funcionalidades de CRUD presentes no TNF:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
public class CountryAppService : AsyncCrudAppService<Country, CountryDto>, ICountryAppService
{
public CountryAppService(IRepository<Country> repository)
: base(repository)
{
}
} |
Note que o serviço recebe como parâmetro um repositório de dados para a entidade Country. Quem define a implementação para a interface IRepository neste exemplo é um nuget package do TNF que contém uma implementação de repositório para o Entity Framework Core chamado: "Tnf.App.EntityFrameworkCore".
O repositório padrão realiza o mapeamento da entidade automaticamente para o seu respectivo DTO através de outros pacotes chamados: Tnf.AutoMapper e Tnf.Dto.
...