DEV Community

Cover image for Understanding Event-Driven Architecture in C# with Real-Life Scenarios
Odumosu Matthew
Odumosu Matthew

Posted on • Edited on

Understanding Event-Driven Architecture in C# with Real-Life Scenarios

In today's world of fast, scalable, and responsive software, Event-Driven Architecture (EDA) has become a go-to approach for designing systems that can handle a variety of tasks efficiently. In this article, we’ll break down what Event-Driven Architecture is, explain it using real-life examples, and provide C# code examples to help you understand how it works in practice.

What is Event-Driven Architecture?

Event-Driven Architecture (EDA) is a software design pattern in which events trigger actions within a system. An event is something that happens within the system—like a user clicking a button, a payment being processed, or data being updated.

In an event-driven system, instead of having components that directly call each other, different parts of the system respond to events as they happen. This leads to a more decoupled, scalable system.

Real-Life Scenario: A Package Delivery System

Let’s take the example of a package delivery system to explain EDA.

Scenario Breakdown:

  • Event 1: A customer places an order.

  • Event 2: The package is picked up for delivery.

  • Event 3:The package is delivered to the customer.

For each of these events, different services or actions are triggered. For example, when the customer places an order, the system might trigger actions like:

  • Notify the warehouse to prepare the package.

  • Send a confirmation email to the customer.

  • Notify the payment service to process the transaction.

Each service listens for a specific event and takes action when that event occurs.

Event-Driven Architecture in C#

Let’s look at how you can implement Event-Driven Architecture in C#.

1. Defining Events

First, we define the events that our system will handle. In C#, this can be represented by a simple class.

// Defining the "OrderPlaced" event
public class OrderPlacedEvent
{
    public string OrderId { get; set; }
    public DateTime OrderDate { get; set; }
}

// Defining the "PackageDelivered" event
public class PackageDeliveredEvent
{
    public string PackageId { get; set; }
    public DateTime DeliveredDate { get; set; }
}

Enter fullscreen mode Exit fullscreen mode

These are simple event classes that carry data about what happened in the system (e.g., an order was placed, a package was delivered).

2. Creating Event Handlers

Next, we create event handlers, which will react when an event occurs. Event handlers in C# listen for specific events and execute code when those events are raised.

// Event handler for order placed event
public class OrderPlacedHandler
{
    public void Handle(OrderPlacedEvent orderEvent)
    {
        Console.WriteLine($"Order with ID {orderEvent.OrderId} was placed on {orderEvent.OrderDate}");
        // Additional logic, like notifying the warehouse
    }
}

// Event handler for package delivered event
public class PackageDeliveredHandler
{
    public void Handle(PackageDeliveredEvent deliveryEvent)
    {
        Console.WriteLine($"Package with ID {deliveryEvent.PackageId} was delivered on {deliveryEvent.DeliveredDate}");
        // Additional logic, like notifying the customer
    }
}

Enter fullscreen mode Exit fullscreen mode

3. Raising Events

In an Event-Driven Architecture, events are typically raised by one part of the system when something important happens.

// Simulating raising an event when an order is placed
public class OrderService
{
    public event Action<OrderPlacedEvent> OnOrderPlaced;

    public void PlaceOrder(string orderId)
    {
        var orderEvent = new OrderPlacedEvent
        {
            OrderId = orderId,
            OrderDate = DateTime.Now
        };

        // Raise the event
        OnOrderPlaced?.Invoke(orderEvent);
    }
}

// Simulating raising an event when a package is delivered
public class DeliveryService
{
    public event Action<PackageDeliveredEvent> OnPackageDelivered;

    public void DeliverPackage(string packageId)
    {
        var deliveryEvent = new PackageDeliveredEvent
        {
            PackageId = packageId,
            DeliveredDate = DateTime.Now
        };

        // Raise the event
        OnPackageDelivered?.Invoke(deliveryEvent);
    }
}

Enter fullscreen mode Exit fullscreen mode

4. Wiring it All Together

To see the full flow, we’ll wire together the services and event handlers. When an event occurs, it will trigger the appropriate event handler to take action.

public class Program
{
    public static void Main(string[] args)
    {
        // Create services
        var orderService = new OrderService();
        var deliveryService = new DeliveryService();

        // Create handlers
        var orderHandler = new OrderPlacedHandler();
        var deliveryHandler = new PackageDeliveredHandler();

        // Subscribe handlers to events
        orderService.OnOrderPlaced += orderHandler.Handle;
        deliveryService.OnPackageDelivered += deliveryHandler.Handle;

        // Raise events
        orderService.PlaceOrder("ORD1234"); // This will trigger the OrderPlacedHandler
        deliveryService.DeliverPackage("PKG5678"); // This will trigger the PackageDeliveredHandler
    }
}

Enter fullscreen mode Exit fullscreen mode

When you run this program, you’ll see output indicating that the order was placed and the package was delivered. The event handlers are executed when their respective events are raised.

Why Use Event-Driven Architecture?

Event-Driven Architecture offers several benefits:

Decoupling: Components in your system don’t need to directly call each other. Instead, they react to events. This makes it easier to change one part of the system without affecting others.

Scalability: As your system grows, you can add more event handlers without modifying existing code. This makes your system more flexible and scalable.

Asynchronous Processing: In many cases, events are handled asynchronously, meaning your system can perform multiple tasks simultaneously, improving responsiveness and throughput.

Real-Life Example: A Restaurant

Let’s compare Event-Driven Architecture to how things work in a restaurant:

  • Customer places an order (this is an event).

  • Kitchen staff prepares the food (this is the event handler for the order).

  • Waiter delivers the food (another event handler for food readiness).

  • Customer eats and leaves feedback (another event, which could trigger a feedback email).

Each part of the restaurant’s operations happens when an event occurs, and everyone (kitchen staff, waiter, customer) responds to those events accordingly. They don’t need to know what each other is doing, they just react when needed.

In the same way, in an event-driven system, different parts of your application (or different microservices) react to events and perform their tasks independently.

Conclusion

Event-Driven Architecture is a powerful way to design systems that are scalable, flexible, and maintainable. By breaking down responsibilities into events and handlers, you can build systems that are easier to manage, modify, and expand over time.

With real-life scenarios like a package delivery system or even a restaurant, you can see how natural and effective this approach can be. Using C# to implement EDA is straightforward, and it allows your software to respond dynamically to events as they happen in real-time.

If you're building modern applications that require flexibility and responsiveness, Event-Driven Architecture is a pattern worth exploring further.

LinkedIn Account : LinkedIn
Twitter Account: Twitter
Credit: Graphics sourced from Softobiz

Top comments (4)

Collapse
 
mldisibio profile image
mldisibio

EDA is a rich topic.
I certainly would recommend a lightweight framework like MassTransit or Wolverine that implements the EDA and messaging patterns and allows the developer to focus on the business logic.

Collapse
 
iamcymentho profile image
Odumosu Matthew

Absolutely! Using frameworks like MassTransit or Wolverine is a great way to simplify implementing EDA. They handle much of the messaging and event handling complexity, letting developers focus on business logic instead. Thank you for your suggestion

Collapse
 
jangelodev profile image
João Angelo

Hi Odumosu Matthew,
Top, thanks for sharing.

Collapse
 
iamcymentho profile image
Odumosu Matthew

You're welcome! Glad you found it helpful.