*********************************************************
Updated to reflect changes in the February CTP
My previous samples demonstrated using ServiceModel to dispatch messages to a strongly typed message handlers. There are times when instead of having a seperate implementation for every message you will want to have a centralised message handler (often this handler is called ProcessMessage). An early version of the Peer channel system code had a message handler called ProcessMessage where the Peer channel messages were dispatched.A Strongly Typed contract
[ServiceContract(Namespace = "urn:uuid:F0E619F9-3AB7-4b9d-A009-269B381C6C85/", CallbackContract = typeof(IHelloMesh))]
[OperationContract(IsOneWay = true)]
void Say(string message);
}
This is considered strongly typed because the method Say takes a string as an argument.
The Contract
This contract defines a a handler that recieves raw messages, it will recieve messages for any action.
public static class ProcessMessageActions
{
public const string SayAction = "Say";
[ServiceContract(Namespace = "urn:30E9233A-6C5C-47a2-8E90-93D592DA0A00/", CallbackContract = typeof(IProcessMessage))]
interface IProcessMessage
[OperationContract(Action="*", IsOneWay = true)]
void ProcessMessage(Message message);
The ProcessMessageActions class defines the actions to be used in a convenient manner.
The Proxy
class HelloMesh : IProcessMessage
public void ProcessMessage(Message message)
if (message.Headers.Action == ProcessMessageActions.SayAction)
string data = message.GetBody<string>();
Console.WriteLine(data);
Again the proxy does little more than delegate to the base implementation. This time the Method is called ProcessMessage and it takes a a Message as its argument. It can be used to create and read the elements of the message including headers.
The InstanceContext
This is the class that is used to handle inbound messages. It has an Implementation IProcessMessage in this case it verifies that the action matches a specific value, if so it does the work associated with that action.
The application is still trivial to write, as before you create an InstanceContext for incoming messages, a proxy for outgoing messages, and then in a loop read what to send, and then use the proxy to send it. In this case it is necessary to create a message object with the data.
class Program
static void Main(string[] args)
InstanceContext instanceContext = new InstanceContext(new HelloMesh());
using (HelloProxy proxy = new HelloProxy(instanceContext, "HelloEndpoint"))
string msg = "";
while (msg != "q")
msg = Console.ReadLine();
Message message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, ProcessMessageActions.SayAction, msg);
proxy.ProcessMessage(message);
proxy.Close();
The Configuration
The only changes necessary to the config are because we renamed the service contract and I also changed the mesh address:
To enable certain changes to be made after the application has been deployed for instance port, the endpoint and binding are usually specified in the app.config file. This is the config file for our application above.
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<client>
<endpoint name="HelloEndpoint"
address="net.p2p://hellomesh/processmessage"
binding="netPeerTcpBinding"
bindingConfiguration="Binding1"
contract="HelloMesh.IProcessMessage">
</endpoint>
</client>
<bindings>
<netPeerTcpBinding>
<binding name="Binding1"
port="5182">
<security mode="None"/>
</binding>
</netPeerTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
Putting the code together in one piece leaves us witt:
The Complete Program:
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
namespace HelloMesh
partial class HelloProxy : System.ServiceModel.DuplexClientBase<IProcessMessage>, IProcessMessage
public HelloProxy(InstanceContext inputInstance, string configurationName) : base(inputInstance, configurationName)
base.InnerDuplexChannel.Open();
base.InnerProxy.ProcessMessage(message);