Implementing State Design Pattern in ASP.NET Core Web API with 3-Tier Architecture

In this ASP.NET Core Web API project utilizing a 3-Tier Architecture with the State Design Pattern, we've created a News management system that encapsulates the state of news items, allowing for a clear and structured way to handle state transitions. The architecture consists of three distinct layers: Presentation, Business Logic, and Data Access. The Business Logic layer is where the State Design Pattern is applied, with different states such as Draft, Published, and Archived, each represented by concrete state classes. The NewsService class is responsible for managing these states and their transitions.

Controllers in the Presentation layer handle HTTP requests and delegate the state-related operations to the NewsService, enabling CRUD functionality for news items. By setting the appropriate state and invoking state-specific methods, such as Publish and Archive, we control the state transitions. While this example focuses on the pattern's core implementation, in a real-world scenario, you would integrate a data access layer to persist and retrieve news items from a database, making it a robust and maintainable system.

Implementing the State Design Pattern in an ASP.NET Core Web API with a 3-Tier Architecture involves separating your application into different layers: Presentation, Business Logic, and Data Access, and using the State Pattern to manage the state of your entities. In this example, we'll create a simple News management system with complete CRUD operations.

Create a new ASP.NET Core Web API Project

You can create a new project using Visual Studio or by running dotnet new webapi -n CSharpCornerNewsApi.

Define the Layers


a. Presentation Layer

This layer includes your controllers, which will handle HTTP requests and responses.

b. Business Logic Layer (Service Layer)

This layer contains the business logic and state management using the State Design Pattern. In this layer, we'll define the states and the context.

c. Data Access Layer

This layer handles data access, such as interacting with a database. You can use Entity Framework or any other ORM.

Define the Model

// Sardar Mudassar Ali Khan
// Models/News.cs
public class News
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public NewsState State { get; set; }
}

public enum NewsState
{
    Draft,
    Published,
    Archived
}

Create a News State Context and Concrete States


a. Create an interface for the states

// Sardar Mudassar Ali Khan
// BusinessLogic/News/INewsState.cs
public interface INewsState
{
    void Publish(News news);
    void Archive(News news);
}

b. Implement concrete states

  • DraftState
    // Sardar Mudassar Ali Khan
    // BusinessLogic/News/DraftState.cs
    public class DraftState : INewsState
    {
        public void Publish(News news)
        {
            // Transition to the Published state
            news.State = NewsState.Published;
        }
    
        public void Archive(News news)
        {
            // Transition to the Archived state
            news.State = NewsState.Archived;
        }
    }
  • Published State

    // Sardar Mudassar Ali Khan
    // BusinessLogic/News/PublishedState.cs
    public class PublishedState: INewsState
    {
        public void Publish(News news)
        {
            // Transition to the Published state
            news.State = NewsState.Published;
        }
    
        public void Archive(News news)
        {
            // Transition to the Archived state
            news.State = NewsState.Archived;
        }
    }
  • Archived State

    // BusinessLogic/News/ArchivedState.cs
    public class ArchivedState: INewsState
    {
        public void Publish(News news)
        {
          news.State = NewsState.Published;
        }
    
        public void Archive(News news)
        {
          news.State = NewsState.Archived;
        }
    }
    

Create the Service Layer

Create a service that manages the state and business logic.

// Sardar Mudassar Ali Khan
// BusinessLogic/News/NewsService.cs
public class NewsService
{
    private INewsState _state;

    public void SetState(INewsState state)
    {
        _state = state;
    }

    public void Publish(News news)
    {
        _state.Publish(news);
    }

    public void Archive(News news)
    {
        _state.Archive(news);
    }
}

Create Controllers

Create a NewsController for handling CRUD operations.

// Sardar Mudassar Ali Khan
// Controllers/NewsController.cs
[Route("api/news")]
[ApiController]
public class NewsController : ControllerBase
{
    private readonly NewsService _newsService;

    public NewsController()
    {
        _newsService = new NewsService();
    }

    [HttpPost]
    public IActionResult CreateNews(News news)
    {
        news.State = NewsState.Draft;
        return Ok("News created successfully.");
    }

    [HttpPost("{id}/publish")]
    public IActionResult PublishNews(int id)
    {
        var news = GetNewsById(id);

        if (news == null)
        {
            return NotFound();
        }

        _newsService.SetState(new PublishedState());
        _newsService.Publish(news);
        return Ok("News published successfully.");
    }

    [HttpPost("{id}/archive")]
    public IActionResult ArchiveNews(int id)
    {
        var news = GetNewsById(id);

        if (news == null)
        {
            return NotFound();
        }

        _newsService.SetState(new ArchivedState());
        _newsService.Archive(news);
        return Ok("News archived successfully.");
    }

    [HttpGet("{id}")]
    public IActionResult GetNews(int id)
    {
        var news = GetNewsById(id);

        if (news == null)
        {
            return NotFound();
        }

        return Ok(news);
    }

}


Configure Dependency Injection

In your Startup.cs, configure dependency injection for your service layer.

services.AddScoped<NewsService>();

Implement Data Access Layer

In your data access layer, interact with your database using Entity Framework or any other data access technology.

Configure Routing and Middleware

Ensure that your API routes and middleware are correctly configured in your Startup. cs file.

Run the Application

You can run your ASP.NET Core Web API application using dotnet run or by using Visual Studio.

In this article, I have demonstrated how to use the State Design Pattern to manage the state of News items in an ASP.NET Core Web API with a 3-Tier Architecture. You can extend this pattern to handle more complex state transitions and integrate it with a database for persistent storage.

Conclusion

In this article, the code examples provided demonstrate the implementation of the State Design Pattern within an ASP.NET Core Web API with a 3-Tier Architecture for a News management system. This pattern is a powerful way to manage the state of entities and control their behavior based on their current state. In this specific scenario, we created three concrete states: DraftState, PublishedState, and ArchivedState, each responsible for handling the transitions between the different states of news items.

key takeaways from this implementation

  • Layered Architecture: We organized the application into three layers - Presentation, Business Logic, and Data Access. This separation of concerns enhances maintainability and modularity.
  • State Design Pattern: The State Design Pattern was applied to manage the state of news items, allowing for a clean and structured way to handle state transitions.
  • State-Specific Behavior: Each concrete state class contains methods for handling state-specific behavior, such as publishing or archiving news, ensuring that the appropriate actions are taken based on the current state.
  • Dependency Injection: We configured dependency injection for the service layer, which promotes testability and loose coupling.
  • HTTP Endpoints: The API exposes HTTP endpoints for creating, publishing, archiving, and retrieving news items, enabling CRUD operations.

This article provides a solid foundation. Real-world applications may require additional features such as data persistence using a database, authentication, authorization, and more. However, the demonstrated pattern and architecture can serve as a starting point for building scalable and maintainable web applications.


Similar Articles