Chain Of Responsibility Pattern C#

Contents

What Is Chain Of Responsibility Pattern?

The Chain of Responsibility is an ordered list of message handlers that know how to do two things; process a specific type of message, or pass the message along to the next message handler in the chain.

The Chain of Responsibility provides a simple mechanism to decouple the sender of a message from the receiver.

The Chain of Responsibility has several traits. The sender is only aware of one receiver. Each receiver is only aware of the next receiver. Receivers process the message or send it down the chain. The sender does not know who received the message. The first receiver to handle the message terminates the chain.

In this respect, the order of the receiver list matters. If the first receiver and the second receiver can both handle the same type of message, some sort of message handling priority would have to be built-in to the list.

Below is the UML and sequence diagram of Chain Of Responsibility pattern from Wikipedia.

UML and sequence diagram of Chain Of Responsibility pattern

Chain Of Responsibility Pattern Example

Example 1

One of the great examples of the Chain of Responsibility pattern is the ATM Dispense machine. The user enters the amount to be dispensed and the machine checks if the amount is dispensable in terms of defined currency bills such as 50$, 20$, 10$, etc.

We will use the Chain of Responsibility pattern to implement this solution. The chain will process the request in the same order as the below image.

We can implement this solution easily in a single program itself but then the complexity will increase and the solution will be tightly coupled. So we will create a chain of dispense systems to dispense bills of 50$, 20$ and 10$.

  1 namespace ATMDispenserExample
  2 {
  3     class Program
  4     {
  5         static void Main(string[] args)
  6         {
  7 
  8             //create handlers
  9             var bills50s = new CurrencyBill(50, 1);
 10             var bills20s = new CurrencyBill(20, 2);
 11             var bills10s = new CurrencyBill(10, 5);
 12 
 13             //set handlers pipeline
 14             bills50s.RegisterNext(bills20s)
 15                     .RegisterNext(bills10s);
 16 
 17             //client code that uses the handler
 18             while (true)
 19             {
 20                 Console.WriteLine("Please enter amount to dispense:");
 21                 var isParsed = int.TryParse(Console.ReadLine(), out var amount);
 22 
 23                 if (isParsed)
 24                 {
 25 
 26                     //sender pass the request to first handler in the pipeline
 27                     var isDepensible = bills50s.DispenseRequest(amount);
 28                     if (isDepensible)
 29                     {
 30                         Console.WriteLine($"Your amount ${amount} is dispensable!");
 31                     }
 32                     else
 33                     {
 34                         Console.WriteLine($"Failed to dispense ${amount}!");
 35                     }
 36                 }
 37                 else
 38                 {
 39                     Console.WriteLine("Please enter a valid amount to dispense");
 40                 }
 41             }
 42         }
 43     }
 44 
 45 
 46     public class CurrencyBill
 47     {
 48         private CurrencyBill next = CurrencyBill.Zero; //sets default handler instead of null object
 49         private static readonly CurrencyBill Zero;
 50 
 51         public int Denomination { get; }
 52         public int Quantity { get; }
 53 
 54         //A static constructor that initializes static Zero property
 55         //This property is used as default next handler instead of a null object
 56         static CurrencyBill()
 57         {
 58             Zero = new ZeroCurrencyBill();
 59         }
 60 
 61         //Use to set static Zero property
 62         //Will always return false at it cannot process any given amount.
 63         public class ZeroCurrencyBill : CurrencyBill
 64         {
 65             public ZeroCurrencyBill() : base(0, 0)
 66             {
 67             }
 68 
 69             public override bool DispenseRequest(int amount)
 70             {
 71                 return false;
 72             }
 73         }
 74 
 75         //CurrencyBill constructor that set the denomination value and quantity
 76         public CurrencyBill(int denomination, int quantity)
 77         {
 78             Denomination = denomination;
 79             Quantity = quantity;
 80         }
 81 
 82         //Method that set next handler in the pipeline
 83         public CurrencyBill RegisterNext(CurrencyBill currencyBill)
 84         {
 85             next = currencyBill;
 86             return next;
 87         }
 88 
 89         //Method that processes the request or passes it to the next handler
 90         public virtual bool DispenseRequest(int amount)
 91         {
 92             if (amount >= Denomination)
 93             {
 94                 var num = Quantity;
 95                 var remainder = amount;
 96                 while (remainder >= Denomination && num > 0)
 97                 {
 98                     remainder -= Denomination;
 99                     num--;
100                 }
101 
102                 if (remainder != 0)
103                 {
104                     return next.DispenseRequest(remainder);
105                 }
106 
107                 return true;
108             }
109             else
110             {
111                 return next.DispenseRequest(amount);
112             }
113 
114         }
115     }
116 }
1 Please enter amount to dispense:
2 140
3 Your amount $140 is dispensable!
4 Please enter amount to dispense:
5 100
6 Your amount $100 is dispensible!
7 Please enter amount to dispense:
8 200
9 Failed to dispense $200!

Example 2

Let’s see another example. This time we will start with the problem statement, the Budget Approval problem.

Let say a worker name William has generated an expense report. He would like to have the expenses approved so he can be repaid. He sends the expenses to his manager. The expenses are too large for his manager to directly approve, so she sends it on to the vice president. The vice president is also unable to approve such a large expense and sends it directly to the president. Now the president has the ultimate authority and will review the approval, and give William a response. Let’s take a look at a solution that does not use the Chain of Responsibility Design Pattern.

There’re a few basic interfaces we’ll cover before we begin to get everybody up to speed.

First, we have an ExpenseReport. An ExpenseReport simply has a total value, the dollars, and cents of the expense.

1 using System;
2 
3 namespace ApprovalCommon
4 {
5     public interface IExpenseReport
6     {
7         Decimal Total { get; }
8     }
9 }

Next, we have an ExpenseApprover. An ExpenseApprover is an employee who can approve an expense.

1 public interface IExpenseApprover
2 {
3     ApprovalResponse ApproveExpense(IExpenseReport expenseReport);
4 }

And then we have an ApprovalResponse; Denied, Approved, or Beyond the Approval Limit for that ExpenseApprover.

1 public enum ApprovalResponse
2 {
3     Denied,
4     Approved,
5     BeyondApprovalLimit,
6 }

The ExpenseReport concrete implementation is very straightforward. It simply exposes the Total as a property.

 1 using System;
 2 
 3 namespace ApprovalCommon
 4 {
 5     public class ExpenseReport : IExpenseReport
 6     {
 7         public ExpenseReport(Decimal total)
 8         {
 9             Total = total;
10         }
11 
12         public decimal Total 
13         { 
14             get;
15             private set;
16         }
17     }
18 }

The Employee class is the concrete implementation of the ExpenseApprover interface. Its constructor takes a string, which is the name and the decimal value for the approvalLimit. The ApproveExpense method simply looks at the ExpenseReport and determines if the value is above, or below the approvalLimit. If it’s above the approvalLimit, BeyondApprovalLimit is returned. Otherwise, the Expense is Approved.

 1 using System;
 2 
 3 namespace ApprovalCommon
 4 {
 5     public class Employee : IExpenseApprover
 6     {
 7         public Employee(string name, Decimal approvalLimit)
 8         {
 9             Name = name;
10             _approvalLimit = approvalLimit;
11         }
12 
13         public string Name { get; private set; }
14 
15         public ApprovalResponse ApproveExpense(IExpenseReport expenseReport)
16         {
17             return expenseReport.Total > _approvalLimit 
18                     ? ApprovalResponse.BeyondApprovalLimit 
19                     : ApprovalResponse.Approved;
20         }
21 
22         private readonly Decimal _approvalLimit;
23     }
24 }

Here we have our main Expense Approval application.

 1 using System;
 2 using System.Collections.Generic;
 3 using ApprovalCommon;
 4 
 5 namespace Approval
 6 {
 7     class Approval
 8     {
 9         static void Main()
10         {
11             List<Employee> managers = new List<Employee>
12                                           {
13                                               new Employee("William Worker", Decimal.Zero),
14                                               new Employee("Mary Manager", new Decimal(1000)),
15                                               new Employee("Victor Vicepres", new Decimal(5000)),
16                                               new Employee("Paula President", new Decimal(20000)),
17                                           };
18 
19             Decimal expenseReportAmount;
20             while (ConsoleInput.TryReadDecimal("Expense report amount:", out expenseReportAmount))
21             {
22                 IExpenseReport expense = new ExpenseReport(expenseReportAmount);
23 
24                 bool expenseProcessed = false;
25 
26                 foreach (Employee approver in managers)
27                 {
28                     ApprovalResponse response = approver.ApproveExpense(expense);
29 
30                     if (response != ApprovalResponse.BeyondApprovalLimit)
31                     {
32                         Console.WriteLine("The request was {0}.", response);
33                         expenseProcessed = true;
34                         break;
35                     }
36                 }
37 
38                 if (!expenseProcessed)
39                 {
40                     Console.WriteLine("No one was able to approve your expense.");
41                 }
42             }
43         }
44     }
45 }

Our sample data is four workers. These workers represent a very simple management reporting structure.

It begins with William, who reports to Mary, who reports to Victor, who reports to Paula. Each member along that chain has an expense limit. William’s limit is 0. He’s not able to approve any expenses. Mary’s limit is $1000, Victor’s is 5000, and Paula’s is 20, 000.

The algorithm begins by reading in the expenseReportAmount from the command line. That amount is fed into the constructor of an ExpenseReport, which will then be passed to every manager to see if they’re able to approve it. If the first manager is able to approve the ExpenseReport, we’re done.

The request was approved or denied. But if they weren’t, we’ll iterate on to the next manager in the list.

Issues in the current implementation:

One of the issues we have is that the caller is responsible for iterating over the list. This means the business logic of how expense reports are promoted through the management chain is captured at the wrong level. If I bring an expense report to my manager, and I ask for approval, if he says that’s beyond my expense limit, he doesn’t tell me to go on and ask his manager, he’ll do that for me. I simply send an expense report, and at some point in the future, I get a response. I don’t need to worry about the promotion process that happened behind the scenes. Our code should reflect that. And with the Chain of Responsibility, we’ll be able to.

Now let’s take a look at the Budget Approval application, using the Chain of Responsibility.

 1 using System;
 2 using ApprovalCommon;
 3 
 4 namespace Approval
 5 {
 6     class Approval
 7     {
 8         static void Main()
 9         {
10             ExpenseHandler william = new ExpenseHandler(new Employee("William Worker", Decimal.Zero));
11             ExpenseHandler mary = new ExpenseHandler(new Employee("Mary Manager", new Decimal(1000)));
12             ExpenseHandler victor = new ExpenseHandler(new Employee("Victor Vicepres", new Decimal(5000)));
13             ExpenseHandler paula = new ExpenseHandler(new Employee("Paula President", new Decimal(20000)));
14 
15             william.RegisterNext(mary);
16             mary.RegisterNext(victor);
17             victor.RegisterNext(paula);
18 
19             Decimal expenseReportAmount;
20             if (ConsoleInput.TryReadDecimal("Expense report amount:", out expenseReportAmount))
21             {
22                 IExpenseReport expense = new ExpenseReport(expenseReportAmount);
23 
24                 ApprovalResponse response = william.Approve(expense);
25 
26                 Console.WriteLine("The request was {0}.", response);
27             }
28         }
29     }
30 }

It should be clear just at first glance that this is a significantly smaller amount of code than what we had in the non-Chain of Responsibility solution.

The most obvious difference, to begin with, is the addition of the ExpenseHandler class. This ExpenseHandler represents a single link in the Chain of Responsibility. Let’s go ahead and take a look at that class to understand how it works.

 1 using ApprovalCommon;
 2 
 3 namespace Approval
 4 {
 5     interface IExpenseHandler
 6     {
 7         ApprovalResponse Approve(IExpenseReport expenseReport);
 8         void RegisterNext(IExpenseHandler next);
 9     }
10 
11     class ExpenseHandler : IExpenseHandler
12     {
13         public ExpenseHandler(IExpenseApprover expenseApprover)
14         {
15             _approver = expenseApprover;
16             _next = EndOfChainExpenseHandler.Instance;
17         }
18 
19         public ApprovalResponse Approve(IExpenseReport expenseReport)
20         {
21             ApprovalResponse response = _approver.ApproveExpense(expenseReport);
22 
23             if(response == ApprovalResponse.BeyondApprovalLimit)
24             {
25                 return _next.Approve(expenseReport);
26             }
27 
28             return response;
29         }
30 
31         public void RegisterNext(IExpenseHandler next)
32         {
33             _next = next;
34         }
35 
36         private readonly IExpenseApprover _approver;
37         private IExpenseHandler _next;
38     }
39 }

The ExpenseHandler implements the IExpenseHandler interface. This interface exposes two methods, the Approve method, which should look familiar, and the RegisterNext method. The RegisterNext method registers the next link in the chain.

Basically, what its saying is if I can’t approve this expense, I should ask the next link in the chain if it’s able to approve the expense. In the ExpenseHandler class, the concrete implementation of the IExpenseHandler interface, we take an ExpenseApprover in the constructor. This Approver is an employee, just like in the previous example. The Approve method receives an ExpenseReport. We ask the Approver, are you able to approve this expense, just like in the previous example. In this case, if they are not able to Approve the expense, because it’s beyond their approval limit, we go to the next link in the chain, and we ask it to Approve it.

Also,

In the above solution, we have used a null object pattern to handle the null reference exception because it gives us a little more freedom in how we want to handle the end of the chain. Every time we create an ExpenseHandler, until we’ve called RegisterNext, next will be null. So instead of letting it be null, we gave it a default value of a null object.

What I’ve done is I’ve created an EndOfChainExpenseHandler class, and this class exposes a singleton Instance. This Instance is the EndOfChainHandler.

 1 using System;
 2 using ApprovalCommon;
 3 
 4 namespace Approval
 5 {
 6     class EndOfChainExpenseHandler : IExpenseHandler
 7     {
 8         private EndOfChainExpenseHandler() { }
 9 
10         public static EndOfChainExpenseHandler Instance
11         {
12             get { return _instance; }
13         }
14 
15         public ApprovalResponse Approve(IExpenseReport expenseReport)
16         {
17             return ApprovalResponse.Denied;
18         }
19 
20         public void RegisterNext(IExpenseHandler next)
21         {
22             throw new InvalidOperationException("End of chain handler must be the end of the chain!");
23         }
24 
25         private static readonly EndOfChainExpenseHandler _instance = new EndOfChainExpenseHandler();
26     }
27 }

The benefits you’ll see when using the Chain of Responsibility include a reduced coupling between the message sender and receiver. You’ll be able to dynamically manage the message handlers, and the end of chain behavior can be defined appropriately depending on your business context.

Chain Of Responsibility Pattern In .NET

.NET exception handling mechanism is a wonderful example where the chain of responsibility pattern is leveraged. We know that we can have multiple catch blocks in a try-catch block code. Here every catch block is kind of a processor to process that particular exception.

So when an exception occurs in the try block, its send to the first catch block to process. If the catch block is not able to process it, it forwards the request to the next object in chain i.e next catch block. If even the last catch block is not able to process it, the exception is thrown outside of the chain to the calling program.

In the following example, two catch blocks are used, and the most specific exception, which comes first, is caught.

 1 class ThrowTest3
 2 {
 3     static void Main()
 4     {
 5         try
 6         {
 7             string s = null;
 8             ProcessString(s);
 9         }
10         // Most specific:
11         catch (ArgumentNullException e)
12         {
13             Console.WriteLine("{0} First exception caught.", e);
14         }
15         // Least specific:
16         catch (Exception e)
17         {
18             Console.WriteLine("{0} Second exception caught.", e);
19         }
20     }
21 
22     static void ProcessString(string s)
23     {
24         if (s == null)
25         {
26             throw new ArgumentNullException();
27         }
28     }
29 }
30 /*
31  Output:
32  System.ArgumentNullException: Value cannot be null.
33  at Test.ThrowTest3.ProcessString(String s) ... First exception caught.
34 */

Chain Of Responsibility Pattern In ASP.NET

The ASP.NET pipeline is a wonderful example where the chain of responsibility pattern is leveraged to provide an extensible programming model. The ASP.NET infrastructure implements WebForms API, ASMX Web services, WCF, ASP.NET Web API, and ASP.NET MVC using HTTP modules and handlers.

Every request in the pipeline passes through a series of modules (a class that implements IHttpModule) before it reaches its target handler (a class that implements IHttpHandler). Once a module in the pipeline has done its duty, it passes the responsibility of the request processing to the next module in the chain. Finally, it reaches the handler.

The following code snippet shows how one can write an object that leverages the chain of responsibility pattern to create a module that filters an incoming request. These filters are configured as chains and will pass the requested content to the next filter in the chain by the ASP.net runtime:

 1 public class SimpleHttpModule : IHttpModule 
 2 { 
 3   public SimpleHttpModule() { } 
 4 
 5   public String ModuleName 
 6   { 
 7     get { return "SimpleHttpModule"; } 
 8   } 
 9 
10   public void Init(HttpApplication application) 
11   { 
12     application.BeginRequest +=  
13     (new EventHandler(this.Application_BeginRequest)); 
14     application.EndRequest +=  
15     (new EventHandler(this.Application_EndRequest)); 
16   } 
17 
18   private void Application_BeginRequest(Object source,  
19   EventArgs e) 
20   { 
21     HttpApplication application = (HttpApplication)source; 
22     HttpContext context = application.Context; 
23     context.Response.Write(SomeHtmlString); 
24   } 
25 
26   private void Application_EndRequest(Object source, EventArgs e) 
27   { 
28     HttpApplication application =      (HttpApplication)source; 
29     HttpContext context = application.Context; 
30     context.Response.Write(SomeHtmlString); 
31   } 
32 
33   public void Dispose() { } 
34 } 
1 <configuration> 
2   <system.web> 
3     <httpModules> 
4       <add name=" SimpleHttpModule " type=" SimpleHttpModule "/> 
5     </httpModules> 
6   </system.web> 
7 </configuration> 

In the ASP.NET pipeline, a request passes through a series of HTTP modules before it hits a handler. A simple HTTP handler routine is given as follows:

 1 public class SimpleHttpHandler: IHttpHandler 
 2 {
 3 
 4   public void ProcessRequest(System.Web.HttpContext context){ 
 5     context.Response.Write("The page request ->" +          
 6     context.Request.RawUrl.ToString()); 
 7   }
 8 
 9   public bool IsReusable 
10   { 
11     get{ return true; } 
12   } 
13 
14 } 

We can configure the handler as given next. Whenever we create an ASP.NET resource with the .smp extension, the handler will be SimpleHttpHandler:

1 <system.web> 
2   <httpHandlers> 
3     <add verb="*" path="*.smp" type="SimpleHttpHandler"/> 
4   </httpHandlers> 
5 </system.web> 

Where To Apply Chain Of Responsibility Pattern?

  • When you have more than one handler for a request
  • When you have reasons why a handler should pass a request on to another one in the chain
  • When you have a set of handlers that varies dynamically
  • When you want to retain flexibility in assigning requests to handlers

Note: You can download the complete solution demo from my github repository.

Further Reading

ASP.NET Core and the Enterprise Part 3: Middleware by K. Scott Allen - In this post, Scott explains how ASP.NET Core is different from tradition ASP.NET. In this post, Scott talks about the replacement for modules and handlers, which is middleware. Middleware is usually chained together and it’s up to them to decide whether to invoke the next one in the chain thus creating a Chain Of Responsibility.

Implementing a Chain-of-responsibility or “Pipeline” in C# by Maxime Rouiller - In this post, Maxime explains how by chaining Strategy Pattern, we can increase the amount of flexibility inside our model and increase the reuse of common algorithms.

Chain of Responsibility as catamorphisms by Mark Seemann - In this post, Mark discusses Chain of Responsibility from a different perspective and explains how instead of relying on keywords like if or switch, you can compose the conditional logic from polymorphic objects. This gives you several advantages. One is that you get better separations of concerns, which will tend to make it easier to refactor the code. Another is that it’s possible to change the behavior at run time, by moving the objects around.

Chain Of Responsibility Pattern C#
Share this

Subscribe to Code with Shadman