Today, I discuss the design of what I actually implemented. Please be aware that I do not claim that it’s the perfect solution to the concept at hand. It’s what I’ve come up with to implement it, which at least for my context works very well. With that being said, let’s dive into the design.
The core of the design is formed by a class called
The name is quite self describing, but let me say some words about its
intended purpose in my publish & subscribe implementation. The
subscription is used as an endpoint for sending messages to a
subscriber, hiding away the thread context (
of the related subscriber instance and the weak reference handling to
the related subscriber instance from the caller. It’s a kind of mediator
instance so to say.
Besides that it provides some information about which message type the subscription is for.
Subscriptions are created by an implementation of the
ISubscriptionAssembler interface. As the
name implies the main responsibility of this interface is to create
subscriptions either in an explicit (create a single subscription for a given
or implicit (infer all subscriptions of a given instance / type) manner …
The current implementation (
SubscriptionAssembler) uses a small wrapper around
capture the thread context while building the subscription. All this factory does is that it registers a new
SyncronizationContext.Current when no context exists. This is especially useful when doing unit testing (which by default has no
Besides that the
SubscriptionAssembler provides functionality to infer all
subscriptions of a particular type and / or instance via reflection. This is done on top of the classes
SubscriptionInspector realizes the relflection part, while the
MessageInterestCache serves as a small
cache for optimizing the performance of the assembler (message interests are only reflected once).
Also included is a bit of functionality which can be used to pre-infer the message interests of a particular type,
which might get handy when integrating with an InversionOfControl-container (most IoC-container split registration and
Once subscriptions have been created, they are managed by an implementation of the
- Tracking all subscriptions for a particular message type (with operations for adding / releasing and retrieving subscriptions for a particular message type).
- Detecting and removing dead references (garbage collected instances).
IMessageBus implementation called
implemented only as a small wrapper around the
ISubscriptionAssembler (for creating subscriptions) and the
ISubscriptionManager (for adding and removing subscriptions explicitly). Here you can impression what it actually does:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
The interface to an InversionOfControl-container is the
IocBridge. This class is just
a small mediator that can be used in combination with the extension method the container provides.
It provides simple access points which call an
ISubscriptionAssembler implementation, when an instance has
been configured, try to infer all subscriptions when a new instance has been created and that release all subscriptions related to a particular
instance when the instance has been removed from the container.
Regarding the design of the publish & subscribe system that’s all there is to tell :-) . Here is a little overview over all classes.
In the last post I mentioned that my favourite IoC-container is Castle Windsor.
In order to use the library there still is a little piece missing. I’ve integrated it with the WindsorContainer by
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Together with some xml the whole stuff can easily be wired together.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
That’s it with my take on (local) publish & subscribe. It may not be perfect but it suits my needs at the moment.
I’m planning to integrate the standard .NET APM in the
IMessageBus interface in order allow asynchronous message sending and the common rendezvous techniques.
I’m looking forward to any feedback for my solution and would like to share the code under some OS license, if someone is interested in…