DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • How to Enhance the Performance of .NET Core Applications for Large Responses
  • Developing Minimal APIs Quickly With Open Source ASP.NET Core
  • Revolutionizing Content Management
  • Architecting Scalable ASP.NET Core Web APIs With Abstract Factory Method and Onion Architecture

Trending

  • Spec-Driven Integration: Turning API Sprawl Into a Governed Capability Fleet for AI
  • Monitoring Spring Boot Applications with Prometheus and Grafana
  • Security Readiness Checklist: From AI Threats to Software Supply Chain Defense
  • How AI Is Rewriting the Rules of Software Security: Machine-Speed Delivery, Shifting Risk, and New Control Points
  1. DZone
  2. Data Engineering
  3. Databases
  4. Revolutionizing API Development: A Journey Through Clean Architecture With Adapter Pattern in ASP.NET Core

Revolutionizing API Development: A Journey Through Clean Architecture With Adapter Pattern in ASP.NET Core

Design patterns play a pivotal role in ensuring the maintainability, scalability, and flexibility of the codebase. One such pattern is the Adapter Design Pattern.

By 
Sardar Mudassar Ali Khan user avatar
Sardar Mudassar Ali Khan
·
Oct. 09, 23 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
3.0K Views

Join the DZone community and get the full member experience.

Join For Free

In the realm of software development, design patterns play a pivotal role in ensuring the maintainability, scalability, and flexibility of the codebase. One such pattern is the Adapter Design Pattern, which allows the interface of an existing class to be used as another interface, facilitating the integration of disparate systems. 

In this article, we'll explore how to implement the Adapter Design Pattern in an ASP.NET Core Web API using Clean Architecture. We'll use a model named DZoneArticles with properties, and we'll cover the complete CRUD (Create, Read, Update, Delete) operations along with the implementation of business logic in all methods. 

Prerequisites

Before diving into the implementation, make sure you have the following prerequisites:

  • Visual Studio or Visual Studio Code
  • .NET SDK installed (version 5.0 or later)
  • Basic understanding of ASP.NET Core Web API and Clean Architecture

Step 1: Setting up the Project

Start by creating a new ASP.NET Core Web API project. Open your terminal or command prompt and run the following commands:

C#
 
dotnet new webapi -n MyApi
cd APIDevelopmentWithCleanArchitectureAndAdapterPattern


Step 2: Creating the Clean Architecture Layers

Implementing Clean Architecture involves creating separate layers for different concerns. These layers typically include:

  1. Presentation Layer (API): Exposes endpoints and handles HTTP requests.
  2. Application Layer: Contains application-specific business logic.
  3. Domain Layer: Represents the core domain models and business rules.
  4. Infrastructure Layer: Deals with data access, external services, and other infrastructure concerns.

Create folders for each layer in your project and structure it accordingly.

Step 3: Defining the Model: DZoneArticles

In the Domain Layer, create a folder named Models. Inside this folder, define the DZoneArticles class with the required properties:

C#
 
// Sardar Mudassar Ali Khan
// Domain/Models/DZoneArticles.cs

namespace APIDevelopmentWithCleanArchitectureAndAdapterPattern.Domain.Models
{
    public class DZoneArticles
    {
        public int Id { get; set; }
        public string Title { get; set; }
    }
}


Step 4: Implementing the Repository Interface

In the Domain Layer, create a folder named Repositories. Inside this folder, define an interface for the repository that will handle CRUD operations:

C#
 
// Sardar Mudassar Ali Khan
// Domain/Repositories/IDZoneArticlesRepository.cs

using System.Collections.Generic;
using System.Threading.Tasks;

namespace APIDevelopmentWithCleanArchitectureAndAdapterPattern.Domain.Repositories
{
    public interface IDZoneArticlesRepository
    {
        Task<IEnumerable<DZoneArticles>> GetAllAsync();
        Task<DZoneArticles> GetByIdAsync(int id);
        Task AddAsync(DZoneArticles article);
        Task UpdateAsync(DZoneArticles article);
        Task DeleteAsync(int id);
    }
}


Step 5: Implementing the Repository

In the Infrastructure Layer, create a folder named Repositories. Inside this folder, implement the IDZoneArticlesRepository interface:

C#
 
// Sardar Mudassar Ali Khan
// Infrastructure/Repositories/DZoneArticlesRepository.cs

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; // Add this namespace
using MyApi.Domain.Models;
using MyApi.Domain.Repositories;

namespace APIDevelopmentWithCleanArchitectureAndAdapterPattern.Infrastructure.Repositories
{
    public class DZoneArticlesRepository : IDZoneArticlesRepository
    {
        private readonly YourDbContext _dbContext; // Replace YourDbContext with your actual DbContext class

        public DZoneArticlesRepository(YourDbContext dbContext) // Replace YourDbContext
        {
            _dbContext = dbContext;
        }

        public async Task<IEnumerable<DZoneArticles>> GetAllAsync()
        {
            return await _dbContext.DZoneArticles.ToListAsync();
        }

        public async Task<DZoneArticles> GetByIdAsync(int id)
        {
            return await _dbContext.DZoneArticles.FindAsync(id);
        }

        public async Task AddAsync(DZoneArticles article)
        {
            _dbContext.DZoneArticles.Add(article);
            await _dbContext.SaveChangesAsync();
        }

        public async Task UpdateAsync(DZoneArticles article)
        {
            _dbContext.Entry(article).State = EntityState.Modified;
            await _dbContext.SaveChangesAsync();
        }

        public async Task DeleteAsync(int id)
        {
            var articleToDelete = await _dbContext.DZoneArticles.FindAsync(id);
            if (articleToDelete != null)
            {
                _dbContext.DZoneArticles.Remove(articleToDelete);
                await _dbContext.SaveChangesAsync();
            }
        }
    }
}


Step 6: Creating the Adapter

Create an adapter class that adapts the repository interface to the application's needs. This adapter will be in the Application Layer:

C#
 
// Sardar Mudassar Ali Khan
// Application/Adapters/DZoneArticlesAdapter.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using MyApi.Domain.Models;
using MyApi.Domain.Repositories;

namespace APIDevelopmentWithCleanArchitectureAndAdapterPattern.Application.Adapters
{
    public class DZoneArticlesAdapter
    {
        private readonly IDZoneArticlesRepository _repository;

        public DZoneArticlesAdapter(IDZoneArticlesRepository repository)
        {
            _repository = repository;
        }

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

        public async Task<DZoneArticles> GetArticleByIdAsync(int id)
        {
            return await _repository.GetByIdAsync(id);
        }

        public async Task AddArticleAsync(DZoneArticles article)
        {
            await _repository.AddAsync(article);
        }

        public async Task UpdateArticleAsync(DZoneArticles article)
        {
            await _repository.UpdateAsync(article);
        }

        public async Task DeleteArticleAsync(int id)
        {
            await _repository.DeleteAsync(id);
        }
    }
}


Step 7: Presentation Layer

In the API Layer, use dependency injection to inject the adapter into your controllers:

C#
 
// Sardar Mudassar Ali Khan
// Presentation/Controllers/DZoneArticlesController.cs

using Microsoft.AspNetCore.Mvc;
using MyApi.Application.Adapters;
using MyApi.Domain.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace APIDevelopmentWithCleanArchitectureAndAdapterPattern.Presentation.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class DZoneArticlesController : ControllerBase
    {
        private readonly DZoneArticlesAdapter _adapter;

        public DZoneArticlesController(DZoneArticlesAdapter adapter)
        {
            _adapter = adapter;
        }

        [HttpGet]
        public async Task<ActionResult<IEnumerable<DZoneArticles>>> GetAllArticles()
        {
            try
            {
                var articles = await _adapter.GetAllArticlesAsync();
                return Ok(articles);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }

        [HttpGet("{id}")]
        public async Task<ActionResult<DZoneArticles>> GetArticleById(int id)
        {
            try
            {
                var article = await _adapter.GetArticleByIdAsync(id);
                if (article == null)
                {
                    return NotFound($"Article with ID {id} not found");
                }

                return Ok(article);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }

        [HttpPost]
        public async Task<ActionResult> AddArticle([FromBody] DZoneArticles article)
        {
            try
            {
                await _adapter.AddArticleAsync(article);
                return CreatedAtAction(nameof(GetArticleById), new { id = article.Id }, article);
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }

        [HttpPut("{id}")]
        public async Task<ActionResult> UpdateArticle(int id, [FromBody] DZoneArticles article)
        {
            try
            {
                if (id != article.Id)
                {
                    return BadRequest("ID mismatch");
                }

                await _adapter.UpdateArticleAsync(article);
                return NoContent();
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }

        [HttpDelete("{id}")]
        public async Task<ActionResult> DeleteArticle(int id)
        {
            try
            {
                await _adapter.DeleteArticleAsync(id);
                return NoContent();
            }
            catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }
    }
}


Ensure that you've registered your dependencies in the Startup.cs file:

C#
 
// Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    // Other configurations...

    // Register repositories and adapters
    services.AddScoped<IDZoneArticlesRepository, DZoneArticlesRepository>();
    services.AddScoped<DZoneArticlesAdapter>();

    // Other configurations...
}


Conclusion

Implementing the Adapter Design Pattern in an ASP.NET Core Web API with Clean Architecture involves creating well-defined layers, each responsible for a specific aspect of the application. By adhering to this architectural pattern, you ensure the separation of concerns, maintainability, and scalability of your codebase.

Remember to adapt the code examples to fit your specific use case and requirements. This guide provides a solid foundation, but customization based on your project's needs is crucial for a successful implementation.

API ASP.NET ASP.NET Core Architecture

Opinions expressed by DZone contributors are their own.

Related

  • How to Enhance the Performance of .NET Core Applications for Large Responses
  • Developing Minimal APIs Quickly With Open Source ASP.NET Core
  • Revolutionizing Content Management
  • Architecting Scalable ASP.NET Core Web APIs With Abstract Factory Method and Onion Architecture

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook