Friday, May 25, 2012

WCF-Callback Contract

Callback Contract :

Callback operations are part of the service contract  and   service contract can have at most one callback contract
Once callback contract defined, the clients are required to support the callback and provide the callback endpoint to the service in every call.
To define a callback contract, the ServiceContract attribute offers the CallbackContract property



[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class)]
        public sealed class ServiceContractAttribute : Attribute
        {
            public Type CallbackContract
            { get; set; }
            //More members
        }

Example :
       interface IMyFirstContractCallback
        {
            [OperationContract]
            void OnCallback();
        }

        [ServiceContract(CallbackContract = typeof(IMyFirstContractCallback))]
        interface IMyFirstInterface
        {
            [OperationContract]
            void AnyMethod();
        }

Note :
 Callback contract need not be defined with a ServiceContract  attribute  and it will be included in the service metadata.  
 All methods in callback interface defined with with the OperationContract attribute.
Once the client imports the metadata of the callback contract, the imported callback interface will not have the same name as in the original service-side definition. It will become interface suffixed with the word Callback.

Example :
Interface :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace CallBackOperation
{

    //Interface IDuplexServiceContract which is our service contract
    //In service Contract need to make sure WCF maintains session information for the duration of a      client's connection.
    //Secondly, we need to specify that which interface will be handling the callback contract eg :IDuplexCallback.
    [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IDuplexCallback))]
    public interface IDuplexServiceContract
    {
        [OperationContract(IsOneWay = true)]
        void Stringmanagement(string value);

        [OperationContract]
         List<string> GetData();
    }


    //Callback contract which client will call, creating a new interface IDuplexCallback
    //This interface has two Call Back methods ,In order that it should be asynchronous,
    //we have defined the one-way attribute on the doHugeTask method.
   
    public interface IDuplexCallback
    {
        [OperationContract(IsOneWay = true)]
        void CallBacktestingFunction(string requestString);

        [OperationContract(IsOneWay = true)]
        void LodingDataStatus(string[] data);
    }
}


Service :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Text;
using System.Threading;
using System.Data.SqlClient;
using System.Data;

namespace CallBackOperation
{
    //InstanceContextMode is PerSession because the use of callback contracts requires a session
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class DuplexCallBack : IDuplexServiceContract
    {
       
        SqlConnection Conn;    
        IDuplexCallback _callback;
        string _requestString = String.Empty;

        public DuplexCallBack()
        {
            //The OperationContext.Current.GetCallBackChannel will be used to make callback to the client.
            //When the service receives a call, OperationContext.Current.GetCallbackChannel returns a channel to just that caller.
            //It does not return a channel that broadcasts to all of the clients.
            _callback = OperationContext.Current.GetCallbackChannel<IDuplexCallback>();
            Conn = new SqlConnection("Connection String");
     
        }


        public void Stringmanagement(string value)
        {          
            _requestString = string.Format("Hey, Welcome {0} , So finally you did it.", value);    
            // CallBack Function
            _callback.CallBacktestingFunction(_requestString);
        }



        List<string> IDuplexServiceContract.GetData()
        {
            List<string> lstFunds = new List<string>();
            Conn.Open();
            SqlCommand Cmd = new SqlCommand("Select top 10 FundName from tblfund order by FundID", Conn);
            SqlDataReader Reader = Cmd.ExecuteReader();
            while (Reader.Read())
            {
                lstFunds.Add(Reader["FundName"].ToString());
            }
            Reader.Close();
            Conn.Close();
            string[] returndataArray = lstFunds.ToArray();
            // CallBack Function
            _callback.LodingDataStatus(returndataArray);
            return lstFunds;
        }
    }
}



WebConfig :

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
      <add name="ScriptModule" preCondition="integratedMode" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </modules>
    <handlers>
      <remove name="WebServiceHandlerFactory-Integrated" />
      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </handlers>
    <directoryBrowse enabled="true" />
  </system.webServer>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="DuplexWcfService.Service1Behavior" name="CallBackOperation.DuplexCallBack">
        <endpoint address="http://localhost:62345/DuplexCallBack.svc" binding="wsDualHttpBinding" contract="CallBackOperation.IDuplexServiceContract">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DuplexWcfService.Service1Behavior">
          <!-- 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="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>



Add Service reference :



 

 




Client WebConfig :
  
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsDualHttpBinding>
                <binding name="WSDualHttpBinding_IDuplexServiceContract" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" 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:62345/DuplexCallBack.svc"
                binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IDuplexServiceContract"
                contract="ServiceReference1.IDuplexServiceContract" name="WSDualHttpBinding_IDuplexServiceContract">
                <identity>
                    <userPrincipalName value="vikas.kumar@Vam.Local" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>



Client Code :



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Console_CallBack_Client.ServiceReference1;
namespace Console_CallBack_Client
{

    //Following methods are callback methods, which the server will call after service methods completed eg :  Stringmanagement() and GetData.
    class DuplexCallbackHandler : IDuplexServiceContractCallback
    {
        public void CallBacktestingFunction(string value)
        {
            Console.WriteLine("\n");
            Console.WriteLine("\t Callback returned from the server");
            Console.WriteLine("\n");
            Console.WriteLine(value);
            Console.WriteLine("\n");
          
        }

        public void LodingDataStatus(string[] data)
        {
            Console.WriteLine("\n");
            Console.WriteLine(string.Format("Total Length of array  : {0}", data.Length.ToString()));
            Console.WriteLine("\n");
        }

    }
     
   
    class Program
    {
        static void Main(string[] args)
        {

            //here I create object of the Instance Context class.Instance Context represents context information of a service.
            //The main use of Instance Context is to handle incoming messages.
            //In short, service reference or proxy is used to send messages to server and Instance Context is used to accept incoming messages.

              InstanceContext instanceContext = new InstanceContext(new DuplexCallbackHandler());
            //In this step we pass the Instance Context object to the constructor of service reference or proxy.
            //server will use the same channel to communicate to the client.

              DuplexServiceContractClient client = new DuplexServiceContractClient(instanceContext);
               client.Stringmanagement("Guugeeaa");               
                 string[] listvalues;
              
                 listvalues = client.GetData();

                 for (int i = 0; i <= listvalues.Length - 1; i++)
                 {
                     Console.WriteLine(listvalues[i].ToString());
                 }
                 Console.WriteLine("\n");
                 Console.ReadLine();

        }
    }
}








 OutPut  :




 

No comments :

Post a Comment