Saturday, January 16, 2010

The "Fancy Proxy" - having fun with WCF - 3-Simple Duplex

This article is part of The "Fancy Proxy" tutorial - implementing a few advance ideas in WCF in one solution.

This is the 3rd step - Simple Duplex

Ok..so why duplex?! in the final step I want to have a proxy that dynamically changes between online & offline state - in previous step we looked at MSMQ - that would be our "offline" solution...I need an "online" solution that will work implementing the same interface, which is "one-way", but I also want to benefit from the "online" state and actually receive "answers" from the server...

So...let's implement a simple Duplex on WCF - to do just that.

We'll start with the contract, since Duplex is designed for async processing, it is built from two "one-way" interfaces, the second acts as the callback interface.

We'll use the same contract as previous samples, we'll see the second -
ISampleContractCallback is registered as the "CallbackContract" of the first interface:

[ServiceContract(CallbackContract=typeof(ISampleContractCallback))]
public interface ISampleContract
{
[OperationContract(IsOneWay=true)]
void GetData(Guid identifier);

[OperationContract(IsOneWay = true)]
void Execute(Guid identifier);
}

public interface ISampleContractCallback
{
[OperationContract(IsOneWay = true)]
void SendData(Guid identifier, string answer);
}


Next we'll implement this interface on server side - our "business logic", here we'll call back the client with the "answer":

public class testFancyProxyService:ISampleContract
{
public void GetData(Guid identifier)
{
Console.WriteLine("recieved GetData request (id {0})", identifier);

ISampleContractCallback client = OperationContext.Current.GetCallbackChannel();

//get data by identifier
string answer = "hi! from the server";

client.SendData(identifier, answer);
}

public void Execute(Guid identifier)
{
Console.WriteLine("recieved Execute request (id {0})", identifier);
}
}


As previous samples, the host does not change:

class Program
{
private static ServiceHost serviceHost = null;

static void Main(string[] args)
{
try
{
startListening();

Console.WriteLine("Server is up, press any key to stop it...");
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error: {0}\n\n Stack:{1}", ex.Message, ex.StackTrace));
Console.Read();
}
finally
{
stopListening();
}
}

private static void startListening()
{
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(testFancyProxyServer.testFancyProxyService));

// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}

private static void stopListening()
{
if (serviceHost != null)
{
if (serviceHost.State == CommunicationState.Opened)
{
serviceHost.Close();
}
}
}
}


The server's endpoint stays as the "regular" TCP sample

<endpoint address="net.tcp://localhost:8080/testFancyProxy" binding="netTcpBinding"
bindingConfiguration=""
contract="testFancyProxyContracts.ISampleContract" />


Same thing on client side - we'll code a small proxy - here we'll create a 'DuplexChannelFactory' instead of a "regular" ChannelFactory:

public class testFancyProxyProxy:ISampleContract
{
InstanceContext m_context;
private NetTcpBinding tcpBinding;
private EndpointAddress endPointAddress;
ISampleContract proxy;

public testFancyProxyProxy(InstanceContext context)
{
m_context = context;
tcpBinding = new NetTcpBinding(SecurityMode.Transport);
endPointAddress = new EndpointAddress(ConfigurationSettings.AppSettings["ServerURI"]);

proxy = new DuplexChannelFactory(m_context, tcpBinding).CreateChannel(endPointAddress);
}

public void GetData(Guid identifier)
{
proxy.GetData(identifier);
}

public void Execute(Guid identifier)
{
proxy.Execute(identifier);
}
}


Testing...to receive an answer from server, we'll add implementation for ISampleContractCallback.

public class testFancyProxyConsumer : ISampleContractCallback
{
private static InstanceContext m_context = null;
private testFancyProxyClient.testFancyProxyProxy proxy;

public void Run()
{
m_context = new InstanceContext(this);

proxy = new testFancyProxyProxy(m_context);
proxy.GetData(Guid.NewGuid());

proxy.Execute(Guid.NewGuid());
}

//ISampleContractCallback:
public void SendData(Guid identifier, string answer)
{
Console.WriteLine("answer from server for id {0}: {1}", identifier, answer);
}
}





That's it!! 3rd step - that's it for the basics, till now we saw simple TCP, simple MSMQ and simple Duplex...next step we'll start with the more advanced steps towards our final goal - a duplex-dynamic proxy.

Till next step...
Diego

PS: source download

No comments:

Post a Comment