Praveen Katiyar' Blog

Learning along the way . . . .

Understanding Events in WCF

Introduction

Events allow the client or clients to be notified that something has occurred on the service side, An event may result from a direct client call, or may be the result of something the service monitors.

Background

While events in WCF are nothing more than call back operations, however by their very nature events usually imply a looser relationship between the publisher and the subscriber than a typical relationship between a client and a service. The Service firing the event is called the publisher, and the client receiving the event is called the subscriber. service typically publishes the same event to multiple subscribing clients. the publisher often does not care about the order of invocation of the subscribers, or any errors, all the publishers knows is that it should deliver the event to the subscribers.

Since service does not care about the returned results from the subscribers. Consequently, event handling operations

  • Should have void return type. 
  • Should not have any out/ref parameters.
  • Should be marked as one way.

Using the code

This article has been divided into 3 modules:

  • WCF Service Library (EventsLib.dll): Actual Service logic, which defines a Service Contract Interface, OperationContract, and implements them, and exposes few functions to the world to use them
  • Console based Host Application to host the WCF Service Library EventsLibHost.exe): Host the WCF library
  • Console Client Application (EventsClient.exe): Client Application which will use this service.

First Module: WCF Service Library (EventsLib.dll)

To create this project, you can simply take a "Class Library" project, while choosing from project wizard option. let’s name it "EventsLib", it is the actual service which implements the business logic. The project already contains a file Class1.cs, let us do some house keeping, before we write any code for the service library  

Little house keeping

  • Delete the file Class1.cs from the project workspace.
  • Add a new Interface named ICalcService  to the project, a new file ICalcService.cs will be added to the project.
  • Add a new Class named CalcService, to the project. that will implement the ICalcService interface, a new file CalcService.cs will be added to the project.
  • Add a new Interface named ICalcServiceEvents  to the project, a new file ICalcServiceEvents.cs will be added to the project.

Defining Interface ICalcServiceEvents (ICalcServiceEvents.cs)

so let’s define interface for the events published by the service.

//  Listing of ICalcServiceEvents.cs
using System;
using System.Text;
using System.ServiceModel;

namespace EventsLib

{

    public interface ICalcServiceEvents

    {

        [OperationContract(IsOneWay = true)]

        void Calculated(int nOp, double dblNum1, double dblNum2, double dblResult);

        [OperationContract(IsOneWay = true)]

        void CalculationFinished();

    }

}

Explanation

Interface simply publishes 2 method. which are basically events for the subscriber. note that, every method in this interface has been

  • Marked as OneWay
  • Does not return any value (void)
  • Has no out/ref parameter

First method Calculated is an event for the subscriber, it is fired, when calculation is done, it also passes the result to the subscribers. along with the operands and operation type.

Second Method CalculationFinished is the event, it is fired, when the Calculation is finished.

 

Defining Interface ICalcService (ICalcService.cs)

so let’s define interface for the service.

//  Listing of ICalcService.cs
using System;
using System.Text;
using System.ServiceModel ;

namespace EventsLib

{

    [ServiceContract(CallbackContract = typeof(ICalcServiceEvents))]

    public interface ICalcService

    {

        [OperationContract]

        void Calculate(int nOp, double dblNum1, double dblNum2);

        [OperationContract]

        void SubscribeCalculatedEvent();

        [OperationContract]

        void SubscribeCalculationFinishedEvent();

    }

}

Explanation

Interface simple defines 3 method.

First Method Calculate is the method, that is related to business logic. that does the actual job. the other two methods are helper methods that are called by the client to subscribe a event published by the client. as you have 2 events, so you have one method for each event.

Implementing ICalcService interface (CalcService.cs)

//  Listing of CalcService.cs

using System;

using System.Text;

using System.ServiceModel;

namespace EventsLib

{

    public  class CalcService : ICalcService

    {

       static Action<int, double, double, double> m_Event1 = delegate { };

       static Action m_Event2 = delegate { };

      public void SubscribeCalculatedEvent()

       {

           ICalcServiceEvents subscriber = OperationContext.Current.GetCallbackChannel<ICalcServiceEvents>();

           m_Event1 += subscriber.Calculated;

       }

       
        public void SubscribeCalculationFinishedEvent()

        {

            ICalcServiceEvents subscriber = OperationContext.Current.GetCallbackChannel<ICalcServiceEvents>();

            m_Event2 += subscriber.CalculationFinished ;

        }

              
        public void Calculate(int nOp, double dblX, double dblY)

        {

            double dblResult = 0;

            switch (nOp)

            {

                case 0: dblResult = dblX + dblY; break;

                case 1: dblResult = dblX – dblY; break;

                case 2: dblResult = dblX * dblY; break;

                case 3: dblResult = (dblY == 0) ? 0 : dblX / dblY; break;

            }

           
            m_Event1(nOp, dblX, dblY, dblResult);

            m_Event2();

       }

    }

}

Explanation
Member variables

static Action<int, double, double, double> m_Event1 = delegate { };

static Action m_Event2 = delegate { };

Action keyword can be used define a delegate, can be used to pass a method as a parameter without explicitly declaring a custom delegate.

static Action <int, double, double, double> m_Event1 = delegate { };

m_Event1 is declared as it takes  four parameters. parameter list which is defined as

<int, double, double, double>

that explains its parameters list and order. the encapsulated method must correspond to the method signature that is defined by this delegate. that is first parameter is an int and the consecutive 3 are double.

m_Event2 is declared without any parameter

static Action m_Event2 = delegate { };

public void SubscribeCalculatedEvent()

public void SubscribeCalculatedEvent()

you simple take take the reference of Call back channel (that is the reference of sink, that implements ICallbackServiceEvents, and assign the reference of Calculated method to m_Event1.

public void SubscribeCalculationFinishedEvent()

you simple take take the reference of Call back channel (that is the reference of sink, that implements ICallbackServiceEvents, and assign the reference of Calculated method to m_Event2.

these so this method gives a choice, whether the client want to notified about this particular event or not.

public void Calculate(int nOp, double dblX, double dblY)()

This function implements the business logic, simple do the desired operation as specified by nOp parameter,

      double dblResult = 0;

    switch (nOp)

    {

        case 0: dblResult = dblX + dblY; break;

        case 1: dblResult = dblX – dblY; break;

        case 2: dblResult = dblX * dblY; break;

        case 3: dblResult = (dblY == 0) ? 0 : dblX / dblY; break;

    }

     

after that it simply calls both the events in orderly fashion using defined delegates.

     m_Event1(nOp, dblX, dblY, dblResult);

    m_Event2();

Second Module: WCF Service Library Host (EventsLibHost.exe)

To create this project, you can simply take a "Console Application" project, while choosing from project wizard option. let’s name it "EventsLibHost", this application will self host the service. let us do some house keeping, before we write any code for the host application.

Adding application configuration

  • Add an Application configuration (App.config) file to the project.

Defining configuration

before we write any code for the host, let’s define the configuration.

Assumption

The Host application will expose the following endpoints for the service.

  • CalcService will expose HTTP endpoint at Port 9011
  • Corresponding mex End Point (IMetadatExchange) for the HTTP end point.
Defining configuration for CalcService
Defining Endpoints

<service name="EventsLib.CalcService" behaviorConfiguration="CalcServiceBehavior">

   <host>

      <baseAddresses>

         <add baseAddress="http://localhost:9011/CalcService"/&gt;

      </baseAddresses>

    </host>

       
    <endpoint address="" binding="wsDualHttpBinding"  contract="EventsLib.ICalcService"/>

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

</service>

Explanation

The service defines, one endpoint with wsDualHttpBinding, if you notice, you will see, that the address field has been omitted, in the end point definition. you can do this, if you define a base address for the said type.  wsDualHttpBinding provides the same support for web service protocol as WSHttpBinding, but for use with duplex contracts

another endpoint is defined as mex, are defined for publication of metadata, IMetadataExchange is standard contract for mex endpoints.

Defining Behavior

<behaviors>

    <serviceBehaviors>

      <!—CalcService Behavior –>

      <behavior name="CalcServiceBehavior">

        <serviceMetadata httpGetEnabled="true"/>

        <serviceDebug includeExceptionDetailInFaults="true "/>

      </behavior>

    </serviceBehaviors>

</behaviors>

Explanation

each service behavior defines two attributes,  

<serviceMetadata httpGetEnabled="true"  /> 

Gets or sets a value that indicates whether to publich service medtadata for retrieval using an HTTP/GET request, true means yes, metadata is available for retrieval using a HTTP/GET request.

<serviceDebug includeExceptionDetailInFaults="true "/>

Set IncludeExceptionDetailsInFaults to true to enable clients to obtain information about internal service method exceptions; it is only recommended as a way of temporarily debugging a service application. this property must be set to false on production servers.

Hosting Service

As we have defined the configuration for service, Let’s write code to host the service.

// Listing of Program.cs

using System;

using System.Text;

using System.ServiceModel;

namespace EventsLibHost

{

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                ServiceHost host = new ServiceHost(typeof(EventsLib.CalcService));

                host.Open();

                Console.WriteLine("Service is Hosted as http://localhost:9011/CalcService");

                Console.WriteLine("\nPress  key to stop the service.");

                Console.ReadLine();

                host.Close();

            }

            catch (Exception eX)

            {

                Console.WriteLine("There was en error while Hosting Service [" + eX.Message +"]" );

                Console.WriteLine("\nPress  key to close.");

                Console.ReadLine();

            }

        }

    }

}

Build and Execute the Host.

Open a command prompt in administrator mode and execute the host. here is the output.

image

Third Module: Client Application (EventsClient.exe)

To create this project, you can simply take a "Console based Application" project, while choosing from project wizard option. let’s name it "EventsClient", 

a new Project EventsClient will be added to the workspace.  

Generating proxy for the CalcService

While the host application is running, right click on the client application project, click on

References –> Add Service Reference 

In the address bar type the address of the mex endpoint address of CalcService as shown below.

image

press OK, this will add an item named CalcServiceReference under Service References Node in client’s project workspace. and will also add an configuration file (app.config) to the client.

Declaring and Implementing the Callback Interface (Events Sink)

Add a new Class to the client project, let say call it CalcServiceCallbackSink, this is where you will implement the event handlers, for both the events fired by the service. below is the code.

using System;

using System.Text;

namespace EventLibClient

{

    class CalcServiceCallbackSink:CalcServiceReference.ICalcServiceCallback

    {

        public void Calculated(int nOp, double dblNum1, double dblNum2, double dblResult)

        {

            switch (nOp)

            {

                case 0: Console.WriteLine("\nOperation : Addition"); break;

                case 1: Console.WriteLine("\nOperation : Subtraction"); break;

                case 2: Console.WriteLine("\nOperation : Multiplication"); break;

                case 3: Console.WriteLine("\nOperation : Division"); break;

            }

            Console.WriteLine("Operand 1 …: {0}", dblNum1);

            Console.WriteLine("Operand 2 …: {0}", dblNum2);

            Console.WriteLine("Result ……: {0}", dblResult);

        }

        public void CalculationFinished()

        {

            Console.WriteLine("Calculation completed");

        }

    }

}

Explanation

this simply handles both the events fired by the service. here is where you display the output/ or whatever is intended  by that event.

Calling Service

and finally write the code to call the service.

Create the Sink object and InstanceContext object.

CalcServiceCallbackSink objsink = new CalcServiceCallbackSink ();

InstanceContext iCntxt = new InstanceContext(objsink);

Create the service proxy object.

CalcServiceReference.CalcServiceClient objClient =

               new CalcServiceReference.CalcServiceClient(iCntxt);

Subscribe the events we desire to handle,

objClient.SubscribeCalculatedEvent ();

objClient.SubscribeCalculationFinishedEvent ();

Call our methods.

            
double dblNum1 = 1000, dblNum2 = 2000 ;

objClient.Calculate (0, dblNum1, dblNum2);

dblNum1 = 2000; dblNum2 = 4000;

objClient.Calculate(1, dblNum1, dblNum2);

dblNum1 = 2000; dblNum2 = 4000;

objClient.Calculate(2, dblNum1, dblNum2);

dblNum1 = 2000; dblNum2 = 400;

objClient.Calculate(3, dblNum1, dblNum2);

and here is the complete code for the client,

//  Listing of Program.cs

using System;

using System.Text;

using System.ServiceModel;

namespace EventLibClient

{

    class Program

    {

        static void Main(string[] args)

        {

            
            CalcServiceCallbackSink objsink = new CalcServiceCallbackSink ();

            InstanceContext iCntxt = new InstanceContext(objsink);

                
            CalcServiceReference.CalcServiceClient objClient = new CalcServiceReference.CalcServiceClient(iCntxt);

            objClient.SubscribeCalculatedEvent ();

            objClient.SubscribeCalculationFinishedEvent ();

           
            double dblNum1 = 1000, dblNum2 = 2000 ;

            objClient.Calculate (0, dblNum1, dblNum2);

            dblNum1 = 2000; dblNum2 = 4000;

            objClient.Calculate(1, dblNum1, dblNum2);

            dblNum1 = 2000; dblNum2 = 4000;

            objClient.Calculate(2, dblNum1, dblNum2);

            dblNum1 = 2000; dblNum2 = 400;

            objClient.Calculate(3, dblNum1, dblNum2);

            Console.WriteLine("Press any key to close …" );

            Console.ReadKey();

        }

    }

}

and here is the output.

image           

that’s all folks.

 

Advertisements

October 4, 2013 Posted by | .NET, SOA, WCF | , , | Leave a comment

Understanding Operations in WCF

WCF supports 3 ways for a client to call a service.

  1. Request Reply : default way of invocation, the client would issue a call, block while the call was in progress, and would continue executing once the method returned. If service doesn’t respond to the service within receiveTimeout, client will receive TimeOutException.
  2. One way calls: fire and forget type operations. that simply means client will send a request to the server and does not care whether service execution was a success or failure. There is no return value from the server side. Client will be blocked only for a moment till it dispatches its call to service. Client can continue to execute its statement, after making one-way call to the service. sometime calls are queued at the server side to be dispatched one at a time. if the number of queued messages has exceeded the queue’s capacity, client will be blocked for the moment till the message is being queued. and as soon as the call is queued, the client will be unblocked and can continue executing, while the service processes the operation in the background.
  3. Call back Operation: WCF Supports allowing a service to call back to its clients. They are specially useful, for notifying client(s) that something happened on the service side. call backs are also commonly referred as duplex operations. not all binding types support call back operations. for example HTTP (for obvious reasons of being a connectionless nature). only two commonly used binding that offer call backs are NetTcpBinding and NetNamedBinding. to offer call backs over HTTP, WCF offers the WSDualHttpBinding, which actually sets up two WS channels. 

Now to see all these things in action let’s create a service.

Creating the Class Library

let’s create a service, create a new project, take a Class Library template, name it OperationLib, let’s do some house keeping with the newly created project.

  • Delete the file Class1.cs from the project workspace.
  • Add a new Interface named IRequestReplyService to the project, a new file IRequestReplyService.cs will be added to the project. 5t6
  • Add a new Class named RequestReplyService, to the project. that will implement the IRequestReplyService interface, a new file RequestReplyService.cs will be added to the project.
  • Add a new Interface named IOneWayCallService to the project, a new file IOneWayCallService.cs will be added to the project.
  • Add a new Class named OneWayCallService, to the project. that will implement the IOneWayCallService interface, a new file OneWayCallService.cs will be added to the project.
  • Add a new Interface named IDuplexService to the project, a new file IDuplexService.cs will be added to the project.
  • Add a new Class named DuplexService, to the project. that will implement the IDuplexService interface, a new file DuplexService.cs will be added to the project.

to keep the things simple, let’s assume that each interface defines only one method, which simply adds a passed value, to  its member variable.

Defining Interfaces

so let’s define interface for each service.

// Listing of IRequestReplyService.cs

using System;
using System.Text;
using System.ServiceModel;

namespace OperationLib
{
    [ServiceContract]
    interface IRequestReplyService
    {
        [OperationContract]
        double AddValue(double dblNum1, double dblNum2);
    }
}


// Listing of RequestReplyService.cs

using System;
using System.Text;

namespace OperationLib
{
    public class RequestReplyService : IRequestReplyService
    {
        public double AddValue(double dblNum1, double dblNum2)
        {
            return (dblNum1 + dblNum2);
        }
    }
}

// Listing of IOneWayCallService.cs

using System;
using System.ServiceModel;
using System.Text;

namespace OperationLib
{
[ServiceContract(SessionMode = SessionMode.Required)]
   interface IOneWayCallService
   {
        [OperationContract(IsOneWay = true)]
        void AddValue(double dblNum );

        [OperationContract]
        double GetResult();
    }

}


// Listing of OneWayCallService.cs

public class OneWayCallService : IOneWayCallService
    {
        private double m_dblResult = 0;

        public void AddValue(double dblVal)
        {
            m_dblResult += dblVal;
        }

        public double GetResult()
        {
            return m_dblResult;
        }
    }

// Listing of IDuplexService.cs

using System;
using System.ServiceModel;
using System.Text;

namespace OperationLib
{
    interface IDuplexServiceCallback
    {
        [OperationContract]
        void OnValueAdded(double dblNum1, double dblNum2, double dblResult);
    }

    [ServiceContract(CallbackContract = typeof(IDuplexServiceCallback))]
    interface IDuplexService
    {
        [OperationContract()]
        void AddValue(double dblNum1, double dblNum2);
    }
}


// Listing of DuplexService.cs

using System;
using System.ServiceModel ;
using System.Text;

namespace OperationLib
{
    public class DuplexService : IDuplexService
    {
        public void AddValue(double dblNum1, double dblNum2)
        {
            double dblResult = dblNum1 + dblNum2;
            IDuplexServiceCallback callbackInstance = OperationContext.Current.GetCallbackChannel<IDuplexServiceCallback>();
            callbackInstance.OnValueAdded(dblNum1, dblNum2, dblResult);
        }
    }
}

Now to see all these things in action let’s create a service.

Hosting the Service

for the sake of simplicity, i have have hosted this service as a self hosted service, to create the Host application, create a new Console based application.

Before we write any code for the Host application, let’s define the configuration file for the Service(s).

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
     
    

<!–************************* Request Reply Service **************************** –>
      <service name="OperationLib.RequestReplyService" behaviorConfiguration="RequestReplyServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9011/RequestReplyService"/&gt;
            <add baseAddress="net.tcp://localhost:9012/RequestReplyService"/>
          </baseAddresses>
        </host>
       
        <endpoint address="http://localhost:9011/RequestReplyService" binding="wsHttpBinding" contract="OperationLib.IRequestReplyService"/>
        <endpoint address="net.tcp://localhost:9012/RequestReplyService" binding="netTcpBinding" contract="OperationLib.IRequestReplyService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

      <!—******************** OnewayCall Service ************************* –>

<service name="OperationLib.OneWayCallService" behaviorConfiguration="OneWayCallServiceBehavior">
       <host>
         <baseAddresses>
           <add baseAddress="http://localhost:9013/OneWayCallService"/&gt;
           <add baseAddress="net.tcp://localhost:9014/OneWayCallService"/>
         </baseAddresses>
       </host>

       <endpoint address="http://localhost:9013/OneWayCallService" binding="wsHttpBinding" contract="OperationLib.IOneWayCallService"/>
       <endpoint address="net.tcp://localhost:9014/OneWayCallService" binding="netTcpBinding" contract="OperationLib.IOneWayCallService"/>
       <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
       <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
     </service>

     <!—********************* Duplex Service ***************************** –>

<service name="OperationLib.DuplexService" behaviorConfiguration="DuplexServiceBehavior" >
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9015/DuplexService"/&gt;
            <add baseAddress="net.tcp://localhost:9016/DuplexService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9015/DuplexService" binding="wsDualHttpBinding" contract="OperationLib.IDuplexService"/>
        <endpoint address="net.tcp://localhost:9016/DuplexService" binding="netTcpBinding" contract="OperationLib.IDuplexService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

</services>

    <!– ********************************** behaviors ********************************** –>
   

<behaviors>
     <serviceBehaviors>

       <!– Single Call Service Behavior –>
       <behavior name="RequestReplyServiceBehavior">
         <serviceMetadata httpGetEnabled="true"/>
         <serviceDebug includeExceptionDetailInFaults="true "/>
       </behavior>

       <!–Single Session Service Behavior –>
       <behavior name="OneWayCallServiceBehavior">
         <serviceMetadata httpGetEnabled="true"/>
         <serviceDebug includeExceptionDetailInFaults="true "/>
       </behavior>

       <!–Singleton Service Behavior –>
       <behavior name="DuplexServiceBehavior" >
         <serviceMetadata httpGetEnabled="true"  />
         <serviceDebug includeExceptionDetailInFaults="true "/>
       </behavior>
      
     </serviceBehaviors>
   </behaviors>

   
  </system.serviceModel>
</configuration>

Now let’s explain the configuration of each service.

 

<service name="OperationLib.RequestReplyService" behaviorConfiguration="RequestReplyServiceBehavior">
        <host>
          <baseAddresses>
           <add baseAddress="http://localhost:9011/RequestReplyService"/>
            <add baseAddress="net.tcp://localhost:9012/RequestReplyService"/>
          </baseAddresses>
        </host>
       
        <endpoint address="http://localhost:9011/RequestReplyService&quot; binding="wsHttpBinding" contract="OperationLib.IRequestReplyService"/>
        <endpoint address="net.tcp://localhost:9012/RequestReplyService" binding="netTcpBinding" contract="OperationLib.IRequestReplyService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

Explanation:

>> to do

      <!– ******************** Single Session Service ************************* –>
      <service name="OperationLib.OneWayCallService" behaviorConfiguration="OneWayCallServiceBehavior">
        <host>
          <baseAddresses>
           <add baseAddress="http://localhost:9013/OneWayCallService"/&gt;
            <add baseAddress="net.tcp://localhost:9014/OneWayCallService"/>

          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9013/OneWayCallService" binding="wsHttpBinding" contract="OperationLib.IOneWayCallService"/>
        <endpoint address="net.tcp://localhost:9014/OneWayCallService" binding="netTcpBinding" contract="OperationLib.IOneWayCallService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

Explanation:

>> to do

<!– ********************* Singleton Service ***************************** –>
      <service name="OperationLib.DuplexService" behaviorConfiguration="DuplexServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9015/DuplexService"/&gt;
            <add baseAddress="net.tcp://localhost:9016/DuplexService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9015/DuplexService&quot; binding="wsDualHttpBinding" contract="OperationLib.IDuplexService"/>
        <endpoint address="net.tcp://localhost:9016/DuplexService" binding="netTcpBinding" contract="OperationLib.IDuplexService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

Explanation:

Now to see all these things in action let’s create a service.
    

Writing code to host the service.

// Listing of Program.cs

using System;
using System.Text;
using System.ServiceModel;

namespace OperationLibHost
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost m_RequestReplyHost = null;
            ServiceHost m_OneWayCallHost = null;
            ServiceHost m_DuplexServiceHost = null;

            Console.WriteLine("\nHosting RequestReplyService at >> ");
            Console.WriteLine("    http://localhost:9011/RequestReplyService&quot;);
            Console.WriteLine("    net.tcp://localhost:9012/RequestReplyService");

            try
            {
                m_RequestReplyHost = new ServiceHost(typeof(OperationLib.RequestReplyService));
                m_RequestReplyHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting RequestReplyService [" + eX.Message + "]");
                m_RequestReplyHost = null;
            }

            if (m_RequestReplyHost != null) Console.WriteLine("RequestReplyService hosted successfully . . .");

            Console.WriteLine("\nHosting OneWayCallService at >> ");
            Console.WriteLine("   
http://localhost:9013/OneWayCallService");
            Console.WriteLine("    net.tcp://localhost:9014/OneWayCallService");
            try
            {
                m_OneWayCallHost = new ServiceHost(typeof(OperationLib.OneWayCallService));
                m_OneWayCallHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting OneWayCallService [" + eX.Message + "]");
                m_OneWayCallHost = null;
            }

            if (m_OneWayCallHost != null) Console.WriteLine("OneWayCallService hosted successfully . . .");

            Console.WriteLine("\nHosting DuplexService  at >> ");
            Console.WriteLine("   
http://localhost:9015/DuplexService");
            Console.WriteLine("    net.tcp://localhost:9016/DuplexService");

            try
            {
                m_DuplexServiceHost = new ServiceHost(typeof(OperationLib.DuplexService ));
                m_DuplexServiceHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting Service [" + eX.Message + "]");
                m_DuplexServiceHost = null;
            }
            if (m_DuplexServiceHost != null) Console.WriteLine("DuplexService hosted successfully . . .");

            Console.WriteLine("\n\nPress any key to close . . .");
            Console.ReadKey();

            m_RequestReplyHost.Close();
            m_OneWayCallHost.Close();
            m_DuplexServiceHost.Close();

            m_RequestReplyHost = null;
            m_OneWayCallHost = null;
            m_DuplexServiceHost = null;
        }
    }
}

Explanation:

Now to see all these things in action let’s create a service.

Build and Execute the host application.

Open a command prompt and execute the host. here is the output.

image

Now when the service is hosted and running, let’s now create a client, which is actually going to use this service.

Creating Client

Creating the base project

Take a console based application.

Generating proxies

while the host application is running, right click on the client application project, click on

Generate Proxy for RequestReplyService.

References –> Add Service Reference

in the address bar type the address of the mex endpoint address of RequestReplyService as shown below.

image

Generate Proxy for OneWayCallService.

References –> Add Service Reference

in the address bar type the address of the mex endpoint address of OneWayCallService as shown below.

image

Generate Proxy for DuplexService.

References –> Add Service Reference

in the address bar type the address of the mex endpoint address of DuplexService as shown below.

image

Adding Callback implementation to the client.

Add a new Class to the Client Project, name it DuplexServiceCallbackSink, below is the listing.

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

namespace OperationClient
{
    class DuplexServiceCallbackSink : DuplexServiceReference.IDuplexServiceCallback
    {
        public void OnValueAdded(double dblNum1, double dblNum2, double dblResult)
        {
            Console.WriteLine("\n\n>> Duplex Service <<CallBack>> called in Client >> Value 1 : {0:F2} Value 2 : {1:F2} Result : {2:F2}", dblNum1, dblNum2, dblResult);
        }
    }
}

Calling Services

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

namespace OperationClient
{
    class Program
    {
        static void Main(string[] args)
        {
            double dblVal1 = 100; double dblVal2 = 200;

            try
            {
                RequestReplyServiceReference.RequestReplyServiceClient obj1 = new RequestReplyServiceReference.RequestReplyServiceClient("WSHttpBinding_IRequestReplyService");
                RequestReplyServiceReference.RequestReplyServiceClient obj2 = new RequestReplyServiceReference.RequestReplyServiceClient("NetTcpBinding_IRequestReplyService");

                Console.WriteLine("Calling Request Reply Service");

                double dblResult1 = obj1.AddValue(dblVal1, dblVal2);
                Console.WriteLine("Using HTTP Binding >> Value 1: {0:F2} Value 2: {1:F2}  Returns : {2:F2}", dblVal1, dblVal2, dblResult1);

                dblVal1 = 100; dblVal2 = 200;
                double dblResult2 = obj2.AddValue(dblVal1, dblVal2);
                Console.WriteLine("Using TCP Binding >> Value 1: {0:F2} Value 2: {1:F2}  Return : {2:F2}", dblVal1, dblVal2, dblResult2);
            }
            catch (Exception eX)
            {
                Console.WriteLine("Error while calling Request Reply Service [ " + eX.Message + "]");
            }
           
            try
            {
                OneWayCallServiceReference.OneWayCallServiceClient obj3 = new OneWayCallServiceReference.OneWayCallServiceClient("WSHttpBinding_IOneWayCallService");
                OneWayCallServiceReference.OneWayCallServiceClient obj4 = new OneWayCallServiceReference.OneWayCallServiceClient("NetTcpBinding_IOneWayCallService");

                Console.WriteLine("Calling OneWayCall Service");

                obj3.AddValue(dblVal1);
                obj3.AddValue(dblVal2);
                double dblResult3 = obj3.GetResult();
                Console.WriteLine("Using HTTP Binding >> Value 1: {0:F2} Value 2: {1:F2}", dblVal1, dblVal2 );
                Console.WriteLine("Result : {0:F2}", dblResult3);

                obj4.AddValue(dblVal1);
                obj4.AddValue(dblVal2);
                double dblResult4 = obj4.GetResult();
                Console.WriteLine("Using TCP Binding >> Value 1: {0:F2} Value 2: {1:F2}", dblVal1, dblVal2);
                Console.WriteLine("Result : {0:F2}", dblResult4);
            }
            catch (Exception eX)
            {
                Console.WriteLine("Error while calling One way Service [ " + eX.Message + "]");
            }

            try
            {
                DuplexServiceCallbackSink callback = new DuplexServiceCallbackSink();
                InstanceContext insCntxt = new InstanceContext(callback);

                DuplexServiceReference.DuplexServiceClient obj5 = new DuplexServiceReference.DuplexServiceClient(insCntxt, "WSDualHttpBinding_IDuplexService");
                DuplexServiceReference.DuplexServiceClient obj6 = new DuplexServiceReference.DuplexServiceClient(insCntxt, "NetTcpBinding_IDuplexService");

                obj5.AddValue(dblVal1, dblVal2);
                obj6.AddValue(dblVal1, dblVal2);
            }
            catch (Exception eX)
            {
                Console.WriteLine("Error while calling Duplex Service [ " + eX.Message + "]");
            }

            Console.WriteLine("\n\nPress any key …");
            Console.ReadKey();
        }
    }
}

and here is the output.

image

October 4, 2013 Posted by | .NET, SOA, WCF | , , | Leave a comment