In previous article, We have created multiple projects to represent layers of Clean Architecture and also we explored how to implement the Domain Layer. Here in this article, we will explore the implementation of Application Infracture Layer
The Application Layer contains the application's business use cases and coordinates the execution of business operations. It defines service interfaces, repository contracts, and DTOs required to communicate between the API and the Domain Layer.
In our Employee Management application, we will create an employee service interface and its implementation to handle employee-related operations such as retrieving, adding, updating, and deleting employees. We will also define repository interfaces that specify the data operations required by the application.
ASP.NET Clean Architecture: Implementing the Application Layer in Web API
Getting Started
The Application Layer is responsible for handling the application's use cases and coordinating business operations. It acts as a bridge between the Domain Layer and the Infrastructure Layer.
In our Employee Management Web API, the Application Layer will handle employee-related operations such as creating, retrieving, updating, and deleting employees.
It will define the repository interfaces, DTOs, and application services required to perform these operations.
Let's implement the Application Layer step by step. Create the following folders:
</> Plain Text
CleanArchitectureDemo.Application
│
├── DTOs
│
├── Interfaces
│
└── Services
Each folder will have a specific responsibility:
| Folder | Responsibility |
|---|---|
| DTOs | Contains Data Transfer Objects |
| Interfaces | Defines repository and service contracts |
| Services | Contains application business workflows |
Step 1: Create Employee DTOs
DTO (Data Transfer Object) is used to transfer data between different layers of an application.
Instead of exposing Domain entities directly through API endpoints, we use DTOs to control the data entering and leaving the application.
Inside the DTOs folder, create the following classes.
CreateEmployeeDto.cs</> C#
namespace CleanArchitectureDemo.Application.DTOs;
public class CreateEmployeeDto
{
public string Name { get; set; }
public string Email { get; set; }
public decimal Salary { get; set; }
}
UpdateEmployeeDto.cs
</> C#
namespace CleanArchitectureDemo.Application.DTOs;
public class UpdateEmployeeDto
{
public string Name { get; set; }
public string Email { get; set; }
public decimal Salary { get; set; }
}
EmployeeDto.cs
</> C#
namespace CleanArchitectureDemo.Application.DTOs;
public class EmployeeDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public decimal Salary { get; set; }
}
We have separated the input and output DTOs to provide better control over the data exchanged through the application.
The CreateEmployeeDto.cs and UpdateEmployeeDto.cs will be used to create and update employee data, similarly EmployeeDto.cs will be used to fetch employee details
Step 2: Create the Employee Repository Interface
The Application Layer needs a way to access employee data. However, it should not directly depend on Entity Framework Core or SQL Server.
To achieve this, we define a repository interface in the Application Layer. Inside the Interfaces folder, create a new interface named IEmployeeRepository.cs.
</> C#
using CleanArchitectureDemo.Domain.Entities;
namespace CleanArchitectureDemo.Application.Interfaces;
public interface IEmployeeRepository
{
Task<IEnumerable<Employee>> GetAllAsync();
Task<Employee?> GetByIdAsync(int id);
Task AddAsync(Employee employee);
Task UpdateAsync(Employee employee);
Task DeleteAsync(Employee employee);
}
Let's understand these methods:
- GetAllAsync(): Retrieves all employees.
- GetByIdAsync(): Retrieves an employee using its ID.
- AddAsync(): Adds a new employee.
- UpdateAsync(): Updates an existing employee.
- DeleteAsync(): Deletes an employee.
Step 3: Create the Employee Service Interface
Next, we will define an interface for employee-related application operations. Inside the Interfaces folder, create IEmployeeService.cs.
</> C#
using CleanArchitectureDemo.Application.DTOs;
namespace CleanArchitectureDemo.Application.Interfaces;
public interface IEmployeeService
{
Task<IEnumerable<EmployeeDto>> GetAllAsync();
Task<EmployeeDto?> GetByIdAsync(int id);
Task<int> CreateAsync(CreateEmployeeDto dto);
Task<bool> UpdateAsync(
int id,
UpdateEmployeeDto dto);
Task<bool> DeleteAsync(int id);
}
This interface defines the operations that the Presentation Layer can use without knowing how they are implemented.
Step 4: Implement the Employee Service
Now, we will implement the employee-related application workflows.Inside the Services folder, create a class named EmployeeService.cs.
</> C#
using CleanArchitectureDemo.Application.DTOs;
using CleanArchitectureDemo.Application.Interfaces;
using CleanArchitectureDemo.Domain.Entities;
namespace CleanArchitectureDemo.Application.Services;
public class EmployeeService : IEmployeeService
{
private readonly IEmployeeRepository _repository;
public EmployeeService(IEmployeeRepository repository)
{
_repository = repository;
}
public async Task<IEnumerable<EmployeeDto>> GetAllAsync()
{
var employees = await _repository.GetAllAsync();
return employees.Select(e => new EmployeeDto
{
Id = e.Id,
Name = e.Name,
Email = e.Email,
Salary = e.Salary
});
}
public async Task<EmployeeDto?> GetByIdAsync(int id)
{
var employee = await _repository.GetByIdAsync(id);
if (employee == null)
return null;
return new EmployeeDto
{
Id = employee.Id,
Name = employee.Name,
Email = employee.Email,
Salary = employee.Salary
};
}
public async Task<int> CreateAsync(CreateEmployeeDto dto)
{
var employee = new Employee(
dto.Name,
dto.Email,
dto.Salary);
await _repository.AddAsync(employee);
return employee.Id;
}
public async Task<bool> UpdateAsync(
int id,
UpdateEmployeeDto dto)
{
var employee = await _repository.GetByIdAsync(id);
if (employee == null)
return false;
employee.UpdateDetails(
dto.Name,
dto.Email,
dto.Salary);
await _repository.UpdateAsync(employee);
return true;
}
public async Task<bool> DeleteAsync(int id)
{
var employee = await _repository.GetByIdAsync(id);
if (employee == null)
return false;
await _repository.DeleteAsync(employee);
return true;
}
}
Step 5: Configure Application Dependency Injection
We need to register the application services so that they can be resolved through ASP.NET Core dependency injection.
To keep dependency registration organized, create a new class named DependencyInjection.cs in the Application project.
DependencyInjection.cs</> C#
using CleanArchitectureDemo.Application.Interfaces;
using CleanArchitectureDemo.Application.Services;
using Microsoft.Extensions.DependencyInjection;
namespace CleanArchitectureDemo.Application;
public static class DependencyInjection
{
public static IServiceCollection AddApplication(
this IServiceCollection services)
{
services.AddScoped<IEmployeeService, EmployeeService>();
return services;
}
}
This extension method registers EmployeeService as the implementation of IEmployeeService.
Note: Install the Microsoft.Extensions.DependencyInjection.Abstractions package if the IServiceCollection namespace is not available in your Class Library project.
Final Application Project Structure
After completing the implementation, your Application project should look like this:</> Plain Text
CleanArchitectureDemo.Application
│
├── DTOs
│ ├── CreateEmployeeDto.cs
│ ├── UpdateEmployeeDto.cs
│ └── EmployeeDto.cs
│
├── Interfaces
│ ├── IEmployeeRepository.cs
│ └── IEmployeeService.cs
│
├── Services
│ └── EmployeeService.cs
│
└── DependencyInjection.cs
This ensures that the Application Layer focuses on application-specific operations without depending on external technologies. After completing these steps, our Application Layer is responsible for:
- Defining application use cases and business workflows.
- Managing communication between the Domain Layer and external dependencies.
- Defining repository interfaces required for data access.
- Handling business operations such as creating, updating, retrieving, and deleting employees.
- Defining Data Transfer Objects (DTOs) for transferring data between application layers.
- Coordinating business operations through services or handlers.
- Keeping application logic independent of infrastructure and presentation technologies.
In the next step, we will implement the Infrastructure Layer, where we configure Entity Framework Core, create the database context, and implement repository classes to handle database operations for our Employee Management application.
Summary
With the Application Layer in place, we have established the necessary structure for handling employee-related operations. It acts as a bridge between the Presentation and Infrastructure Layers through well-defined interfaces, keeping the application logic organized and independent of specific implementation details. This separation makes the application easier to maintain, test, and extend as new requirements are introduced.
Thanks