Hi

I'm developing a WCF service, which defines a callback contract through which the server can call a method on the client. Below is a sample code:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = (typeof(ISampleServiceCallback)))]
public interface ISampleService 
{  
    [OperationContract(IsInitiating = true, IsTerminating = false, IsOneWay = false)]        
    bool Register(int controllerId);        
    [OperationContract(IsInitiating = false, IsTerminating = true, IsOneWay = true)] 
    void Unregister();    
}

[ServiceContract]
public interface ISampleServiceCallback 
{ 
    [OperationContract(IsOneWay = false)]        
    bool ReceiveMessage(string message);    
}

The problem arises when the client on exit fails to call the Unregister() method - becouse of a crash or something, so the server still has the reference to the client's callback channel. When the server calls the ReceiveMessage method on the client, that method blocks for the time specified by the "sendTimeout" in the app.config before throwing an exception. I tried using the following approach to call the callback method

public delegate bool ReceiveDelegate(string message);
public void NotifyClient(string message)
{    
    ReceiveDelegate receiver = new ReceiveDelegate(_callback.ReceiveMessage); //_callback is a reference to the callback channel    
    receiver.BeginInvoke(message, new AsyncCallback(onReceiveCompleted), receiver); 
}

private void onReceiveCompleted(IAsyncResult result)
{    
    bool ok = false;    
    try    
    {        
        ok = ((ReceiveDelegate)result.AsyncState).EndInvoke(result);    
    }    
    catch(Exception ex)    
    {        
        string error = ex.Message;    
    }
}

In the example above, the receiver.BeginInvoke() still blocks the calling thread - which is wird becouse when I tried calling another long-lasting function the same way and the call to BeginInvoke did not block.
So my question is: How can I define and implement the ReceiveMessage method as asynchronous, so it will not block the calling thread.
Any idea will be appreciated

Uros

Can you upload a sample project demonstrating the issue? I spend a considerable amount of time implementing the same feature with .NET Remoting altough remoting is less robust than WCF.

Also what lines blocks for the timeout period? Looking at this code:

public void NotifyClient(string message)
{    
    ReceiveDelegate receiver = new ReceiveDelegate(_callback.ReceiveMessage); //_callback is a reference to the callback channel    
    receiver.BeginInvoke(message, new AsyncCallback(onReceiveCompleted), receiver); 
}

I'm guessing your code blocks on the ReceiveDelegate receiver = new ReceiveDelegate line which leads me to believe that WCF is testing the client to make sure it is alive. I am not aware of calling .BeginInvoke() in any way that makes the calling thread block. You could also call the NotifyClient() method asynchronously instead of just the call to the client method.

You can also catch the timeout exceptions and remove the reference to that client in your server application so you're not hanging on to dead connections.

Edited 6 Years Ago by sknake: n/a

Hi

I checked it again and the line that is blocking the calling thread is receiver.BeginInvoke() and not the previous line, when the delegate instance is created. I am attaching a Sample service and client. They are both created were sloppy - just to show the blocking BeginInvoke call

Uros

See Nick Allens (WCF Architect) from MSFT.
http://blogs.msdn.com/drnick/archive/2007/06/12/begininvoke-bugs.aspx
I spent about a full afternoon trying to figure this one out.
Hope this helps.

Hi

I checked it again and the line that is blocking the calling thread is receiver.BeginInvoke() and not the previous line, when the delegate instance is created. I am attaching a Sample service and client. They are both created were sloppy - just to show the blocking BeginInvoke call

Uros

This article has been dead for over six months. Start a new discussion instead.