Search code examples
c#wcfmessage-passingduplex

Multilayer WCF duplex communication


I have this problem. I have two WCF services - ServiceA and ServiceB. Both services are host in different windows services and communicate via net.tcp. Client access Service A. In Service A I access Service B. Problem what I got is that I want to communication be duplex.

That is I want client to call method TestA in ServiceA. This method would call method TestB in ServiceB. Method TestB would make some long duration action and then raises callback back to ServiceA that would raises callback to client. Methods TestAand TestBare one way contracts.

communication schema

I can get to the point in which ServiceA raises callback back to client. Then it crashes on InvalidCastException trying to get callback channel in operation context.

IServiceACallback Callback
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel<IServiceACallback>();
        }
    }

Is it because I am in a different thread and operation context is just simply not complete? Because I can raise callback back to client when I am not doing it from another callback from ServiceB. Can I solve it with some service attributes maybe? Or is there some communication pattern that I can use?


Solution

  • Ok, I figure it out.

    By raising callback from ServiceB to ServiceA I was in different OperationContext. This context was on entirely different thread so got no connection with the Client but instead got part of OperationContext from ServiceB.

    I added new member to CallbackHandler of ServiceA that points to OperationContext. To this I pass current context during creation of ServiceB using DuplexChannelfactory. This context is the correct one and can be used to raises callbacks back to Client. I hope that code makes it understandable.

    Creation of ServiceB in ServiceA:

    InstanceContext context = new InstanceContext(new CallbackHandler(OperationContext.Current));
    ChannelFactory<IService> factory = new DuplexChannelFactory<IServiceB>(context, binding, address);
    IServiceB service = factory.CreateChannel();
    

    CallbackHandler of ServiceA:

    public class CallbackHandler : IServiceBCallback
    {
        OperationContext _context;
    
        public CallbackHandler(OperationContext context)
        {
            _context = context;
        }
    
        public void TestProgress(string msg)
        {
            IServiceACallback callback = _context.GetCallbackChannel<IServiceACallback>();
            callback.TestProgress(msg);
        }
    }