Event Aggregation with MEF (with and without EventAggregator)

The title probably sounds like an oxymoron, but it is not. Recently there was a question on our CodePlex forums from Denis Vuyka about whether or not MEF supports anything like EventBroker for pub/sub type communication. Asking such a question makes a lot of sense, as if you are building open-ended systems of extensions, you will run into cases where you need a loosely coupled way to communicate between the parts. For example you might have a dynamically populated navigation bar. like the one in Outlook, where you publish an event to indicate the item selection. The individual subsystems (contacts, mail, etc) all subscribe to that event to receive notifications.

In as much as it make sense, we don’t currently have a specific facility for this, mostly due to the fact that we had bigger fish to fry. However using p&p’s EventAggregator for Prism is a great option. Of course I am biased, as I came from the Prism project before joining the MEF team. EventAggregator is a very simple service that allows writing up publishers and subscribers in a loosely coupled way. It also provides benefits over events in that it is delegate based and supports a weak delegate notion, thus allowing subscribers to not be held-alive by the publisher. Additionally EventAggregator supports providing lambda predicates for subscription, thus allowing subscribers to conditionally handle the notification based on custom filters against the payload. Finally it is thread safe, and can marshall between threads through using overloads on the event Subscribe() method. The EventAggregator also doesn’t have any real dependencies on Prism itself. Because it is so simple, it is very easy to integrate with MEF, thus allowing MEF parts to benefit from it’s capabilities. Sure enough, Denis went and wired up EA to MEF without a hitch, which he posted about here.  Nice job Denis!

Event Aggregation without EventAggregator

Around the same time that Denis was looking at EventAggregator I started thinking about the problem as it relates to MEF. The question I kept toying with was did we really need EventAggregator at all, or could we simply remove it, and instead just expose the events directly? After a bit of chatting and pairing with Julian Dominguez my former mate from patterns & practices, we realized we actually could. Instead of adding EventAggregator to the container at all, you can simply add Prism events as exports through a catalog which is passed to the container. Once you do, Publisher and Subscriber can easily import the event and access it in a similar fashion. Below are the steps you need to follow, and for which the code is in the attached zip (along with unit tests)

Creating the Event

First create your custom event class by deriving from CompositePresentationEvent and passing your custom args class. Add an Export to the event, and mark it as a shared CreationPolicy, this way all publishers / consumers share the same event instance. For example below I defined a CustomCompositionEvent.

[Export]
[CompositionOptions(CreationPolicy = CreationPolicy.Shared)]
public class CustomCompositionEvent : CompositePresentationEvent<CustomArgs> {}

public class CustomArgs{}

Registering

Next register the event in a catalog. You can use any catalog of your choice, in this case because I am in a unit-test (really an acceptance test as I am just using MEF), I registered manually with a TypeCatalog in a Setup() method. However in a real app, you would probably use a Directory / Assembly catalog.

public void Setup()
{
    var catalog = new TypeCatalog(typeof (Subscriber), typeof (Publisher), typeof(CustomCompositionEvent));
    _container = new CompositionContainer(catalog);
}

Subscribing / Publishing

Once you have registered the event, you can easily import it into any of your parts. Below are my fake publisher and subscriber that I am using for my tests.

  [Export]
  public class Publisher
  {
      [Import]
      public CustomCompositionEvent CustomCompositionEvent { get; set; }
  }

  [Export]
  public class Subscriber
  {
      [Import]
      public CustomCompositionEvent CustomCompositionEvent { get; set; }
  }

To subscribe, call the Subscribe() method on the event, passing in a lambda for the subscriber method. To publish, call the Publish() method on the event and pass the args. See the p&p documentation for more on the params available to both methods.

Both can be seen below in my acceptance test.

[TestMethod]
public void When_event_is_fired_subscriber_gets_notified()
{
    Setup();
    bool eventRaised = false;
    var subscriber = _container.GetExportedObject<Subscriber>();
    var customEvent = _container.GetExportedObject<CustomCompositionEvent>();
    subscriber.CustomCompositionEvent.Subscribe(a => eventRaised = true);
    customEvent.Publish(null);
    Assert.IsTrue(eventRaised);
}

In the code above, I am grabbing a Subscriber instance from the container, which imports the event. I am then grabbing the event directly. I could have actually used the instance of the event that was on the subscriber, but that might look confusing in code, so for clarity, I imported it again directly. This also drives home why it needs to be shared. Next the subscriber subscribes to the event. In this case in my unit test, I am simply setting a boolean when the event is raised, so I can verify it in the test. Finally i am calling publish. In live code, you would probably have the part wire itself up to subscribe in the property setter.

Conclusion

Prism’s EventAggregator infrastructure provides a great way to facilitate loosely coupled communication between parts in your MEF app. You can either use the EventAggregator itself in the container, or you can import CompositePresentationEvents directly. Either approach works well.

You can find the code for this post here.

This entry was posted in com, Composite WPF, event aggregator, MEF, prism. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • David Harper

    Thanks, Glenn! I appreciate it.

  • http://blogs.msdn.com/gblock Glenn Block

    Hi David

    The code is old, but I found it on the MSDN mirror of this post. It’s here: http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-09-44-09-47/MefEventWiring.zip

    I’ll update this posts as well, thanks!

  • David Harper

    I realize this post is a bit dated but I would be very interested in viewing the full code sample as mentioned within the post. I’ve searched the page and can’t seem to find the download link for the .zip file. Is this sample still available?

  • chibacity

    Great post. Just to note though, that EventAggregator itself (specifically GetEvent) is *not* thread-safe. This was quite a surprise to me given its architectural intent. A quick look in reflector reveals all. The following post details the code in question: http://stackoverflow.com/questions/2834035/eventaggregator-is-it-thread-safe

  • jrockers

    [PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.Shared)] replaces [CompositionOptions(CreationPolicy = CreationPolicy.Shared)]
    in Silverlight 4
    http://mef.codeplex.com/SourceControl/list/changesets

  • Eldoen

    yep agree after looking at Denis’ and this seems both are quite interesting. guess I will have to try out both to see which is lighter weight;)

  • http://denisvuyka.wordpress.com Denis Vuyka

    Great post. I’m facing a dilemma now as both approaches seem appealing :)