A simplified non topic based Event Notification Server in wcf with multiple protocol support.

Contents

Introduction

Part I – Basic

What is Event Notification Server(ENS)?
Multiple Protocol Support
How does it work?
Procedure to use ENS and test clients.
Limitation

Part II – Internal.

Data Structure and Algorithm
Architecture of Event Notification Server.

Publisher & Subscriber Model

Part III – Documentation of Code

Introduction

A simplified Event Notification Server allows you to be notified
when an alert is generated in a system without filtering for what type
of event you are registered.In various scenarios we need such type of
publish subscribe scheme .Here a simplified Event Notification Server
is implemented in wcf using pub/sub scheme with multiple protocol
support.In this implementation if a client subscribes with a server,
the client will get all the events sent by the publisher.

Sources

I read the Juval Lowy Article
on msdn magazine but the article is based on topic based pub/sub scheme
.But for many cases a simple pub/sub scheme is needed without topic
scheme .So i made many changes to the code and finally made a
simplified version,i hope that this simplified implementation with
multiple protocol support will be helpful to many men like me in their
project.The code used in this article is based on the juva’s lovy
article, but some parts are not changed.

Part I – Basic

What is Event Notification Server?

Event Notification Server is an “Event Notification” system. It
connects programs that provide information changes over time
(publishers) with programs that want to receive notifications of those
changes (subscribers). It is the middle ware that deals with publishers
and subscribers.

Multiple Protocol Support

There are essentially two main groups applications that communicate
through networks or the Internet – client server and the and
peer-to-peer. Event Notification Server employ client server
architectures for better performance.

Here the Event Notification Server expose different protocols based connectivity. A client
based on his requirement will choose protocol to connect.

Diagram 1 – Several clients connected to a Event Notification Server with multiple protocol.

If a client is in the same machine with Event Notification Server
(ENS) then it will connect with ENS thru Named Pipe protocol Because
Named Pipe protocol is the fastest for same machine boundary.

If a client is in the same Local Area Network (LAN) with ENS it
will connect with ENS thru TCP protocol Because TCP is a connection
oriented reliable protocol.

If a client is in the same Virtual Private Network (VPN) with
ENS then it will connect with ENS thru TCP protocol Because TCP is a
connection oriented reliable protocol.

If a client is in the Internet with ENS then it will connect with
ENS thru HTTP protocol Because HTTP is a firewall friendly protocol.It
is unidirectional by default but using wsdualhttp binding i get
bidirectional behavior.

How does it Work?

Here each client will register himself to ENS then when an event
comes to ENS then ENS will send it to clients that are registered.
For
Example we have 10 clients and all 10 clients would register to the ENS
to receive notifications (client programs are individual programs) and
then whenever the event occurs from the publisher, the ENS notifies all
those clients.

Procedure to use ENS and test clients:

How to start the total System:

In the VS2008 just press F5 to launch total system and then it will be ready to go.

Event Notification Server:

Nothing will need to be configured.

It will start with machine IP on which it is started.

For event receiving purpose(publisher service)
it will open port as follows:
8000 For HTTP.
8001 for TCP.
Mypipe1 for NamedPipe

For event broadcasting purpose(subscription service)
it will open port as follows:

8003 For HTTP.
8002 for TCP.
Mypipe2 for NamedPipe

How to send event:

1. For sending a single event clicks on button “Fire a single Event”.

2. For sending auto event set the interval then click the button
“Fire Auto Event”.

How to receive event:

1. Click the “Subscribe” button of test client.

2. Then it will start to receive the events.

Limitation

Does not work under NAT.
NO authentication, encryption
No Fault Tolerance Support .
No provision to prevent DOS (Denial of Service attack) attack.

Part II – Internal.

Data Structure:

A simple List contains the list of subscribers.

Algorithm:

Decouple the publishers from the subscribers by introducing a dedicated subscription service and a dedicated publishing service.

Subscribers that want to subscribe to events will register with the subscription service.

Subscription service will manages the lists of subscribers.

When there is an event in publisher

o The publisher will want subscriber list form subscriber service.

o Then Publisher will send the event to each subscriber of the list.

Architecture of Event Notification Server:

architecture.PNG

Publisher & Subscriber Model

Publish/subscribe (or pub/sub) is an asynchronous messaging paradigm
where senders (publishers) of messages are not programmed to send their
messages to specific receivers (subscribers). Rather, published
messages are characterized without knowledge of what (if any)
subscribers there may be. Subscribers express interest and receive
messages , without knowledge of what (if any) publishers there are.
This decoupling of publishers and subscribers can allow for greater
scalability and a more dynamic network topology.Much the same way, the
publisher can only notify subscribers it knows about. There is no way
for the publisher to deliver an event to whomever wishes to receive it,
nor is there an ability to broadcast an event. In addition, all
publishers must repeatedly have the necessary code to manage the list
of the subscribers and the publishing act itself.There is no way for a
subscriber to ask that if an event is fired, the application should
create an instance of the subscriber and let it handle the event.
Setting up subscriptions has to be done programmatically.

Part III – Documentation of Code

DataContract

Collapse
[DataContract]
public class AlertData
{
private string _SeqNo;
private string _Description;

[DataMember]
public string SeqNo { get { return _SeqNo; } set { _SeqNo = value; } }

[DataMember]
public string Description { get { return _Description; } set { _Description = value; } }
}

Event Publishing

The publishing service exposes the events contract in an endpoint, you need to mark the events contract as a service contract.

Collapse
   /// <summary>
/// This is the service contract of Publish Service

[ServiceContract]
interface IEvent
{
[OperationContract(IsOneWay = true)]
void OnEvent(AlertData e);
}

To provide your own publishing service, derive from IEvent and use method to deliver the event to all subscribers.

Collapse
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class Publishing : IEvent
{

/// This method is called from the publisher client to send the event.
public void OnEvent(AlertData e)
{

IEvent[] subscribers = Subscription.GetClientList();
Type type = typeof(IEvent);
MethodInfo methodInfo = type.GetMethod("OnEvent");
foreach ( IEvent subscriber in subscribers)
{
try
{
methodInfo.Invoke(subscriber, new object[] { e });
}
catch
{

}
}
}
}

Managing Registration(subscriptions):

For managing registration, I defined IRegistration interface shown in Example 1.

Collapse
/// <summary>
/// This is the Service contract for SubscriptionService
/// </summary>
[ServiceContract(CallbackContract = typeof(IEvent))]
public interface IRegistration
{
[OperationContract]
void Register( );

[OperationContract]
void UnRegister();

[OperationContract]
string GetDateTime();
}

The callback interface is

Collapse
   /// <summary>
/// This is the service contract of Publish Service
/// </summary>
[ServiceContract]
interface IEvent
{
[OperationContract(IsOneWay = true)]
void OnEvent(AlertData e);
}

The application needs to expose its own subscription service in the
form of an endpoint that supports its specific interface of
IRegistration. To do so, the application needs to provide a service
class that derives from IRegistration specify the callback contract as
a type parameter,.

Collapse
  
/// This is the class for Subscription Service that is deployed to listen.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Subscription : IRegistration
{

/// This the data structue that is used for pub/sub scheme.
/// Here list is used to hold the subscribers.

static List<IEvent> m_ClientList;


/// This is constructor of the class.It is used here to create the instance
/// of the pub/sub data structure
static Subscription()
{
m_ClientList = new List<IEvent>();
}

/// This method return the complete subscriber list to publisher service.

internal static IEvent[] GetClientList()
{
lock (typeof(Subscription))
{
return m_ClientList.ToArray();
}
}


/// This method is called by subscriber to register itself with Server.
/// It register the client with pub/sub service.
public void Register( )
{
lock (typeof(Subscription))
{
IEvent subscriber = OperationContext.Current.GetCallbackChannel<IEvent>();
if (m_ClientList.Contains(subscriber))
{
return;
}
m_ClientList.Add(subscriber);
}
}



/// This method is called by subscriber to Unsubscribe itself from Server.
/// It Unsubscribe the client with pub/sub service.
public void UnRegister()
{
lock (typeof(Subscription))
{
IEvent subscriber = OperationContext.Current.GetCallbackChannel<IEvent>();
m_ClientList.Remove(subscriber);
}
}


public string GetDateTime()
{
return System.DateTime.Now.ToString();
}

}

stores subscribers in a generic static list.

Collapse
/// This the data structue that is used for pub/sub scheme. 
/// Here list is used to hold the subscribers.



static List<IEvent> m_ClientList;

The Register ( ) method extracts the callback reference from the
operation call context. Then retrieves the list of subscribers for the
event from the store. If the list does not contain the subscriber, it
adds it in. UnRegister() operates in a similar manner.

Hosting

For hosting you have to expose Publishing service multiple times for multiple protocols.

Collapse
  
eventServiceHost = new ServiceHost(typeof(Publishing));

///Here diferent binding is created for different protocol.
/// For example NetTcpBinding is created for TCP protocol.
/// For example WSDualHttpBinding is created for HTTP protocol.
// For example NetNamedPipeBinding is created for Named Pipe protocol.

System.ServiceModel.Channels.Binding wsDualBindingpublish = new WSDualHttpBinding();
System.ServiceModel.Channels.Binding tcpBindingpublish = new NetTcpBinding();
System.ServiceModel.Channels.Binding namedPipeBindingpublish = new NetNamedPipeBinding();

///By the following line i add the address of PublishService to eventServiceHost for
///differnt protocol
eventServiceHost.AddServiceEndpoint(typeof(IEvent), wsDualBindingpublish,
"http://localhost:8000/PublishingService/");
eventServiceHost.AddServiceEndpoint(typeof(IEvent), tcpBindingpublish,
"net.tcp://localhost:8001/PublishingService");
eventServiceHost.AddServiceEndpoint(typeof(IEvent), namedPipeBindingpublish,
"net.pipe://localhost/MyPipe1");

//This line is used to open pub service to listen.
eventServiceHost.Open();

For hosting you have to expose Subscription service multiple times for multiple protocols

Collapse
 subscriptionManagerHost = new ServiceHost(typeof(Subscription));

System.ServiceModel.Channels.Binding wsDualBinding = new WSDualHttpBinding(
WSDualHttpSecurityMode.None);
System.ServiceModel.Channels.Binding tcpBinding = new NetTcpBinding(SecurityMode.None);
System.ServiceModel.Channels.Binding namedPipeBinding = new NetNamedPipeBinding();


///By the following line i add the address of Subscription Service
///to subscriptionManagerHost for differnt protocol
///subscriptionManagerHost.AddServiceEndpoint(typeof(IRegistration), wsDualBinding,

subscriptionManagerHost.AddServiceEndpoint(typeof(IRegistration),
wsDualBinding,
"http://localhost:8003/SubscriptionServie/");
subscriptionManagerHost.AddServiceEndpoint(typeof(IRegistration),
tcpBinding,
"net.tcp://localhost:8002/SubscriptionServie");
subscriptionManagerHost.AddServiceEndpoint(typeof(IRegistration),
namedPipeBinding,
"net.pipe://localhost/MyPipe2");



//This line is used to open sub service to listen.
subscriptionManagerHost.Open();

Http Client Connection:

We know that http is unidirectional. To make it bidirectional we
have to use WSDualHttpBinding and have to open two sockets connection
in client and server. so here ClientBaseAddress is used to set client,s
address to listen in client.

Collapse
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key ="EndpointAddress" value ="http://localhost:8003/SubscriptionServie/"/>
</appSettings>

</configuration>


WSDualHttpBinding namedpipebinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(EndpoindAddress);
InstanceContext context = new InstanceContext(callbackinstance);
m_Proxy = new RegistrationProxy(context, namedpipebinding, endpointAddress);
string strHostName = Dns.GetHostName();
IPHostEntry ipEntry = Dns.GetHostByName(strHostName);
IPAddress[] addr = ipEntry.AddressList;
namedpipebinding.ClientBaseAddress = new Uri("http://" +
addr[0].ToString() + ":" + "4000" + "/");

Tcp Client Connection:

SecurityMode.None is used here so that it can communicate over cross domain and over vpn.

Collapse
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key ="EndpointAddress" value ="net.tcp://localhost:8002/SubscriptionServie"/>
</appSettings>
</configuration>
NetTcpBinding NetTcpbinding = new NetTcpBinding(SecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(EndpoindAddress);
InstanceContext context = new InstanceContext(callbackinstance);
m_Proxy = new RegistrationProxy(context, NetTcpbinding, endpointAddress);

IPC Client Connection:

Collapse
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key ="EndpointAddress" value ="net.pipe://localhost/MyPipe2"/>
</appSettings>
</configuration>
NetNamedPipeBinding namedpipebinding = new NetNamedPipeBinding();
EndpointAddress endpointAddress = new EndpointAddress(EndpoindAddress);
InstanceContext context = new InstanceContext(callbackinstance);
m_Proxy = new RegistrationProxy(context, namedpipebinding, endpointAddress);

Http Publisher Connection:

We know that http is unidirectional. To make it bidirectional we
have to use WSDualHttpBinding and have to open two sockets connection
in client and server. so here ClientBaseAddress is used to set client,s
address to listen in client.

Collapse
WSDualHttpBinding wsDualBindingpublish = new WSDualHttpBinding();
EndpointAddress endpointAddress =
new EndpointAddress("http://localhost:8000/PublishingService/");
string strHostName = Dns.GetHostName();

IPHostEntry ipEntry = Dns.GetHostByName(strHostName);

IPAddress[] addr = ipEntry.AddressList;

wsDualBindingpublish.ClientBaseAddress = new Uri("http://" + addr[0].ToString()
+ ":" + "3000" + "/");
proxy = new PublisherProxy(wsDualBindingpublish, endpointAddress);

Conclusion

Here the code implement most simple scenario of pub/sub scheme without topic based which is helpful in many scenarios.

In the future post i will give fault tolerance implementation of this.

and then i will show how windows and certificate authentication can be implemented using this implementation.

Referance

What You Need To Know About One-Way Calls, Callbacks, And Events

Programming WCF Services – Written by Microsoft software legend Juval Lowy

wiki

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

 

Razan Paul (Raju)


Software Developer (Senior)

Bangladesh Bangladesh

Member

I am from Munshiganj, Bangladesh. I work for an offshore software
company in Dhaka, Bangladesh. For me, programming is a passion first, a
hobby second, and a career third.

My Blog: http://weblogs.asp.net/razan/

View my professional profile on LinkedIn.

Feel free to mail me for anything at razanpaul AT yahoo Dot com.

This entry was posted in SOA. Bookmark the permalink.

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s