Tuesday, June 5, 2012

Callbacks in WCF with an Example

WCF allows service to call back its clients. This way service acts like client and client acts like a service. Client must support\facilitate call back by hosting call back object. Clients are required to support the call back and provide the end point info of call back in their every call to the service. Steps involved in creating a call  back are,

a. Service defines call back type(interface that client's call back handler class must implement). Call back contract need not be marked as Service contract but it is implied.
b. Service contract mentions name of call back type in the service contract attribute.

//call back type

interface IExampleCallBack
{
   [OperationContract] 
   void ClientAction();
}

[ServiceContract(CallbackContract = typeof(IExampleCallback))] 
interface IExampleContract
{
   [OperationContract] 
   void ServiceMethod1();
}

c. Client creates call back host by providing bindings that support call backs, endpoint for the call back and the call back class that implements the call back type. Though this class need not have the attribute ServiceBehavi
d. Client instantiates InstanceContext class by providing call back handler object as parameter to the constructor. 
e. Since Client is supposed to pass call back end point info to the service. Client shall pass this InstanceContext object while creating the proxy.


class ExampleCallBack: IExampleCallBack
{
   public void ClientAction() {//do something based on service call}
}
IExampleCallBack callback = new ExampleCallBack();
InstanceContext context = new InstanceContext(callback);
ExampleContractClient proxy = new ExampleContractClient(context);
proxy.ServiceMethod1();

Service can use OperationContext to get the call back instance and then call methods on call back instance i.e. methods on client side.

IExampleCallBack callback = OperationContext.Current.GetCallbackChannel<IExampleCallBack>();
callback.ClientAction();  

Important Notes and Points about Call backs:

1. HTTP does not support call back because of its connection less nature.  Hence we cannot use BasicHttpBinding or WSHttpBinding for call back mechanism. NetTcpBinding, NamedNetPipeBinding can support call backs due to their underlying bidirectional transport. WSDualHttpBinding also supports call back mechanism by setting two http channels underneath.

2. By default service class is single threaded. Service instance is associated with a lock and only one thread can own this lock at a time, to access the service instance. Invoking the clients code requires service thread to be blocked while call backs are invoked. A deadlock would occur since when clients reply, processing that reply would need ownership of service instance's lock. There are three ways to avoid this deadlock:
    a. Making the service behavior Multithreaded, which means more resources and complex synchronization.
  b. Making the service behavior class as Re-Entrant. A service can be configured as re-entrant by setting the concurrency mode as ConcurrencyMode.Reentrant. When service is configured to be reentrant, service instance still is locked and owned by single thread. But WCF will release the lock quietly before invoking a call back method.
    c. Making the call back methods as OneWay. This can be done  by setting IsOneWay tag on call back operation contract to true. This assures there will be no reply from the client and hence eventhough service is single threaded there would be no deadlock.
    

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
class ExampleService : IExampleContract
{
   public void ServiceMethod1()
   {
      IMyContractCa llback callback = OperationContext.Current.GetCallbackChannel<IExampleCallback>();
      callback.ClientAction();
   }
}

IsOneWay Attribute:



interface IExampleCallBack
{
   [OperationContract(IsOneWay = true)] 
   void ClientAction();
}






No comments:

Post a Comment