Blog / Design Patterns
The Chain of Responsibility Design Pattern in C# and .Net
  • Dec 28, 2020
  • 69
  • 99

The first design pattern in the Behavioral Category is the Chain of Responsibility Design Pattern. Let's take a look at this design pattern to see when and how to implement it in C# and .Net.

Note: Code can be downloaded at my Github


Advertisement
 


1. What is the Chain of Responsibility Design Pattern?

Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.

Chain of responsibility design pattern gives more than one object an opportunity to handle a request by linking receiving objects together in form of a chain.

2. When to implement the Chain of Responsibility Design Pattern?

In general, the Chain of Responsibility is used when:

  • Your application is expected to process different requests in various ways, but you don't know the exact type of the request and the sequences are unknown beforehand
  • It's essential to execute several handler in a particular order
  • The set of handlers and their order are supposed to change at runtime

For example, you are building an online ordering system. The system requires the ordering process to be executed in sequence so that the order can be placed successfully. Your task is to building this system which is also easy to enhance in the future if there are requirements on adding steps into the existing sequence. The Chain of Responsibility Design Pattern is here to help you achieve this purpose.

3. How to implement the Chain of Responsibility Design Pattern?

We will build the online ordering system we mentioned in the example above. The sequence of the ordering process is like below:
   User Authenticated > Cart Has Items > Address Is Provided > Payment Method Is Provided

1
2
3
4
5
6
7
8
public class Order
{
    public Guid ID { get; set; } = Guid.NewGuid();
    public string Cart { get; set; } = null;
    public string Address { get; set; } = null;
    public string Payment { get; set; } = null;
    public bool IsAuthenticated { get; set; } = false;
}

Below are steps to implement the Chain of Responsibility Design Pattern:

Step 1: Create a Handler Interface

1
2
3
4
5
6
public interface IHandler
{
    IHandler SetNext(IHandler handler);
 
    string Handle(Order order);
}

Step 2: Create a Handler Abstract Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
abstract class AbstractHandler : IHandler
{
    private IHandler _nextHandler;
 
    public IHandler SetNext(IHandler handler)
    {
        this._nextHandler = handler;
 
        // Returning a handler from here will let us link handlers in a
        // convenient way like this:
        // monkey.SetNext(squirrel).SetNext(dog);
        return handler;
    }
 
    public virtual string Handle(Order order)
    {
        if (this._nextHandler != null)
        {
            return this._nextHandler.Handle(order);
        }
        else
        {
            return null;
        }
    }
}

Step 3: Create Handler classes for each step in sequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class AuthenticationHandler : AbstractHandler
{
    public override string Handle(Order order)
    {
        if (!order.IsAuthenticated)
        {
            return $"Authentication: The request is not valid.";
        }
        else
        {
            Console.WriteLine($"   Authentication: Passed Authentication Handler.");
            return base.Handle(order);
        }
    }
}
 
class CartHandler : AbstractHandler
{
    public override string Handle(Order order)
    {
        if (string.IsNullOrEmpty(order.Cart))
        {
            return $"Cart: The cart is empty.";
        }
        else
        {
            Console.WriteLine($"   Cart: Passed Cart Handler.");
            return base.Handle(order);
        }
    }
}
 
class AddressHandler : AbstractHandler
{
    public override string Handle(Order order)
    {
        if (string.IsNullOrEmpty(order.Address))
        {
            return $"Address: The address is not provided.";
        }
        else
        {
            Console.WriteLine($"   Authentication: Passed Address Handler.");
            return base.Handle(order);
        }
    }
}
 
class PaymentHandler : AbstractHandler
{
    public override string Handle(Order order)
    {
        if (string.IsNullOrEmpty(order.Payment))
        {
            return $"Payment: The payment method is not provided.";
        }
        else
        {
            Console.WriteLine($"   Payment: Passed Payment Handler.");
            return base.Handle(order);
        }
    }
}

Done! Now you can test the Chain of Responsibility Design Pattern in your application. Also, the sequence of steps can be changed based on your needs.

class Program
{
    static void Main(string[] args)
    {
        List<Order> orders = new List<Order>() { 
            new Order(),
            new Order()
            {
                IsAuthenticated = true
            },
            new Order()
            {
                Cart = "Orange, Banana, Pork",
                IsAuthenticated = true
            },
            new Order()
            {
                Cart = "Samsung Galaxy S9",
                IsAuthenticated = true,
                Address = "Brooklyn, NY"
            },
            new Order()
            {
                Cart = "Macbook Pro",
                IsAuthenticated = true,
                Address = "Brooklyn, NY",
                Payment = "Credit Card"
            }
        };

        var authentication = new AuthenticationHandler();
        var cart = new CartHandler();
        var address = new AddressHandler();
        var payment = new PaymentHandler();

        authentication.SetNext(cart).SetNext(address).SetNext(payment);

        Client.ClientCode(authentication, orders);
        Console.WriteLine();
    }
}
class Client
{
    // The client code is usually suited to work with a single handler. In
    // most cases, it is not even aware that the handler is part of a chain.
    public static void ClientCode(AbstractHandler handler, List<Order> orders)
    {
        foreach (var o in orders)
        {
            Console.WriteLine($"Client: Processing Order ID: {o.ID}");

            var result = handler.Handle(o);

            if (result != null)
            {
                Console.Write($"   {result}");
            }
            else
            {
                Console.WriteLine($"   Order {o.ID} is processed successfully!");
            }
            Console.WriteLine($"\n");
        }
    }
}

Output:


4. Conclusion

With the help of the Chain of Responsibility Design Pattern, your application can be ensured to run in process that you prefer. I hope this article helps you to build a better application. Please let me know your thoughts by commenting below.


If you have a Website or a Web API developed by using .Net Core and looking for a way to publish your applications, this post will explain how to do it using GoDaddy Windows Hosting.Note: at this mome ...

Search text in Stored Procedure in SQL SELECT DISTINCT o.name AS Object_Name, o.type_desc FROM sys.sql_modules m INNER JOIN sys.objects o ON m.object_id = o ...

Using cherry-pick to select specific commits for your Pull Request.1. Create a new branch based on the target of the Pull Requestgit branch cherry-branch origin/master2. Switch to a new branchgit chec ...

After deployment Angular and API on IIS, it's working fine unless I refresh the page. Once refreshed, the web encountered 404 error. In this article, I will explain how to resolve this.Since Angular i ...

There are some benefits of keeping both UI and API parts in the same place for small projects. In this article, I will explain how I did to deploy Angular Web and ASP .Net Core API in the same folder ...

I got CORS error after publishing my API and Angular app to IIS even though CORS is enabled and the origins of the Angular app is added. Below is how I resolved this issue.Just simple, make sure you s ...

1. The Situation:Error Message:&nbsp;Pulse Secure Application failed to load Java. Please install correct JRE version.Description: This issue happens when I'm using a M1 Mac with a correct version of ...

Accelerated Mobile Pages (AMP)&nbsp;focuses on delivering static content from publishers as quickly as possible and possibly rewards early adopters with a boost in rank. Let's see how to implement it ...

Below is how to decrypt/convert a Hex string value into text using VB.Net:Decrypting Hex string value to string in VB.Net Function HexToString(ByVal hex As String) As String Dim text As New Sy ...