Adding Store and Forward support to the Prism EventAggregator

Tuesday, November 25, 2008 – 5:00 AM

I was playing around with the Prism event aggregation feature recently and came across a scenario that is common enough that I thought I’d post the solution here.

The Prism event aggregator feature allows you to create loosely coupled communication between components in your application using a publish-subscribe model. The default implementation provided by Prism simply drops events that are published before a subscriber is ready to receive them, they’re forever lost. I wanted to keep a list of events that had not been processed and pass them on when a subscriber became available, a store and forward model. It turns out that implementing such a store and forward model in a common event base class is relatively trivial.

But first a little bit about the event aggregation feature in Prism…

Prism’s event aggregator model has two parts. Publishers publish events via the aggregator which is responsible for routing data to any subscribers. Here I’m using the aggregator to publish a LoggerEvent which sends a payload message, in this case a string:

    this.EventAggregator.GetEvent<LoggerEvent>().Publish(message);

Elsewhere in my application I subscribe to the event and define a delegate to process the payload. Here I simply add the message string to the LoggerText:

    public LoggerPresentationModel(IEventAggregator eventAggregator)
    {
        _eventAggregator.GetEvent<LoggerEvent>().Subscribe(
            LoggerEventHandler,
            ThreadOption.PublisherThread);
    }

    private void LoggerEventHandler(string message)
    {
        LoggerText += message;
    }

Every time an event is published the event handler will be called on each subscriber. What if publishers to your event aggregator are publishing events before any subscribers are available to receive them?

It turns out that implementing a store and forward event is very simple, thanks largely to the virtual methods on the base classes provided by the Prism framework. All I had to do was override two methods. The overridden Subscribe method adds the new subscriber and then flushes the cache list by publishing all it’s stored payloads. The new Publish method updates a list of payloads and flushes it if subscribers are available.

Here’s the code:

    public class CachedEvent<TPayload> : CompositeWpfEvent<TPayload>
    {
        private readonly List<TPayload> _cache = new List<TPayload>();

        private bool HasSubscribers
        {
            get { return (Subscriptions.Count > 0); }
        }

        public override void Publish(TPayload payload)
        {
            _cache.Add(payload);
            Flush();
        }

        public override SubscriptionToken Subscribe(Action<TPayload> action, 
            ThreadOption threadOption, 
            bool keepSubscriberReferenceAlive, 
            Predicate<TPayload> filter)
        {
            SubscriptionToken token = base.Subscribe(action, threadOption, 
                keepSubscriberReferenceAlive, filter);
            Flush();
            return token;
        }

        public void Flush()
        {
            if (!HasSubscribers)
                return;

            foreach (TPayload payload in _cache)
                base.Publish(payload);
            _cache.Clear();
        }
    }

Now all you need to do to get your event to exhibit cached behavior is to inherit from the CachedEvent class.

Note that the above code isn’t ideal. Firstly it subclasses CompositeWpfEvent, rather than the EventBase class. I did this to save having to change the code the Prism team shipped. You might want to modify your version of the source. Another approach might be to use behaviors to achieve the same end which would keep the class hierarchy flatter.

I’ve also passed this on to the Prism team, they may come up with a better solution in a future release.

  1. 1 Trackback(s)

  2. Nov 29, 2008: Notes From the Team Room : Store And Forward Prism Event

Sorry, comments for this entry are closed at this time.