Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Wcf Client Server Push using MSMQ

4.88/5 (6 votes)
8 Feb 2011CPOL3 min read 59.8K   2.2K  
Client Server internal push technology using MSMQ and WCF

Introduction

Searching for an easy solution for server push technology using WCF was a bit of a hassle.

I had few requirements:

  1. Must use WCF
  2. Both the server and the client applications don't have to run while messages were being transmitted
  3. A common Queue for all the clients on the server side
  4. Server push is required - can't use polling

IIS WebService was an option but was complicated to implement with a common client Queue.

A solution was found using Microsoft Message Queuing system. Both the client and the server have a message box that use to communicate. Both applications don't have to run while messaging the opposite side.

Note

This project is not done to explain bindings, contracts and services. This is done to provide a simple server push design overview.

Requirements

  1. MSMQ installed (server and clients) - Go to Control Panel -> Add Remove Program -> Add Windows Component and select “Message Queuing”
  2. Run Visual Studio as administrator.
  3. Client and Server must be able to see each other (ping each other using either IP or host name). If you need external communication support - see the "Modification for public communication" section.

Overview

Modification for Public Communication

If a WebService is required - for external internet communication, a wrapper can be made which provides a WebService endpoint and creates an internal Queue message. This will remove the requirement for both client and server to see each other's messaging queue.

Using the Code

The flow is as follows:

Client registers itself by giving the server its own MSMQ address.

C#
RegisterClientServiceClient registerClientServiceClient = 
		new RegisterClientServiceClient("RegisterClientEndPoint");

using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
	ClientInfo clientInfo = new ClientInfo();

	clientInfo.GroupName = ConfigurationManager.AppSettings["GroupName"];
	clientInfo.ClientName = System.Net.Dns.GetHostName();

	// ClientName can be changed to ip address
	clientInfo.PushMessageBoxAddress = "net.msmq://" + 
		clientInfo.ClientName + "/private/WcfServerPush/ClientMessageBox";

	registerClientServiceClient.RegisterClient(clientInfo);
				
	scope.Complete();
}   

RegisterClientServiceClient class derives from the RegisterClientIService and using the ClientBase template. This is regular WCF implementation.

C#
 public class RegisterClientServiceClient : 
	ClientBase<RegisterClientIService>, RegisterClientIService
{
	public RegisterClientServiceClient(string endpointConfigurationName) :
		base(endpointConfigurationName)
	{
	}

	public void RegisterClient(ClientInfo clientInfo)
	{
		base.Channel.RegisterClient(clientInfo);
	}
}  

On the server side, RegisterClient is implemented as a regular operation which derives from the same interface service RegisterClientIService:

C#
public class RegisterClientService : RegisterClientIService
{
	[OperationBehavior(TransactionScopeRequired = 
			true, TransactionAutoComplete = true)]
	public void RegisterClient(ClientInfo clientInfo)
	{
		WcfServerPushServerBO.Instance.RegisterClient(clientInfo);
	}
}

Creating the MSMQ ServiceHost on the server side is easy:

C#
 if (!MessageQueue.Exists(registerClientMSMQName))
{
	MessageQueue versionManagerQueue = 
		MessageQueue.Create(registerClientMSMQName, true);
	versionManagerQueue.SetPermissions
		(@"Everyone", MessageQueueAccessRights.FullControl);

	versionManagerQueue.SetPermissions(@"ANONYMOUS LOGON",
		MessageQueueAccessRights.ReceiveMessage |
		MessageQueueAccessRights.PeekMessage |
		MessageQueueAccessRights.WriteMessage);
}   

The client side is almost the same as the server side, but with a small modification. Because we want the ability for the WPF to register an event with the ServiceHost - whenever we get a new message, we need to create the actual service and give its instance to the ServiceHost. Whenever we provide an instance of a service to the ServiceHost, we must add an InstanceConextMode.Single to the behavior:

C#
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PushMessageService : MessageBoxIService, INotifyPropertyChanged 

Lastly, we need to modify the App.Config to define the Service. We can also give an http binding (not only the netMsmqBinding) to the endpoint - if in the future we would like to provide a metadata exchange ability.

XML
 <service name="WcfServerPushServer.RegisterClientService" 
	behaviorConfiguration="WcfServerPushServer.RegisterClientServiceBehavior">
  <host>
	  <baseAddresses>
	  <add baseAddress="http://localhost:8001/WcfServerPush/
				RegisterClientServiceHttp/" />
	  </baseAddresses>
  </host>

  <endpoint address="net.msmq://localhost/private/WcfServerPush/RegisterClientService"
			  binding="netMsmqBinding"
			  bindingConfiguration="srmpBinding"
			  contract="WcfServerPushIServices.RegisterClientIService">
  </endpoint>
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service> 

The client side needs to recognize the endpoint as follows:

XML
<client>
	<endpoint name="RegisterClientEndPoint" 
	address="net.msmq://localhost/private/WcfServerPush/RegisterClientService" 
	binding="netMsmqBinding" bindingConfiguration="netMsmqBindingConfig" 
	contract="WcfServerPushIServices.RegisterClientIService"/>
</client> 

Solution Architecture

  • WcfServerPush - A WPF project that serves as both the client and server application. You can install the application on either side and decide yourself what to run. The WPF project is also responsible to create the message queue if not found and start the service hosts. In a real development project - it is important to separate the view from the boot bootstrapper.
  • WcfServerPushServer - The server side service and business objects, including the client's Queue
  • WcfServerPushClient - The client side service
  • WcfServerPushIServices - The message box service interface and the register client service interface. Common project for both the server and the client.

History

  • February 6th 2011: First release

License

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