Here we are at the final entry for my event broker solution. If you just stumbled upon CODEGATOR then go back a few days and start reading from the entry entitled" "An event broker solution - part 1". If you've read all the posts in this series then you're probably just as eager as I am to finish! Let's wrap this discussion up - sound good?
The operation of the EventBroker class actually starts whenever a publisher is registered. Remember how an EventPublisherModel instance was created to represent each publisher inside the EventBroker? Well, just before that model is added to the topic list inside the EventBroker a public method called Open is called by the EventBroker to wire the publisher's event to an internal event handler inside the model class. The Open method looks like this:
public void Open()
{
eventInfo.AddEventHandler(
client != null ? client.Target : null,
messageDelegate
);
}
The reason for doing that is so that the EventBroker will know whenever the publisher fires the event - even if no subscribers are interested in the event. The internal handler that is now associated with the publisher's event looks like this:
private void BackgroundEventHandler(object state)
{
owner.ForwardToHandlers(
topic,
(object[])state
);
}
This handler calls ForwardToHandlers each time an event is published. ForwardToHandlers is a method on the EventBroker class that looks at the topic associated with the published event, then uses that topic to find the list of all registered subscribers. Once that's done, The FireMessage method is called to actually forward the event to each subscriber. The listing for the ForwardToHandlers method looks like this:
internal virtual void ForwardToHandlers(
string topic,
object[] args
)
{
try
{
// Play nicely with other threads.
syncLock.AcquireReaderLock(Timeout.Infinite);
// Get the list of handlers for the topic.
List<EventSubscriberModel> list;
if (!sinkTable.TryGetValue(topic, out list))
return;
// Loop and fire each handler in the list.
for (int x = 0; x < list.Count; x++)
{
try
{
list[x].FireMessage(args);
}
catch
{
// The exception is eaten here so that the loop
// can fire the event for all the handlers.
}
}
}
finally
{
// Cleanup the lock.
syncLock.ReleaseReaderLock();
}
}
The next step in the chain is the FireMessage method in the EventSubscriberModel class. This method calls the event handler on the subscriber using the reflection information that was gathered during the registration of the subscriber. The subscribers event handler can either be called directly or the call can be posted to the UI's synchronization context - depending upon the values that were in place when the subscriber was registered. Here is what the FireMessage method looks like:
public void FireMessage(object[] args)
{
// Should we forward the event directly or dispatch it to
// the UI's synchronization context?
if (synchronizedCallback == null)
methodInfo.Invoke(
(client != null) ? client.Target : null,
args
);
else
asyncOperation.Post(
synchronizedCallback,
args
);
}
That's pretty much it for my EventBroker. The code is kinda raw, I admit. I may or may not have the time to make it clean and shiny - that really just depends on how much free time I have. If I actually use this code anywhere I'll probably get fed up with all the warts on it and take some time to fix things. My intention when I created this code was to put something useful in my toolbox and also to give myself something to blog about for awhile. I hope you find the code useful, and I hoped you've enjoyed the blog entries.
Later! 