Asp.Net Web Api Syllabus

Clean Architecture

Clean Architecture is a software design approach introduced by Robert C. Martin (Uncle Bob) to build maintainable, testable, and flexible applications. It emphasizes separating concerns and decoupling dependencies to create systems that are easier to extend and modify.

This tutorial will walk you through Clean Architecture concepts, its structure, and a step-by-step implementation using .NET Core as an example.

Key Principles of Clean Architecture

  1. Independent of Frameworks: The business logic should not depend on external frameworks, making it portable across environments.
  2. Testable: The application should be testable independently of external elements like UI or database.
  3. Independent of UI or Database: Core business logic should not depend on how data is presented or stored.
  4. Separation of Concerns: Divide the system into layers, each focusing on specific responsibilities.

Layers of Clean Architecture

1. Entities (Core Business Logic)

  • Contains the application’s core business rules.
  • Represents the core business logic and domain models.
  • Should not depend on any external libraries.

2. Use Cases (Application Logic)

  • Implements application-specific business rules.
  • Orchestrates the flow of data between entities and external systems.
  • Handles input validation, transformations, and other application tasks.

3. Interface Adapters

  • Converts data from external systems into a format suitable for use cases or entities.
  • Manages communication between the core and the outer layers (UI, database).

4. Frameworks and Drivers

  • Contains external components like databases, UI frameworks, or third-party libraries.
  • These components should depend on the inner layers, not the other way around.

Dependency Rule

The most important rule in Clean Architecture is the Dependency Rule:
Dependencies must point inward, meaning inner layers (like entities) should not depend on outer layers (like frameworks).

Clean Architecture in .NET Core: Step-by-Step Implementation

Project Setup

We’ll create a simple application for managing a To-Do List using Clean Architecture.

1. Create Project Structure

Organize your solution into the following layers:

  - ToDoApp.Core (Entities and Use Cases)
- ToDoApp.Application (Application Logic)
- ToDoApp.Infrastructure (Frameworks and Drivers)
- ToDoApp.WebAPI (Presentation Layer)

Implementation

1. Entities Layer

Create a ToDoApp.Core project:

namespace ToDoApp.Core.Entities
{
public class ToDoItem
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsCompleted { get; set; }
}
}

2. Use Cases Layer

Create a ToDoApp.Application project:

  • Define interfaces and implement use case logic.

Interface:

namespace ToDoApp.Application.Interfaces
{
public interface IToDoRepository
{
Task<IEnumerable<ToDoItem>> GetAllAsync();
Task<ToDoItem> GetByIdAsync(int id);
Task AddAsync(ToDoItem toDoItem);
Task UpdateAsync(ToDoItem toDoItem);
Task DeleteAsync(int id);
}
}

Use Case:

namespace ToDoApp.Application.UseCases
{
public class GetAllToDosUseCase
{
private readonly IToDoRepository _repository;

public GetAllToDosUseCase(IToDoRepository repository)
{
_repository = repository;
}

public async Task<IEnumerable<ToDoItem>> ExecuteAsync()
{
return await _repository.GetAllAsync();
}
}
}

3. Infrastructure Layer

Create a ToDoApp.Infrastructure project:

  • Implement interfaces and manage data persistence.

Repository Implementation:

using ToDoApp.Application.Interfaces;
using ToDoApp.Core.Entities;

namespace ToDoApp.Infrastructure.Data
{
public class ToDoRepository : IToDoRepository
{
private readonly List<ToDoItem> _dataStore = new();

public Task<IEnumerable<ToDoItem>> GetAllAsync() => Task.FromResult(_dataStore.AsEnumerable());

public Task<ToDoItem> GetByIdAsync(int id) =>
Task.FromResult(_dataStore.FirstOrDefault(t => t.Id == id));

public Task AddAsync(ToDoItem toDoItem)
{
_dataStore.Add(toDoItem);
return Task.CompletedTask;
}

public Task UpdateAsync(ToDoItem toDoItem)
{
var item = _dataStore.FirstOrDefault(t => t.Id == toDoItem.Id);
if (item != null)
{
item.Title = toDoItem.Title;
item.IsCompleted = toDoItem.IsCompleted;
}
return Task.CompletedTask;
}

public Task DeleteAsync(int id)
{
var item = _dataStore.FirstOrDefault(t => t.Id == id);
if (item != null) _dataStore.Remove(item);
return Task.CompletedTask;
}
}
}

4. Presentation Layer

Create a ToDoApp.WebAPI project:

  • Use ASP.NET Core to expose endpoints.

Controller:

using Microsoft.AspNetCore.Mvc;
using ToDoApp.Application.Interfaces;
using ToDoApp.Application.UseCases;

namespace ToDoApp.WebAPI.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ToDoController : ControllerBase
{
private readonly GetAllToDosUseCase _getAllToDosUseCase;

public ToDoController(GetAllToDosUseCase getAllToDosUseCase)
{
_getAllToDosUseCase = getAllToDosUseCase;
}

[HttpGet]
public async Task<IActionResult> Get()
{
var todos = await _getAllToDosUseCase.ExecuteAsync();
return Ok(todos);
}
}
}

Final Steps

  1. Dependency Injection: Register all dependencies (e.g., IToDoRepository and its implementation) in the Startup.cs or Program.cs.csharpCopy codeservices.AddScoped<IToDoRepository, ToDoRepository>(); services.AddScoped<GetAllToDosUseCase>();
  2. Run the Application:
    • Build and run the Web API.
    • Test endpoints using Postman or Swagger.

Advantages of Clean Architecture

  1. Scalability: Easily add new features without disrupting existing functionality.
  2. Maintainability: Decoupled layers make updates and bug fixes less risky.
  3. Testability: Each layer can be tested independently.
  4. Flexibility: Easily swap frameworks or external libraries without affecting core logic.

Conclusion

Clean Architecture provides a robust framework for designing scalable and maintainable software. By adhering to its principles, you can create applications that are not only efficient but also easy to extend and test.

Leave a Comment

Your email address will not be published. Required fields are marked *