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
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

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

  • Securing the Future: Best Practices for Privacy and Data Governance in LLMOps
  • Driving DevOps With Smart, Scalable Testing
  • Memory Leak Due to Time-Taking finalize() Method
  • System Coexistence: Bridging Legacy and Modern Architecture
  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
2.6K 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
Oops! Something Went Wrong

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

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

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 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!