How to implement a contract callback using a oneway method in WCF

Introduction :

In this demonstration we will see how to create a one way method in a WCF contract. This is used in the case when you concider that an exposed method in your service, will be running for a long time when you want to still handle your application during this moment.

For our demonstration we will concider one service which exposes a simple Select() method to provide informations about employees of a company from a database. Our client will bind its received datas in a datagridview and show them. Concidering that you know how to implement a business and mapping object layer we will not introduce the way how datas are requested in the database.

The following picture shows us the WCF concept :
WCF01
Service Side

Here’s how this type of solution is mostly organised:

Image11

The first thing that we have to define is the exposed datas.
Here we want to access to a list of employees in a database. So we implement Employe class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace Contracts.ComplexTypes
{
 [DataContract]
 public class Employe
 {
  [DataMember]
  public string FirstName
  {get;set;}
  [DataMember]
  public string LastName
  {get;set;}
 }
}

DataContract is the attribute used to expose our type Employe.
DataMember is the attribute used to exposed our properties.

When this is done, create a contract which is a C# interface ICompany. By this contract we are able to define exposed method through our simple service host console:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Contracts.ComplexTypes;

namespace Contracts
{
 [ServiceContract]
 public interface ICompanyCallBack
 {
  [OperationContract(IsOneWay = true)]
  void Notify(List<Employe>listEmp);
 }

 [ServiceContract(CallbackContract = typeof(ICompanyCallBack))]
 public interface ICompany
 {
  [OperationContract]
  List<Employe>Select();

  [OperationContract(IsOneWay=true)]
  void SelectOne();
 }
}

ServiceContract is the attribute used to indicate that our contract has to expose defined methods inside. The OperationContract attribute define which methods will be exposed to the service.
Here we can see 2 ServiceContract :
ICompany interface implement a oneway method to tell :
“When a client is using me, he won’t be obliged to wait for a response from me!!”.
This ServiceContract has a CallBackContract which define used contract and its method to do the callback.

Now let’s implement our methods:

namespace Services
{
    public class Company : ICompany
    {
        #region ICompany Membres
        public List<Employe>Select()
        {
            return Business.BusinessData.select();
        }

        public void SelectOne()
        {
            //Simulate a long process
            System.Threading.Thread.Sleep(5000);
            List<Employe>listEmp = Business.BusinessData.select();
            ICompanyCallBack callBack = OperationContext.Current.GetCallbackChannel<ICompanyCallBack>();
            callBack.Notify(listEmp);
        }
        #endregion
    }
}

In the SelectOne() method we need to get the callback context transmitted by the client using an OperationContext.
GetCallbackChannel define the service contract ICompanyCallBack which will have to be implemented by the client to be notified.

Now let’s see the service host class and its configuration file:

namespace ClassicHost
{
   class Program
   {
     public static void Main(string[] args)
     {
       ServiceHost host = new ServiceHost(typeof(Services.Company));
       host.Open();
       Console.Write('Service host is listening...');
       Console.Read();
       host.Close();
     }
  }
}

Here’s the App.config file :
Click over me!!

Client Side

Our client is a winForm application which provide a binding between a datagridview datasource and the return of exposed oneway method SelectOne().

private void button1_Click(object sender, EventArgs e)
{
   //Note "MyEndPoint" EndPoint name in parameter of the DuplexChannelFactory constructor.
   //"This" keyWord is here to notify which class implement the
   //callback interce ICompanyCallBack
   DuplexChannelFactory<Contracts.ICompany>factory =
   new DuplexChannelFactory<Contracts.ICompany>(this,"MyEndPoint");

  //Thanks to he proxy we access to exposed method SelectOne().
   Contracts.ICompany proxy = factory.CreateChannel();
   proxy.SelectOne();
}

#region ICompanyCallBack Membres
public void Notify(List<Contracts.ComplexTypes.Employe>listEmp)
{
   //The Thread where we will called is not the Thread which has created
   //the user control, so we use the MethodInvoker to proceed.
   dataGridView1.Invoke(new MethodInvoker
            (delegate()
             {
               this.dataGridView1.DataSource = null;
               this.dataGridView1.DataSource = listEmp;
             }
            )
            );
    }
#endregion

As we have already said, the client implements ICompanyCallBack to be able to notify when the exposed method has finished to process.
The client configuration file App.config has the same EndPoint as what is defined in App.config of ClassicHost:

Click over me!!

You will be able to note that between the time you click on GetEmployeesCallBack button and the time when you receive the result, you still can handle your form(not freezed)!!!

Click here

Thanks for reading!! 😉