C# Best Practices – Subscribe/Publish Model in Web-based Applications

design-patternsobject-oriented-design

I was recently exposed to a desktop application that uses an publish/subscribe model to handle commands, events, etc. I can't seem to find any good examples of using this in a web application, so I wonder if I am off base in trying to use this for web based development (on the server side)? I'm using asp.net c#.

My main question in regards to the design is:
When using a publish/subscribe model, is it better to have generic commands/events that pass no parameters and then have the subscribers look at static context objects that contain the data relevant to the event? Or is it better to create custom arguments for every event that contain data related to the event?

The whole concept of a global container seems so convenient but at the same time seems to break encapsulation.

Any thoughts or best practices from anyone who has implemented this type of model in a web based application? Even suggestions on this model out of the scope of my question are appreciated.

Best Answer

For patterns (observer pattern, publish/subscribe, visitor pattern) where there is a single entity talking to or dealing with multiple entities the communication has what i call it language problem.

There is something similar i had answered which i recommend you to read Observer pattern; knowing *what* changed?


Basically, if you only give single argument or no arguments which means events are triggered and received as you want but they don't quite convey much. It works fine for many trivial example. On the other side if you keep too much information diverse for each module - then definitely you are creating something (as you call it a container) is only a dumping bags. Even for a moment if we keep encapsulation violation arguments away for a moment, dumping bags are not good. For the first part, if you have one more customer and if the container gets one more information is added all other customers now will have to ignore one more field (and recompile themselves)

Part of the problem really is, that while we typically generalize the observers (i.e. different concrete objects as observer and implement observe() or notify() method) but it is equally important that the notification that needs to be given itself is a matter of abstraction. We must ask - what should i notify? and even more what must i not notify?

Take a real world notifiers to understand this:

1. First of that class is broadcast type messages
* a notification at airport notifies about: arrived departed flights and their times.
* a stock market bill board notifies about: updates on various stocks

The first thing to understand that what gets notified is far more stable and very easily understandable, and hence, attaching any number receiver will not ever create a problem. The metadata is well defined and even if it has to change, it is likely that most observer will get benefited from it.

So really speaking language problem doesn't exists in broadcast type notifications.

2. The multicast or unicast scenario where there messages specific to obsever

Any typical newsletter or rss feed or email are rather personal, there is too and from fields that get the message to places. Here the message can be anything - so for all practical purposes, the message transmission doesn't typically have any single format that can hold all information - this is another extreme where to which a container can evolve to. As in the cases of emails for example, the metadata is again standardized but much meaningful information is in the body and it is upto the end observer/reader to interpret this. the language problem does exists here but channels (in our case the API which carries information) must be freed from interpreting this. Let the source somehow create a blob of information and let the observer know what to do with the blob.

So in essence, what you really need to do is to model the notification - what is truly the message content which needs to be black-boxed. the essence of the answer i gave in above link is that you may create a sort of generic name-value pairs or any general encoding of messages and pass on. It can even be something like void* of C. But that exercise is must. On the other hand, find what is the metadata (such as source, timestamps, etc.). These fields can be visible to all message readers.

One last thing to note is, be critical to what is the responsibility of the source/publisher and what is not avoid customizations, extensions to the definition or role of publisher for specific customers. This is the single most source of digression in most such cases. Avoid till you come to a point of loosing salary! :)

Doing all this will force you to put more effort but save you from the technical debt of evolving into a huge (depending on your scale) garbage bag type container and most people cannot figure out why these things are there.