14

I'm using OperationContext.Current.GetCallbackChannel to get a channel to the client that called a WCF service operation.

Do I need to worry about closing / disposing these callback channels or is this taken care of by the framework?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Peladao
  • 4,036
  • 1
  • 23
  • 43

2 Answers2

6

Well, I just tried it myself and it turns out that if you Close & Dispose the callback channel (after casting to IClientChannel) the entire Service channel becomes useless and when called throws a ProtocolException saying:

"This channel can no longer be used to send messages as the output session was auto-closed due to a server-initiated shutdown. Either disable auto-close by setting the DispatchRuntime.AutomaticInputSessionShutdown to false, or consider modifying the shutdown protocol with the remote server."

I assume that this is an unwelcome consequence or side effect of attempting to close & dispose the callback channel, meaning that this should not be done.

Peladao
  • 4,036
  • 1
  • 23
  • 43
1

In my opinion you should.

The callback mechanism supplies nothing like a higher-level protocol for managing the connection between the service and the callback endpoint. It is up to the developer to come up with some application-level protocol or a consistent pattern for managing the lifecycle of the connection. The service can only call back to the client if the client-side channel is still open, which is typically achieved by not closing the proxy. Keeping the proxy open will also prevent the callback object from being garbage-collected. If the service maintains a reference on a callback endpoint and the client-side proxy is closed or the client application itself is gone, when the service invokes the callback it will get an ObjectDisposedException from the service channel. It is therefore preferable for the client to inform the service when it no longer wishes to receive callbacks or when the client application is shutting down. To that end, you can add an explicit Disconnect() method to the service contract. Since every method call carries the callback reference with it, in the Disconnect() method the service can remove the callback reference from its internal store.

here is an exemple :

class MyService : IServiceContract
{
   static List<IServiceContractCallback> m_Callbacks = new List<IServiceContractCallback>();
public void Connect()
{
    IServiceContractCallbackcallback = OperationContext.Current.GetCallbackChannel<IServiceContractCallback>();
    if(m_Callbacks.Contains(callback) == false)
    {
       m_Callbacks.Add(callback);
    }
}
public void Disconnect()
{
    IServiceContractCallback callback = OperationContext.Current.GetCallbackChannel<IServiceContractCallback>();
    if(m_Callbacks.Contains(callback))
    {
        m_Callbacks.Remove(callback);
    }
    else
    {
        throw new InvalidOperationException("Cannot find callback");
    }
}

In such a way a client can inform the service that the callback is no longer needed. Does it answer your question ?

Tomasz Jaskuλa
  • 15,723
  • 5
  • 46
  • 73
  • I see. So to call Close and Dispose on the callback channel, to what type should I cast the channel? IClientChannel or something else? – Peladao Nov 18 '11 at 13:16
  • 3
    No this is not what I meant. I understand the need for doing what you suggest, but on top of that, I am wondering if it is necessary to add 'callback.Close' and/or 'callback.Dispose' before 'm_Callback.Remove(callback)'. – Peladao Nov 18 '11 at 21:03