Geeks With Blogs
Ram Kinkar Pandey

Implementing callback in WCF services.

 

This is a way of writing asynchronous code using wcf services. But do we know why to do this explicitly when adding a service reference also gives you a facility of generating asynchronous operations? This is because the asynchronous operations which we generate while adding service reference are not fake asynchronous calls, in fact they are synchronous call only, just let code not to wait for the response/ notification and it has its timeout period and will throw a timeout exception if response/notification will not be received before timeout. So for implementing real asynchronous operations we like to implement callbacks using callback contract.

 

Not all bindings supports callback mechanism. We got 2 binding with the help of which we can implement callback

  1. netTcpBinding
  2. wsDualHttpBinding

There are 2 important things which make any binding to support callback

 

  1. binding must allow session
  2. binding protocol should allow call from server to client.

 

BasicHttpBinding does not support session so callbacks are not allowed and other http binding do not support callback because http protocol does not allow notification server to each on the on same port.

 

Then how wsDualHttpBinding supports callback?

While using wsDualHttpBinding client used to pass a callback address to server and server can use this address to notify back to client.

 

However netTcpBinding protocol allows notification from server on same port.

 

So we will see how we can implement callback using these 2 bindings. For wsDualHttpBinding we will host our application in IIS and for netTcpBinding we will host our application in a console, as in IIS 6.0 we can not host netTcpBinding applications.

 

For these implementations I have used one service contract and used with both kind of bindings and have used “Add Service Reference” mechanism to add service references in client. I have used Http Url to expose metadata of netTcpBinding service so use http Url to add service reference.

 

Using wsDualHttpBinding :

 

Service Contract:

 

// NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.

    [ServiceContract(CallbackContract = typeof(ICallback), SessionMode=SessionMode.Required)]

    public interface ISampleService

    {

 

        [OperationContract(IsOneWay = true)]

        void GetData(string value);

 

        // TODO: Add your service operations here

    }

 

    public interface ICallback

    {

        [OperationContract(IsOneWay = true)]

        void Notify(string value);

    }

 

Server Implementation:

 

public class SampleService : ISampleService

    {

        private string result;

       

        public void GetData(string value)

        {

            result = string.Format("You entered: {0}", value);

            

            Thread.Sleep(5000);

            OperationContext.Current.GetCallbackChannel<ICallback>().Notify(value);

        }

 

       

    }

 

Server Configuration:

 

<system.serviceModel>

    <services>

      <service name="wsDualHttpBinding.SampleService" behaviorConfiguration="wsDualHttpBinding.SampleServiceBehavior">

        <!-- Service Endpoints -->

        <endpoint address="" binding="wsDualHttpBinding" contract="wsDualHttpBinding.ISampleService">

          <!--

              Upon deployment, the following identity element should be removed or replaced to reflect the

              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity

              automatically.

          -->

          <identity>

            <dns value="localhost"/>

          </identity>

        </endpoint>

       

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="wsDualHttpBinding.SampleServiceBehavior">

          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->

          <serviceMetadata httpGetEnabled="true"/>

          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

 

Client Implementation:

 

public partial class TestForm : Form

    {

        public TestForm()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            InstanceContext instanceContext=new InstanceContext(new SampleServiceCallback());

           

            SampleServiceProxy.SampleServiceClient sampleServiceClient = new SampleServiceClient(instanceContext);

            sampleServiceClient.GetData("using wsDualHttpBinding,You have entered :"+textBox1.Text);

 

            netTcpSampleServiceProxy.SampleServiceClient netTcpsampleServiceClient=new netTcpSampleServiceProxy.SampleServiceClient(instanceContext);

            sampleServiceClient.GetData("using netTcpBinding, You have entered :"+textBox1.Text);

        }

 

    }

 

    public class SampleServiceCallback : ISampleServiceCallback

    {

 

        #region ISampleServiceCallback Members

 

        public void Notify(string value)

        {

            MessageBox.Show(value);

        }

 

        #endregion

    }

 

Client Configuration:

 

<system.serviceModel>

        <bindings>

            <netTcpBinding>

                <binding name="NetTcpBinding_ISampleService" closeTimeout="00:01:00"

                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

                    transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"

                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"

                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"

                    maxReceivedMessageSize="65536">

                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />

                    <reliableSession ordered="true" inactivityTimeout="00:10:00"

                        enabled="false" />

                    <security mode="Transport">

                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />

                        <message clientCredentialType="Windows" />

                    </security>

                </binding>

            </netTcpBinding>

            <wsDualHttpBinding>

                <binding name="WSDualHttpBinding_ISampleService" closeTimeout="00:01:00"

                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

                    bypassProxyOnLocal="false" clientBaseAddress="http://localhost:8881/wsDualHttpBinding"

                    transactionFlow="false" hostNameComparisonMode="StrongWildcard"

                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"

                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">

                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />

                    <reliableSession ordered="true" inactivityTimeout="00:10:00" />

                    <security mode="Message">

                        <message clientCredentialType="Windows" negotiateServiceCredential="true"

                            algorithmSuite="Default" />

                    </security>

                </binding>

            </wsDualHttpBinding>

        </bindings>

        <client>

            <endpoint address="http://localhost/wsDualHttpBinding/SampleService.svc" binding="wsDualHttpBinding"

                bindingConfiguration="WSDualHttpBinding_ISampleService" contract="SampleServiceProxy.ISampleService"

                name="WSDualHttpBinding_ISampleService">

                <identity>

                    <dns value="localhost" />

                </identity>

            </endpoint>

            <endpoint address="net.tcp://localhost:9000/SampleService" binding="netTcpBinding"

                bindingConfiguration="NetTcpBinding_ISampleService" contract="netTcpSampleServiceProxy.ISampleService"

                name="NetTcpBinding_ISampleService">

                <identity>

                    <dns value="localhost" />

                </identity>

            </endpoint>

        </client>

    </system.serviceModel>

 

Using netTcpBinding :

 

Service Contract:

 

// NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.

    [ServiceContract(CallbackContract = typeof(ICallback), SessionMode=SessionMode.Required)]

    public interface ISampleService

    {

 

        [OperationContract(IsOneWay = true)]

        void GetData(string value);

 

        // TODO: Add your service operations here

    }

 

    public interface ICallback

    {

        [OperationContract(IsOneWay = true)]

        void Notify(string value);

    }

 

Server Implementation:

 

public class SampleService : ISampleService

    {

        private string result;

       

        public void GetData(string value)

        {

            result = string.Format("You entered: {0}", value);

           

            Thread.Sleep(5000);

            OperationContext.Current.GetCallbackChannel<ICallback>().Notify(value);

        }

 

       

    }

 

Server Configuration:

 

  <system.serviceModel>

    <services>

      <service name="wsDualHttpBinding.SampleService" behaviorConfiguration="wsDualHttpBinding.SampleServiceBehavior">

        <!-- Service Endpoints -->

        <endpoint address="net.tcp://localhost:9000/SampleService" binding="netTcpBinding" contract="wsDualHttpBinding.ISampleService">

          <!--

              Upon deployment, the following identity element should be removed or replaced to reflect the

              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity

              automatically.

          -->

          <identity>

            <dns value="localhost"/>

          </identity>

        </endpoint>

        <!--<host>

          <baseAddresses>

            <add baseAddress="net.tcp://localhost:9000/SampleService"/>

          </baseAddresses>

        </host>-->

        <!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="wsDualHttpBinding.SampleServiceBehavior">

          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->

          <serviceMetadata httpGetEnabled="true"/>

          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

 

Server Hosting:

 

ServiceHost host = new ServiceHost(typeof(SampleService), new Uri("http://localhost:8090/SampleService"));

            host.Open();

            ServiceEndpointCollection endpoints = host.Description.Endpoints;

            foreach (ServiceEndpoint endpoint in endpoints)

            {

                Console.WriteLine("The 'SampleService' service host is listening at {0}", endpoint.Address);

            }

            Console.WriteLine("Press <enter> to terminate the service.");

            Console.ReadLine();

 

Client Implementation:

 

Same as wsDualHttpBinding client implementation (As I have used same client for both kind of bindings.)

 

Client Configuration:

 

Same as wsDualHttpBinding client implementation (As I have used same client for both kind of bindings.)

 

 

Posted on Saturday, October 24, 2009 5:09 AM WCF | Back to top


Comments on this post: Implementing Callback using WCF

# re: Implementing Callback using WCF
Requesting Gravatar...
Duplex WCF client objects function like their nonduplex counterparts, with the exception that they expose the functionality necessary to support callbacks, including the configuration of the callback service.Duplex services specify a callback contract that the client application must implement in order to provide a callback object for the service to call according to the requirements of the contract..... ...
Left by empfohlenes Casino on Mar 18, 2010 8:06 PM

# re: Implementing Callback using WCF
Requesting Gravatar...
Thx man - i was searching half of the net for a tutorial with a callback service using netTcpBinding. Now I found it :)) thx!!
Left by Philipp on Mar 22, 2011 1:12 AM

# re: Implementing Callback using WCF
Requesting Gravatar...
Thanx buddy,,,,hope u publish much more such rich & well described articles. it really easyl to understand.
Left by sumanta das on Jan 22, 2012 7:11 PM

# re: Implementing Callback using WCF
Requesting Gravatar...
I copied the code above to my system and could not get it to build because ISampleServiceCallback in the server implementation was undefined.
I tried using ICallback as the reference, but it too was undefined.
If you could post more details about the steps required to successfully make this app work, that would be appreciated.
Left by Tim on Aug 27, 2012 4:28 AM

# re: Implementing Callback using WCF
Requesting Gravatar...
Sorry, but this did not work! Dont get me wrong, but where is the rest of the implementation?
Left by Viktor on Jan 17, 2013 2:58 AM

# re: Implementing Callback using WCF
Requesting Gravatar...
this codes only work in localhost. but not work in internet !!
what is problem?!
Left by FARHAD on Dec 06, 2014 1:52 AM

Your comment:
 (will show your gravatar)


Copyright © ramkinkarpandey | Powered by: GeeksWithBlogs.net