Reputation: 86987
I've got a stock-standard ASP.NET MVC 3 web application.
I've got several cross-cutting concerns, and i wish to employ some AOP, most notably the event dispatcher pattern.
For example, i wish to "raise an event" in my controllers when something happens, then have several "listeners" scattered across my application (repository, services, etc) which listen for this event and act accordingly.
I should also mention, i'm using StructureMap for my IoC container - so it would be best if the event dispatcher made use (or was pluggable) for the IoC container, instead of relying on it's own.
Has anyone found a NuGet package that does this, or alternatively, can point me to an article/question stating how to do it?
Upvotes: 1
Views: 1123
Reputation: 5903
Controller is supposed to be stateless. Framework destroys controller object after request been handled and recreate it when next request come. Actually ASP.NET MVC creates separate instance of controller for each request. Declaring event in controller and subscribing for this event by other application services might cause memory leak (GC will not destroy used controller because there will be alive references to the controller from other alive object).
Also keep in mind that IIS might kill your web application's process if it will be idle or by some other reasons, so your web application is also supposed to be stateless.
You also must keep in mind concurrency of that event handling,
You can employ Event publisher-subscriber pattern, but it should be implemented as separate "agent", for example as Windows Service, which will listen to some port and handle requests from your Web Application.
Upvotes: 4
Reputation: 23472
I don't think your controllers should be raising events, that should be something for your domain logic after you have done your domain specific validation. How can you be sure that something has really happened before you have done the validation to make sure it will work?
However, it is not that hard to implement a simple event based solution. I would go for something like:
public abstract class BaseEvent {}
public class EventRouter {
private Dictionary<Type, List<Action<BaseEvent>>> _eventRoutes;
public EventRouter ()
{
_eventRoutes= new Dictionary<Type, List<Action<BaseEvent >>>();
}
public void Register<TEvent>(Action<TEvent> route) where TEvent : BaseEvent
{
List<Action<TEvent>> routes;
var type = typeof(BaseEvent);
if (_eventRoutes.TryGetValue(type, out routes).IsFalse())
{
routes = new List<Action<TEvent>>();
_eventRoutes.Add(type, routes);
}
routes.Add((y) => route(y as BaseEvent));
}
public bool TryGetValue(Type commandType, out List<Action<TEvent>> handlers)
{
return _eventRoutes.TryGetValue(eventType, out handlers);
}
}
public class InMemoryEventDispatcher : IEventBus
{
private readonly IEventRouter _eventRouter;
public InMemoryEventBus(IEventRouter eventRouter)
{
_eventRouter = eventRouter;
}
public void PublishEvent<TEvent>(TEvent @event) where TEvent : BaseEvent
{
var eventType = @event.GetType();
List<Action<TEvent>> eventHandlers;
if (_eventRouter.TryGetValue(eventType, out eventHandlers).IsTrue())
{
foreach (var eventHandler in eventHandlers)
{
eventHandler(@event);
}
}
}
public void PublishEvents<TEvent>(IEnumerable<BaseEvent> events) where TEvent : BaseEvent
{
foreach (var @event in events)
{
PublishEvent(@event);
}
}
}
With that ready you can register the actions you want to execute per event. I haven't compiled it but something like that should go.
Upvotes: 0