Channels ▼

Arnon Rotem-Gal-Oz

Dr. Dobb's Bloggers

Eventing in WCF

October 18, 2008

As I mentioned in a couple of previous posts (like "Using REST along with other architectural ), I've been spending the last few weeks writing an Event system over WCF (probably also explains posts on WCF gotchas like this;) ). Being a communication infrastructure it is still a long way from being completed, but it seems to be stabilizing and I think it turned out nicely so I thought I'd share a few details.

Let's start with the simple part - the usage.
The eventing is built on the idea of a bus (i.e. no centralized components) and the resources/services that want to use eventing have to use a library which I call EventBroker. There are two modes for using the EventBroker. one is "regular" events which are contexless. This means that consecutive events can reach different services, and there is no context that flows from event to event:

<span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px"><span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">bool</span> raisedEvent <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px">=</span> eb.RaiseEvent(<span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">new</span> SampleEvent());</span>
The second type of events are Sagas, which represent long running interactions. Sagas does have a "best effort" guarantee to reach the same recipients over consecutive calls. Also you can also End sagas (sucessful termination), Force End Saga (successful termination by a service that didn't initiate the saga) and Abot Saga (unsuccessful termination): Here is how you raise a saga event.
<span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px">var evnt <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px">=</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">new</span> SampleEvent { data <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px">=</span> somevalue};<br />var SagaId <span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px">=</span> Guid.NewGuid();<br />eb.RaiseSagaEvent(SagaId, evnt);</span>
if you use the same Saga Id, the events are handled as part of the same saga, if you use a Saga Id that wasn't previously defined it will initialize a new saga.
The eventbroker translates events to the relevant contract and dispatches the events over to the different subscribers. Which brings us to to the next part which I guess, is also a little more interesting. How subscriptions are defined.

The first thing to do is to define the event itself.
<span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px">    <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">public</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">class</span> SampleClassEvent :ImEvent<br />    {<br />        <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">public</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">string</span> DataMember1 {set;get;}<br />        <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">public</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">int</span> DataMember2 { set; get;}<br />    }</span>
There aren't any real constraints on the event, except that it has to "implement" the ImEvent interface. Which is really an empty interface but it marks the event as one for the event broker.
Then you have to define an interface for handling the event. The event broker, builds on the idea of convention rather than configuration (an idea popularized by the rails framework) so it is easier to generate the interface (something I do with a resharper template)
<span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px">    [ServiceContract]<br />    <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">public</span>  <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">interface</span> IHandleSampleClass<br />    {<br />        [OperationContract]<br />        <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">int</span>  SampleClass(SampleClassEvent eventOccured);<br />        <br />    }</span>
The convention is that the interface will have a IHandle prefix followed by the name of the event. It will hold a single operation named like the event (without the Event suffix) and will recieve a single parameter which is the event data. Currently events do return a value (int) but I am thinking about changing it to void and have everything marked as OneWay for added performance

Now, when we create a service which needs to handle events it will do that by specifing which events it handles. E.g.
<span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px">    [ServiceContract]<br />    <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">public</span> <span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px">interface</span> ImSampelResource : ImContract, IHandleSampleClass, IHandleSomeOtherThing<br />    {<br />    }<br /></span>
So each contract declares all its subscriptions (by a list of IHandleXXX). It should also include the ImContract interface which holds all the service operation used by the eventbroker (e.g. ending sagas etc.).
Services that want to raise events should inherit from a ControlEdge class (base class Edge component that delegates control events to the event broker)

There's still the question of how does the event broker knows where to find other services. There are several ways this can be done (e.g. a service repository) but since we have blogjecting watchdogs in place anyway, we use them to propagate liveliness (and location ) of services.

This sums up this post. It is basically just a little context for several planned posts where I hope to talk about some of the challenges, alternatives and design decisions that led me to the current design. Meanwhile, I'd also be happy to hear any comments, ideas or reactions you may have

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video