Up to this point we have covered all of the support classes for the event broker solution, as well as the registration process for the EventBroker class. Today I'm going to discuss the process of un-registering a previously registered publisher or subscriber with the event broker.
First of all, I realize that a publisher or subscriber might simply die off without actually calling one of the unregister methods on the EventBroker class, which is why I chose to hold my reference to the publisher/subscriber object using a WeakReference wrapper. This way, I can tell inside the EventBroker if I'm dealing with a reference to a "dead" object, and by using WeakReference we wont prevent the garbage collector from doing it's job. I know what your thinking, "but what about all those potential references to "dead" subscribers and publishers? Wont they build up over time?" Right? That's what you were thinking - right? Well, later on I plan to add a background task that will periodically clean out the event broker's zombie registrations, but I didn't add that now because I was too busy trying to get things to simply work. My philosophy is: "make it work today, make it fancy tomorrow".
The unregister methods look similar to the register methods. Once again we can unregister an object or a class type. Here are the signatures for the unregister methods:
public virtual void Unregister(object client)
public virtual void Unregister(Type clientType)
Both of these public methods defer their processing to a pair of private methods called UnregisterEvents and UnregisterHandlers. There are also to versions of these methods as well:
private void UnregisterEvents(object client)
private void UnregisterEvents(Type clientType)
Just like their register counterparts, the internal differences between the two version are quite small. The only thing to keep in mind here is that if registered an object instance with the EventBroker then you probably want to unregister the same object instance. Don't register an object instance and then unregister a class type, or vice-versa.
Here is what the code for the UnregisterEvents methods looks like:
private void UnregisterEvents(
Type clientType
)
{
// Get the collection of all the events.
EventInfo[] tempEvents = clientType.GetEvents(
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic
);
try
{
// Play nicely with other threads.
syncLock.AcquireWriterLock(Timeout.Infinite);
// Loop and find the decorated events.
for (int x = 0; x < tempEvents.Length; x++)
{
// Get the collection of all custom attributes for the event.
object[] attributes = tempEvents[x].GetCustomAttributes(
typeof(EventPublicationAttribute),
true
);
// Loop and find all the topics.
for (int y = 0; y < attributes.Length; y++)
{
// Recover the custom attribute reference.
EventPublicationAttribute attr =
(EventPublicationAttribute)attributes
;
// Get the list associated with the topic.
List<EventPublisherModel> list = sourceTable[attr.Topic];
// If the model isn't registred then simply continue.
if (list == null)
continue;
// Create a model for the event.
EventPublisherModel messageEvent = new EventPublisherModel(
this,
null,
clientType,
tempEvents[x],
attr.AsyncEvent,
attr.Topic
);
// Is the model associated with the topic?
int index = list.IndexOf(messageEvent);
// If so, then close and remove it.
if (index != -1)
{
list[index].Close();
list.RemoveAt(index);
}
// If the list is empty then remove it from the table.
if (list.Count == 0)
sourceTable.Remove(attr.Topic);
}
}
}
finally
{
// Cleanup the lock.
syncLock.ReleaseWriterLock();
}
}
The processing logic is almost identical to the registration logic - so much so that I'll probably refactor things in the near future and combine some of the duplicate code. (Don't say I didn't warn you about how new this code is) Anyway, the first step is to reflect on the type in order to locate all the static events. Then, for each event we find, we check for the presence of our custom EventPublicationAttribute attribute. The events that aren't decorated we don't care about. For the decorated events we recover the associated attribute and use the information contained within it to create a model instance to represent the publisher. Once we have created the model instance we use it to check the event broker's topic list for a matching entry. If we find a matching entry in the list we remove it.
I'm not going to show a listing for the UnregisterEventHandlers method. If you read the description for the RegisterEventHandler method, and the description above then you probably already know what's going inside UnregisterEventHandlers. If not, then download the code and take a peek.
That's the entire un-registration process from front to start. Any questions? If so then add them to the bottom of this blog and I'll do my best to answer. That's about it for today. Tomorrow I'll discuss the runtime operation of the EventBroker class, complete with a walk through from a test publisher firing and event to a test subscriber getting the message.