Building a Robust ASP.NET Core Web API with Singleton Design Pattern and Three-Tier Architecture

Singleton Design Pattern in an ASP.NET Core Web API using a Three-Tier Architecture for a model named CSharpCornerArticle with complete CRUD operations.

Step 1. Create CSharpCornerArticle Model

Firstly, let's define the CSharpCornerArticle model:

// Sardar Mudassar Ali Khan
public class CSharpCornerArticle
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    // Add other properties as needed
}

Step 2. Create Data Access Layer 

Next, let's create the Data Access Layer (DAL) responsible for handling data operations. Here, we'll use a Singleton pattern for the data context:

// Sardar Mudassar Ali Khan
// Data Access Layer
public class CSharpCornerArticleRepository
{
    private static CSharpCornerArticleRepository _instance;
    private List<CSharpCornerArticle> _articles;

    private CSharpCornerArticleRepository()
    {
        _articles = new List<CSharpCornerArticle>();
        // You can initialize data or connect to a database here
    }

    public static CSharpCornerArticleRepository Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new CSharpCornerArticleRepository();
            }
            return _instance;
        }
    }

    public List<CSharpCornerArticle> GetAllArticles()
    {
        return _articles;
    }

    public CSharpCornerArticle GetArticleById(int id)
    {
        return _articles.FirstOrDefault(a => a.Id == id);
    }

    public void AddArticle(CSharpCornerArticle article)
    {
        // Add validation and error handling as needed
        _articles.Add(article);
    }

    public void UpdateArticle(CSharpCornerArticle article)
    {
        // Add validation and error handling as needed
        var existingArticle = _articles.FirstOrDefault(a => a.Id == article.Id);
        if (existingArticle != null)
        {
            existingArticle.Title = article.Title;
            existingArticle.Content = article.Content;
            // Update other properties as needed
        }
    }

    public void DeleteArticle(int id)
    {
        // Add validation and error handling as needed
        var articleToRemove = _articles.FirstOrDefault(a => a.Id == id);
        if (articleToRemove != null)
        {
            _articles.Remove(articleToRemove);
        }
    }
}

Step 3. Create a Services layer

Now, let's create a Service Layer to interact with the Data Access Layer:

// Sardar Mudassar Ali Khan
// Service Layer
public class CSharpCornerArticleService
{
    private readonly CSharpCornerArticleRepository _repository;

    public CSharpCornerArticleService()
    {
        _repository = CSharpCornerArticleRepository.Instance;
    }

    public List<CSharpCornerArticle> GetAllArticles()
    {
        return _repository.GetAllArticles();
    }

    public CSharpCornerArticle GetArticleById(int id)
    {
        return _repository.GetArticleById(id);
    }

    public void AddArticle(CSharpCornerArticle article)
    {
        _repository.AddArticle(article);
    }

    public void UpdateArticle(CSharpCornerArticle article)
    {
        _repository.UpdateArticle(article);
    }

    public void DeleteArticle(int id)
    {
        _repository.DeleteArticle(id);
    }
}

Step 4. Create a Presentation layer 

Finally, let's create a Controller in the Presentation Layer (Web API) to handle HTTP requests:

// Sardar Mudassar Ali Khan
// Controller
[ApiController]
[Route("api/[controller]")]
public class CSharpCornerArticleController : ControllerBase
{
    private readonly CSharpCornerArticleService _service;

    public CSharpCornerArticleController()
    {
        _service = new CSharpCornerArticleService();
    }

    [HttpGet]
    public IActionResult GetAllArticles()
    {
        var articles = _service.GetAllArticles();
        return Ok(articles);
    }

    [HttpGet("{id}")]
    public IActionResult GetArticleById(int id)
    {
        var article = _service.GetArticleById(id);
        if (article == null)
        {
            return NotFound();
        }
        return Ok(article);
    }

    [HttpPost]
    public IActionResult AddArticle([FromBody] CSharpCornerArticle article)
    {
        _service.AddArticle(article);
        return CreatedAtAction(nameof(GetArticleById), new { id = article.Id }, article);
    }

    [HttpPut("{id}")]
    public IActionResult UpdateArticle(int id, [FromBody] CSharpCornerArticle article)
    {
        var existingArticle = _service.GetArticleById(id);
        if (existingArticle == null)
        {
            return NotFound();
        }
        article.Id = id;
        _service.UpdateArticle(article);
        return NoContent();
    }

    [HttpDelete("{id}")]
    public IActionResult DeleteArticle(int id)
    {
        var existingArticle = _service.GetArticleById(id);
        if (existingArticle == null)
        {
            return NotFound();
        }
        _service.DeleteArticle(id);
        return NoContent();
    }
}

This example provides a basic structure for a Three-Tier Architecture in an ASP.NET Core Web API, implementing a Singleton Design Pattern for the Data Access Layer. Remember to adjust the code based on your specific requirements and consider using dependency injection for better testability and maintainability.

Conclusion

This article covered the implementation of a robust ASP.NET Core Web API using the Singleton Design Pattern and a Three-Tier Architecture for handling CRUD operations on the CSharpCornerArticle model. The key components included the Model representing the data structure, a Singleton-based Data Access Layer (DAL) responsible for data operations, a Service Layer to interact with the DAL, and a Controller in the Presentation Layer to handle HTTP requests.

The Singleton Design Pattern was employed in the DAL to ensure a single instance of the repository throughout the application, providing centralized and efficient access to data. This design pattern promotes reusability, and maintainability, and helps manage shared resources effectively.

The Three-Tier Architecture separated concerns into distinct layers, promoting a modular and scalable design. The Model encapsulated the data structure, the Service Layer orchestrated business logic, and the Controller handled HTTP requests, ensuring a clear separation of responsibilities.

Additionally, the article emphasized the importance of considering dependency injection for better testability and maintainability. Dependency injection allows for the easy replacement of components and facilitates unit testing by decoupling dependencies.

By following the principles outlined in this article, developers can create a well-structured, maintainable, and scalable ASP.NET Core Web API, adhering to best practices in software architecture and design.