views:

675

answers:

4

I have a Client Application, a server and another client, lets call it third party. I have a callback interface as part of my contract that is implemented both by the third party and the client.

The third party will call a server operation(method) then the server will trigger a callback but instead of calling the callback of the third party, it will call the callback implementation of the client.

A: 

From a quick read of the Microsoft Duplex service documentation I don't think that will do what you want. There could be some other clever Kung Fu WCF way to do it but in my case I created a "PassThruService" for the server that implemented the same contract as the real service and sent any requests received onto the client.

This is a part of my code that explains the thrust of it.

private const int OPERATION_TIMEOUT = 5000;
private MyServiceClient m_client = new MyServiceClient();

public bool IsAlive() {
    try {
        logger.Debug("PassThruService IsAlive.");

        bool isAlive = false;
        ManualResetEvent isAliveMRE = new ManualResetEvent(false);

        m_client.IsAliveComplete += (s, a) => { isAlive = a.Result; isAliveMRE.Set(); };
        m_client.IsAliveAsync();

        if (isAliveMRE.WaitOne(OPERATION_TIMEOUT)) {
            return isAlive;
        }
        else {
            throw new TimeoutException();
        }
    }
    catch (Exception excp) {
        logger.Error("Exception PassThruService IsAlive. " + excp.Message);
        throw;
    }
sipwiz
A: 

I don't fully see what you're really asking here.... but I'll try to give some tips anyway.

Relaying messages or routing is not very well supported in WCF in .NET 3.5 - the infrastructure is there, but it's still a lot of work to set it up manually.

The best intro I know into this topic for WCF in .NET 3.5 is a two-part article by Michele Leroux Bustamante on MSDN magazine:

Part 2 has a section on duplex routers - does that help you in your quest at all??

WCF in .NET 4.0 promises to bring additional support for routing - there will be a RoutingService base class which can be leveraged to write routing services, and it will allow for configurable, content- or metadata-based routing - whatever it is that you need.

.NET 4.0 is scheduled to be released sometime later this year (2009) - hopefully! So while this is still the future, it's looking rosy!

Marc

marc_s
+1  A: 

Yes, you can absolutely do that.

The easiest way is to implement your service as a PerSession service, and capture the callback context on initialization/construction. Typically I will add the service object (which really represents a connection at that point) to an internal core object.

Then, when you get in a message from a client, you can make a call to any of the service objects (not through the contract), and internally forward the data to the associated client.

This is a pretty minimal implementation of the concept, without exception handling, and some pretty bad design (static class BAD!). I haven't tested this, but the principles should hold even if I missed crossing an i or dotting a t. This example also forwards the calls to all clients, but selecting an individual client follows the same basic pattern.

Trying to do this with a singleton service will be more difficult, and a per-call service obviously won't work :)

[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IContract
{
    [OperationContract(IsOneWay = true)]
    void SendTheData(string s);
}

public interface ICallback
{
    [OperationContract(IsOneWay = true)]
    void ForwardTheData(string s);
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.PerSession)]
public class ServiceConnection : IContract
{
    private ICallback m_callback;

    public ServiceConnection()
    {
        m_callback = OperationContext.Current.GetCallbackChannel<ICallback>();
        ServiceCore.Add(this);
    }

    public void SendTheData(string s)
    {
        ServiceCore.DataArrived(s);
    }

    public void SendToClient(string s)
    {
        m_callback.ForwardTheData(s);
    }
}

static public class ServiceCore
{
    static private List<ServiceConnection> m_connections = new List<ServiceConnection>();


    public static void DataArrived(string s)
    {
        foreach(ServiceConnection conn in m_connections)
        {
            conn.SendTheData(s);
        }
    }

    public static void Add(ServiceConnection connection)
    {
        m_connections.Add(connection);
    }
}
kyoryu
A: 

I think I found the solution..

Here's the link. http://msdn.microsoft.com/en-us/magazine/cc163537.aspx

Try to look at figure 6. That's what I'm trying to achieve.

Lawrence A. Contreras
Look at my example... I simplified it with only one operation, but it's the same pattern.
kyoryu