Event Driven Programming in ASP.NET

By Yashvit Naik on August 16, 2015

Event Driven Programming in ASP.NET using IOC Container

Event driven programming is something we all are familiar with. If anybody has done a bit of WinForms or WebForms back in the days, they will be familiar with events such as a button click. Those were UI events where as I will be covering Events in the Business Logic Layer of a n-tier application, but the concept remains the same.

Consider a scenario where an order is placed in a E-Commerce Web Application. The application might need to perform some actions like send an email to the customer. Another action might be notify the warehouse to ready the order. The service layer of the application should only be concerned with creating the order and saving it in the database and not with the sending of emails.

Going forward another requirement gets added where the system needs to send a SMS or Push Notification to the customer. If the email sending logic is coupled with the creation of the order, then the sms and other logic will also end up in the same place making it more and more complex over time.

To avoid code complexity and to abide by the single responsibility principle and separation of concern we can use Pub/Sub Pattern to make sure all the components are very loosely coupled. Once the order is created an event should be raised, which is handled in other parts of the system. So the next time a different developer needs to add more event handling logic into the system like that of sending a SMS when the order is created, all he has to do is write a new Event Handler and subscribe to the same Order Created Event.

We could use C# Events & Delegates to do this, but in a Web Application I don’t think it is the best way to go. In a web application the lifetime and scope of the objects is short lived and having to register events on a per request scope seems like a bit of an overhead to me.

My solution is based on Udi Dahan’s implementation of Domain Events but I did not use a Static Class because the events will be raised from my Service Layer and injecting an EventService is not a problem.

I have also have added support for async/await. This is a solution based entirely on the use of a DI Container and does not use C# Events and Delegates.

How to Define Events

First, we have an interface that all Events will implement.

public interface IEvent
{
}

Now let’s create an Event for Order Created. This class will contain the event args within.

public class OrderCreatedEvent : IEvent
{
  OrderDto Order
}

How to Define Event Handlers

The Event Handlers will implement the IEventHandler interface with an async function to handle the event raised.

public interface IEventHandler<T> where T : IEvent
{
  Task Handle(T args);
}

Now lets go ahead and add a Event Handler to handle the OrderCreated event. Lets call it NotifyCustomerOnOrderCreated. We can inject any dependency like a service or a repository inside this Event Handler to do the necessary processing. In our case maybe a Email Service that takes care of the email sending.

public class NotifyCustomerOnOrderCreated : IEventHandler<OrderCreatedEvent>
{
  public async Task Handle(OrderCreatedEvent args)
  {
    // Code to send email/sms to customer
  }
}

How to Subscribe to Events

Now coming to the Subscription part of the Pub/Sub pattern. All the event handlers need to be registered with the IOC Container used in the Web Application. The below code shows how to do this using Autofac. Note that you will need to register Event Handlers with Autofac every time you add a new one.

{
  ..
  ..
  builder.RegisterType<NotifyCustomerOnOrderCreated>()
         .As<IEventHandler<OrderCreatedEvent>>()
         .InstancePerRequest();
  ..
}

*This can definitely be done in a generic way depending on the DI container you use.

How to Wire It All Up

Now lets see how this all comes together. The Event dispatching service below looks for all Event Handlers that are subscribed to the Event and calls the Handle function on each one of them. This service can be injected into your business logic components like the service layer to Raise Events.

public interface IEventService
{
  Task Raise<T>(T args) where T : IEvent;
}
 
public class EventService : IEventService
{
  // DI Container
  private IComponentContext _container { get; set; }
 
  // Autofac automatically injects the container
  public EventService(IComponentContext container)
  {
    _container = container;
  }
 
  public async Task Raise<T>(T args) where T : IEvent
  {
    if (_container != null)
    {
      // Find all Event Handlers of type T
      foreach (var handler in _container.Resolve<IEnumerable<IEventHandler<T>>>())
      {
        // Call Handle on every Event Handler
        await handler.Handle(args);
      }
    }
  }
}

How to Raise Events

Now you can raise the Order Created Event once your service layer saves the order in the db. You can inject the IEventService in your service layer and raise the event with await.

public class OrderService : IOrderService
{
  public async Task CreateOrder(Order order)
  {
    // Code to save order
    // ..
    
    await eventService.Raise<OrderCreatedEvent>(new OrderCreatedEvent(){Order = newOrder});
  }
}

Thats it. This is a very simple pub/sub pattern implementation to handle events in your web application business logic. If you are looking at implementing this in a non web based application then you might want to look at C# Events & Delegates which can help you achieve the same. But that said, this implementation should work absolutely fine in Desktop Applications too.

Things to Remember

  • The event handler are async but they still are in process. So avoid blocking calls in your Even Handlers. I will be coming up with a Fire & Forget version of this soon. Been working on an implementation using Hangfire.io
  • This example uses Autofac but can be done using any other DI container. The implementation of the EventService will change slightly as the way you resolve dependencies might vary.