In software architecture, Chain of Responsibility (CoR) is a behavioral pattern that allows you to process requests through a chain of handlers, without the sender knowing which object will handle it. Each handler decides: process the request or pass it on.
It is an excellent pattern for:
-
successive validations
-
middlewares
-
message processing
-
pipelines
-
approvals in enterprise flows
The Concept Behind Chain of Responsibility
The idea is simple: you have a series of objects, each with its responsibility. When a request enters the chain, each handler checks if it can process it. If not, it passes it on.
Advantages:
-
complete decoupling between sender and processor
-
flexibility in modifying the chain
-
easy addition of new steps in the flow
Example in C# (.NET)
We will build a chain of validations for a simple request.
1. Define the abstract Handler
public abstract class Handler
{
private Handler _next;
public Handler SetNext(Handler next)
{
_next = next;
return next;
}
public virtual void Handle(Request request)
{
if (_next != null)
_next.Handle(request);
}
}
2. Create the concrete handlers
public class AuthHandler : Handler
{
public override void Handle(Request request)
{
if (!request.IsAuthenticated)
throw new Exception("User not authenticated!");
Console.WriteLine("Auth OK");
base.Handle(request);
}
}
public class ValidationHandler : Handler
{
public override void Handle(Request request)
{
if (string.IsNullOrWhiteSpace(request.Data))
throw new Exception("Invalid data!");
Console.WriteLine("Validation OK");
base.Handle(request);
}
}
public class LoggingHandler : Handler
{
public override void Handle(Request request)
{
Console.WriteLine("Logged request");
base.Handle(request);
}
}
3. The Request Class
public class Request
{
public bool IsAuthenticated { get; set; }
public string Data { get; set; }
}
4. Configure the chain
var request = new Request
{
IsAuthenticated = true,
Data = "Hello!"
};
var handler = new AuthHandler();
handler
.SetNext(new ValidationHandler())
.SetNext(new LoggingHandler());
handler.Handle(request);
What do we get?
Execution of the flow:
Auth OK
Validation OK
Logged request
When do we use Chain of Responsibility in .NET?
✔ Pipelines in ASP.NET Core (middlewares)
✔ Multiple validations when submitting a form
✔ Messages processed sequentially in queues
✔ Approval flows (approver → manager → director)
✔ Any system where steps need to be decoupled