Praveen Katiyar' Blog

Learning along the way . . . .

Understanding Instance Management in WCF

instance management is the technique WCF uses to bind client requests to service instances, governing which service instance handles which client request, and when. WCF Supports 3 types of instance activation

  • Per Call : per call services allocate and destroy a new service instance for each  client request.
  • Per Session: session full services allocate a service instance for each client  connection.
  • Singleton: singleton services share the same service instance for all clients, across all connections and activations.

by and large the service instance mode is strictly a server side implementation detail, hat should not manifest itself on the client side in any way.

now let’s define a service, that demonstrates the instance management in real life.

Creating the Class Library

let’s create a service, create a new project, take a Class Library template, name it InstanceLib, 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 ISingleCallService to the project, a new file ISingleCallService.cs will be added to the project.
  • Add a new Class named SingleCallService, to the project. that will implement the ISingleCallService interface, a new file SingleCallService.cs will be added to the project.
  • Add a new Interface named ISessionService to the project, a new file ISessionService.cs will be added to the project.
  • Add a new Class named SessionService, to the project. that will implement the ISessionService interface, a new file SessionService.cs will be added to the project.
  • Add a new Interface named ISingletonService to the project, a new file ISingletonService.cs will be added to the project.
  • Add a new Class named SingletonService, to the project. that will implement the ISingletonService interface, a new file SingletonService.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 ISingleCallService.cs

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

namespace InstanceLib
{
    [ServiceContract]
    interface ISingleCallService
    {
        [OperationContract]
        double AddValue (double dblNum);
    }
}

// Listing of ISessionService.cs

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

namespace InstanceLib
{
    [ServiceContract]
    interface ISessionService
    {
        [OperationContract]
        double AddValue (double dblNum);
    }
}

// Listing of ISingletonService.cs

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

namespace InstanceLib
{
    [ServiceContract]
    interface ISingletonService
    {
        [OperationContract]
        double AddValue (double dblNum);
    }
}

Implementing Interfaces

Let’s implement each interface,as shown below.

// Listing of SingleCallService.cs

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

namespace InstanceLib
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]  
    public class SingleCallService : ISingleCallService
    {
        private double m_dblTotal = 0 ;

        public double AddValue(double dblVal)
        {
            m_dblTotal += dblVal;
            return m_dblTotal;
        }
    }
}

Important

You can notice ServiceBehavior attribute of the class, which has been defined as InstanceContextMode.PerCall, it specifies that a new InstanceContext object is created prior to and recycled subsequent to each calll. if you omit this attribute or do not specify, then InstanceContextMode.PerCall is assumed by default.

// Listing of SessionService.cs

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

namespace InstanceLib
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class SessionService : ISessionService
    {
        private double m_dblTotal = 0 ;

        public double AddValue(double dblVal)
        {
            m_dblTotal += dblVal;
            return m_dblTotal;
        }
    }
}

Important

You can notice ServiceBehavior attribute of the class, which has been defined as InstanceContextMode.PerSession, it specifies that InstanceContext object is created for each session.

 // Listing of SingletonService.cs

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

namespace InstanceLib
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class SingletonService : ISingletonService
    {
        private double m_dblTotal = 0 ;

        public double AddValue(double dblVal)
        {
            m_dblTotal += dblVal;
            return m_dblTotal;
        }
    }
}

Important

You can notice ServiceBehavior attribute of the class, which has been defined as InstanceContextMode.Singlel, it specifies that Only one InstanceContext object is used for all incoming calls and is not recycled to the calls. if the service object does not exist, one is created. 

if you notice the all 3 service implementation, you will notice the difference in ServiceBehavior class attribute of each class, apart from that, all interfaces has been implemented has the same implementation. they simply add a passed value to a member variable of the class.

Build the project and your Class Library is ready. 

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>

      <!–************************ Single Call Service ************************ –>
      <service name="InstanceLib.SingleCallService" behaviorConfiguration="SingleCallServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:9011/SingleCallService"/>
            <add baseAddress="net.tcp://localhost:9012/SingleCallService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9011/SingleCallService" binding="wsHttpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="net.tcp://localhost:9012/SingleCallService" binding="netTcpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

      <!—************************ Single Session Service ************************–>
     <service name="InstanceLib.SessionService" behaviorConfiguration="SessionServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:9013/SessionService"/>
            <add baseAddress="net.tcp://localhost:9014/SessionService"/>
          </baseAddresses>
        </host>

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

      <!—************************** Singleton Service **************************–>
     <service name="InstanceLib.SingletonService" behaviorConfiguration="SingletonServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:9015/SingletonService"/>
            <add baseAddress="net.tcp://localhost:9016/SingletonService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9015/SingletonService" binding="wsHttpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="net.tcp://localhost:9016/SingletonService" binding="netTcpBinding" contract="InstanceLib.ISingletonService"/>
        <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="SingleCallServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>

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

        <!–Singleton Service Behavior –>
        <behavior name="SingletonServiceBehavior">

          <serviceMetadata httpGetEnabled="true"/>
        </behavior>

      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>

Now let’s analyze the Configuration file.

Single Call service.

<!–******************* Single Call Service ************************** –>
      <service name="InstanceLib.SingleCallService" behaviorConfiguration="SingleCallServiceBehavior">
        <host>
         <baseAddresses>
            <add baseAddress="
http://localhost:9011/SingleCallService"/>
            <add baseAddress="net.tcp://localhost:9012/SingleCallService"/>
         </baseAddresses>
        </host>

        <endpoint address="http://localhost:9011/SingleCallService" binding="wsHttpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="net.tcp://localhost:9012/SingleCallService" binding="netTcpBinding" contract="InstanceLib.ISingleCallService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

Session service.

<!—************************* Single Session Service ************************* –>
      <service name="InstanceLib.SessionService" behaviorConfiguration="SessionServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:9013/SessionService"/>
            <add baseAddress="net.tcp://localhost:9014/SessionService"/>
          </baseAddresses>
        </host>

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

Singleton service.

<!—************************** Singleton Service **************************–>
     <service name="InstanceLib.SingletonService" behaviorConfiguration="SingletonServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:9015/SingletonService"/>
            <add baseAddress="net.tcp://localhost:9016/SingletonService"/>
          </baseAddresses>
        </host>

        <endpoint address="http://localhost:9015/SingletonService" binding="wsHttpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="net.tcp://localhost:9016/SingletonService" binding="netTcpBinding" contract="InstanceLib.ISingletonService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
      </service>

 

Writing code to host the service.

// Listing of Program.cs

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

namespace InstanceLibHost
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost m_SingleCallHost = null;
            ServiceHost m_SingleSessHost = null;
            ServiceHost m_SingletonHost = null;

            Console.WriteLine("\nHosting Single Call Service at >> " );
            Console.WriteLine("   
http://localhost:9011/SingleCallService");
            Console.WriteLine("    net.tcp://localhost:9012/SingleCallService");
       
            try
            {
                m_SingleCallHost = new ServiceHost(typeof(InstanceLib.SingleCallService));
                m_SingleCallHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting Single Call Service Service [" + eX.Message + "]");
                m_SingleCallHost = null;
            }

            if ( m_SingleCallHost!= null ) Console.WriteLine("Single Call Service hosted successfully . . .");

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

            if (m_SingleSessHost != null) Console.WriteLine("Single Session Service hosted successfully . . .");

            Console.WriteLine("\nHosting Singlton Service at >> " );
            Console.WriteLine("   
http://localhost:9015/SingletonService" );
            Console.WriteLine("    net.tcp://localhost:9016/SingletonService");
       
            try
            {
                m_SingletonHost = new ServiceHost(new InstanceLib.SingletonService());
                m_SingletonHost.Open();
            }
            catch (Exception eX)
            {
                Console.WriteLine("Failed while starting Service [" + eX.Message + "]");
                m_SingletonHost = null;
            }
            if (m_SingletonHost != null) Console.WriteLine("Singleton Service hosted successfully . . .");

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

            m_SingleCallHost.Close ();
            m_SingleSessHost.Close ();
            m_SingletonHost.Close () ;

            m_SingleCallHost = null;
            m_SingleSessHost = null;
            m_SingletonHost = null;
        }
    }
}

Build and Execute the Service.

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 SingleCallService.

References –> Add Service Reference

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

image

in the namespace type some good name, let’s say SingleCallServiceReference for instance.

hit OK, this will simply add a new file app.config to the project. and a new item in the Service Reference node of the project.

Generate Proxy for SessionService.

References –> Add Service Reference

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

image

in the namespace type some good name, let’s say SessionServiceReference for instance.

Generate Proxy for SingletonService.

References –> Add Service Reference

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

image

in the namespace type some good name, let’s say SingletonServiceReference for instance.

Now when you have added references of all 3 services, let’s write code for the client to use these services.

// Listing of Program.cs

using System;
using System.Text;

namespace InstanceClient
{
class Program
    {
        static void Main(string[] args)
        {
            SingleCallServiceReference.SingleCallServiceClient objSvc1 = new SingleCallServiceReference.SingleCallServiceClient("WSHttpBinding_ISingleCallService");
            SingleCallServiceReference.SingleCallServiceClient objSvc2 = new SingleCallServiceReference.SingleCallServiceClient("NetTcpBinding_ISingleCallService");

            Console.WriteLine("Client 1 Calling Single Call Service 3 times Using Http Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue1 = 10;
                double dblResult1 = objSvc1.AddValue(dblValue1);
                Console.WriteLine("Using HTTP Binding >> Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
            }

            Console.WriteLine("Client 2 Calling Single Call Service 3 times using TCP Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue2 = 10;
                double dblResult2 = objSvc2.AddValue(dblValue2);
                Console.WriteLine("Using TCP  Binding >> Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
            }

            SessionServiceReference.SessionServiceClient objSvc3 = new SessionServiceReference.SessionServiceClient("WSHttpBinding_ISessionService");
            SessionServiceReference.SessionServiceClient objSvc4 = new SessionServiceReference.SessionServiceClient("NetTcpBinding_ISessionService");

            Console.WriteLine("\n\nClient 1 Calling Single Session Service 3 times Using Http Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue1 = 10;
                double dblResult1 = objSvc3.AddValue(dblValue1);
                Console.WriteLine("Using HTTP Binding >> Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
            }

            Console.WriteLine("Client 2 Calling Single Session Service 3 times using TCP Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue2 = 10;
                double dblResult2 = objSvc4.AddValue(dblValue2);
                Console.WriteLine("Using TCP  Binding >> Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
            }

            SingletonServiceReference.SingletonServiceClient objSvc5 = new SingletonServiceReference.SingletonServiceClient("WSHttpBinding_ISingletonService");
            SingletonServiceReference.SingletonServiceClient objSvc6 = new SingletonServiceReference.SingletonServiceClient("NetTcpBinding_ISingletonService");

            Console.WriteLine("\n\nClient 1 Calling Singleton Service 3 times Using Http Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue1 = 10;
                double dblResult1 = objSvc5.AddValue(dblValue1);
                Console.WriteLine("Using HTTP Binding >> Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
            }

            Console.WriteLine("Client 2 Calling Singleton Service 3 times using TCP Binding");
            for (int nI = 0; nI < 3; nI++)
            {
                double dblValue2 = 10;
                double dblResult2 = objSvc6.AddValue(dblValue2);
                Console.WriteLine("Using TCP  Binding >> Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
            }

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

 

Open command prompt and execute the client to see the output.

image

Open one more command prompt, and execute another instance of client.

image

as you can see from the output, all the instance mode in action.

Advertisements

September 29, 2013 Posted by | .NET, CodeProject, SOA, WCF | , , , | Leave a comment

Creating and Consuming a WCF Service without configuration files.

Introduction

This article explains how to create a simple WCF Service Host it on a specified port according to specified binding. all this you can do on the fly.

Background

Normally when we develop WCF Services, we are in habit of using Configuration files. (web.config/app.config depending on the environment). it is indeed very good idea to use configuration files. all this seems very automatic. And using configuration files is default way of doing things.

How this project is organized

In this article i have used 3 projects.

  • WCF Service (WCFMathLib.dll):  Actual Service logic, which defines a Service Contract Interface, OperationContract, and implements them, and exposes few functions to the world to use them.
  • Host Application (ConWCFMathHost.exe): Defines the logic to host the said service, according to the parameters supplied at the command line.
  • Client Application (ConWCFMathClient.exe): Client Application which will use this service.

First Part : WCF Service (WCFMathLib.dll):

The actual Service which implements the business logic. it defines an ServiceContract and few Operations available through Service. as shown below.  let;s call it IMathInterface.cs

to create this project you can simply take a Class Library Project, from while choosing from project wizard option. let’s Name it "WCFMathLib", it already contains a File Class1.cs, rename that file as MathService.cs, add one more file (IMathService.cs) to define the interface, although you can define interface this file also. below is the listing of both files.

 

Defining a Service Contract

// Listing of IMathInterface.cs
[ServiceContract]
public interface IMathService
{
    [OperationContract]
    double AddNumber(double dblX, double dblY);
   
    [OperationContract]
    double SubtractNumber(double dblX, double dblY);
   
    [OperationContract]
    double MultiplyNumber(double dblX, double dblY);
   
    [OperationContract]
    double DivideNumber(double dblX, double dblY);
}

Implementation  of Service Contract

//    Listing MathInterface.cs
public class MathService : IMathService
{
    public double AddNumber(double dblX, double dblY)
    {
        return (dblX + dblY);
    }

    public double SubtractNumber(double dblX, double dblY)
    {
        return (dblX – dblY);
    }

    public double MultiplyNumber(double dblX, double dblY)
    {
        return (dblX * dblY);
    }

    public double DivideNumber(double dblX, double dblY)
    {
        return ((dblY == 0 ) ? 0 : dblX / dblY);
    }
}

ServiceContract attribute

Service Contract. Describes which related operations can be tied together as a single functional unit that the client can perform on the service.

OperationContract attribute

An Operation contract specifyies that the said operation is exposed by the service, service defines the parameters and return type of an operation.

as one can see, there is nothing special here, just an Service Contract definition and its implementation.

Second Part : WCF Service (ConWCFMathHost.exe):

Host application has been developed as console based application, which host our Service (WCFMathLib.MathService), according to the supplied parameters, parameters are supplied in the following form.  it accepts two parameters.

ConWCFMathHost.exe TCP/HTTP portAdr <return>

Parameter 1 : Binding accepted values are HTTP and TCP

Parameter 2 : Port Number, and integer value specifyin the port value.

Hosting Service using HTTP Bidnding

private static void StartHTTPService( int nPort)
{
    string strAdr = "
http://localhost:" + nPort.ToString() + "/MathService";
    try
    {
        Uri adrbase = new Uri(strAdr);
        m_svcHost = new ServiceHost(typeof(MathService), adrbase);

        ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
        m_svcHost.Description.Behaviors.Add(mBehave);
        m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

        BasicHttpBinding httpb = new BasicHttpBinding();
        m_svcHost.AddServiceEndpoint(typeof(IMathService), httpb, strAdr);
        m_svcHost.Open();
        Console.WriteLine("\n\nService is Running as >> " + strAdr );
    }
    catch (Exception eX)
    {
        m_svcHost = null;
        Console.WriteLine("Service can not be started as >> [" + strAdr + "] \n\nError Message [" + eX.Message + "]");
    }
}

Hosting Service using TCP Bidnding

private static void StartTCPService(int nPort)
{
    string strAdr = "net.tcp://localhost:" + nPort.ToString() + "/MathService";
    try
    {
        Uri adrbase = new Uri(strAdr);
        m_svcHost = new ServiceHost(typeof(MathService), adrbase);
        NetTcpBinding tcpb = new NetTcpBinding();

                ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
        m_svcHost.Description.Behaviors.Add(mBehave);
        m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange),   MetadataExchangeBindings.CreateMexTcpBinding(), "mex");

        m_svcHost.AddServiceEndpoint(typeof(IMathService), tcpb, strAdr);
        m_svcHost.Open();
        Console.WriteLine("\n\nService is Running as >> " + strAdr );
    }
    catch (Exception eX)
    {
        m_svcHost = null;
        Console.WriteLine("Service can not be started as >> [" + strAdr + "] \n\nError Message [" + eX.Message + "]");
    }
}

Code Description

Create Desired binding (TCP/HTTP)

ServiceMetadataBehavior, Controls the publication of service metadata and associated information. although we can omit the part shown in bold, as far as this project is concerned, as we are going to create everything by hand, but it is a good Idea, to always add a IMetadataExchange endpoint to the service. as it  exposes methods used to return the metadata about  the service. it is usefull when we are generating the proxy class and config files from the service using SVCUtil.exe utility.

Host Application Complete Code

// Program.cs

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

namespace ConWCFMathHost
{
    class Program
    {
        static ServiceHost m_svcHost = null;
        static void Main(string[] args)
        {
            if (args.Count() != 2)
            {
                Console.WriteLine("Insufficient arguments supplied");
                Console.WriteLine("Service Host must be started as <Executable Name> <TCP/HTTP> <Port#>");
                Console.WriteLine("Argument 1 >> Specifying the Binding, which binding will be used to Host (Supported values are either HTTP or TCP) without quotes");
                Console.WriteLine("Argument 2 >> Port Number a numeric value, the port you want to use");
                Console.WriteLine("\nExamples");
                Console.WriteLine("<Executable Name> TCP 9001");
                Console.WriteLine("<Executable Name> TCP 8001");
                Console.WriteLine("<Executable Name> HTTP 8001");
                Console.WriteLine("<Executable Name> HTTP 9001");
                return;
            }

            string strBinding = args[0].ToUpper();
            bool bSuccess = ((strBinding == "TCP") || (strBinding == "HTTP"));
            if (bSuccess == false)
            {
                Console.WriteLine("\nBinding argument is invalid, should be either TCP or HTTP)");
                return;
            }
           
            int nPort = 0;
            bSuccess = int.TryParse(args[1], out nPort);
            if (bSuccess == false)
            {
                Console.WriteLine("\nPort number must be a numeric value");
                return;
            }

            bool bindingTCP = (strBinding == "TCP");
            if (bindingTCP) StartTCPService(nPort);  else StartHTTPService(nPort);
            if (m_svcHost != null)
            {
                Console.WriteLine("\nPress any key to close the Service");
                Console.ReadKey();
                StopService();
            }
        }

        private static void StartTCPService(int nPort)
        {
            string strAdr = "net.tcp://localhost:" + nPort.ToString() + "/MathService";
            try
            {
                Uri adrbase = new Uri(strAdr);
                m_svcHost = new ServiceHost(typeof(MathService), adrbase);
               
                ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
                m_svcHost.Description.Behaviors.Add(mBehave);
                m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");

                NetTcpBinding tcpb = new NetTcpBinding();
                m_svcHost.AddServiceEndpoint(typeof(IMathService), tcpb, strAdr);
                m_svcHost.Open();
                Console.WriteLine("\n\nService is Running as >> " + strAdr );
            }
            catch (Exception eX)
            {
                m_svcHost = null;
                Console.WriteLine("Service can not be started as >> [" + strAdr + "] \n\nError Message [" + eX.Message + "]");
            }
        }

        private static void StartHTTPService( int nPort)
        {
            string strAdr = "
http://localhost:" + nPort.ToString() + "/MathService";
            try
            {
                Uri adrbase = new Uri(strAdr);
                m_svcHost = new ServiceHost(typeof(MathService), adrbase);
               
                ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
                m_svcHost.Description.Behaviors.Add(mBehave);
                m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

                BasicHttpBinding httpb = new BasicHttpBinding();
                m_svcHost.AddServiceEndpoint(typeof(IMathService), httpb, strAdr);
                m_svcHost.Open();
                Console.WriteLine("\n\nService is Running as >> " + strAdr );
            }
            catch (Exception eX)
            {
                m_svcHost = null;
                Console.WriteLine("Service can not be started as >> [" + strAdr + "] \n\nError Message [" + eX.Message + "]");
            }
        }

        private static void StopService()
        {
            if (m_svcHost != null)
            {
                m_svcHost.Close();
                m_svcHost = null;
            }
        }
    }
}

Third Part : Client (ConWCFMathClient.exe):

Client application has been also developed as console based application, parameters through command line in the following form.  you need to supply 6 parameters at the command line.

ConWCFMathClient <Host Machine> <TCP/HTTP> <Port#> <ADD/SUB/MUL/DIV> Num1 Num2

Parameter 1 : name/IP address of the machine, where service has been hosted.

Parameter 2 : Binding of the hosted service, accepted values are HTTP and TCP

Parameter 3 : Port Number, and integer value specifyin the port value.

Parameter 4 : Operation Code (accepted values are ADD, SUB, MUL, DIV)

Parameter 5 : Operand 1, operand value 1 for the operation.

Parameter 6 : Operand 2, operand value 2 for the operation.

Importing the Interface  definition

You can define the interface or just import the IMathService.cs file from the Service. this simply defines the interface, so that there is no error while compiling the client project

// Listing of IMathInterface.cs
namespace ConWCFMathClient
{
    [ServiceContract]
    public interface IMathService
    {
        [OperationContract]
        double AddNumber(double dblX, double dblY);
       
        [OperationContract]
        double SubtractNumber(double dblX, double dblY);
       
        [OperationContract]
        double MultiplyNumber(double dblX, double dblY);
       
        [OperationContract]
        double DivideNumber(double dblX, double dblY);
    }
}

  

Calling Methods of the Service

a function has been created to call  methods of the Service, passing all the parameter to the method, after validating them. here is the mehod.

private static void Evaluate(string strServer, string strBinding, int nPort, string strOper, double dblVal1, double dblVal2)
{
    ChannelFactory<IMathService> channelFactory = null;
    EndpointAddress ep = null;

    string strEPAdr = "http://" + strServer + ":" + nPort.ToString() + "/MathService";
    try
    {
        switch (strBinding)
        {
            case "TCP":
                NetTcpBinding tcpb = new NetTcpBinding();
                channelFactory = new ChannelFactory<IMathService>(tcpb);

                // End Point Address
                strEPAdr = "net.tcp://" + strServer + ":" + nPort.ToString() + "/MathService";
                break;

            case "HTTP":
                BasicHttpBinding httpb = new BasicHttpBinding();
                channelFactory = new ChannelFactory<IMathService>(httpb);
               
                // End Point Address
                strEPAdr = "
http://" + strServer + ":" + nPort.ToString() + "/MathService";
                break;
        }

        // Create End Point
        ep = new EndpointAddress(strEPAdr);

        // Create Channel
        IMathService mathSvcObj = channelFactory.CreateChannel(ep);
        double dblResult = 0;

            // Call Methods
        switch (strOper)
        {
            case "ADD": dblResult = mathSvcObj.AddNumber(dblVal1, dblVal2); break;
            case "SUB": dblResult = mathSvcObj.SubtractNumber(dblVal1, dblVal2); break;
            case "MUL": dblResult = mathSvcObj.MultiplyNumber(dblVal1, dblVal2); break;
            case "DIV": dblResult = mathSvcObj.DivideNumber(dblVal1, dblVal2); break;
        }

        //  Display Results.
        Console.WriteLine("Operation {0} ", strOper );
        Console.WriteLine("Operand 1 {0} ", dblVal1.ToString ( "F2"));
        Console.WriteLine("Operand 2 {0} ", dblVal2.ToString("F2"));
        Console.WriteLine("Result {0} ", dblResult.ToString("F2"));
        channelFactory.Close();
    }
    catch (Exception eX)
    {
        // Something unexpected happended ..
        Console.WriteLine("Error while performing operation [" + eX.Message + "] \n\n Inner Exception [" + eX.InnerException + "]");
    }
}

Code Description

Before you can call any method, you need to do two things.

Create a channel factory object, using the specified binding using .

for HTTP Bindng

BasicHttpBinding httpb = new BasicHttpBinding();
channelFactory = new ChannelFactory<IMathService>(httpb);

for TCP Bindng

NetTcpBinding tcpb = new NetTcpBinding();
channelFactory = new ChannelFactory<IMathService>(tcpb);
 

EndPoint address for HTTP binding

strEPAdr = "http://" + strServer + ":" + nPort.ToString() + "/MathService";

EndPoint address   TCP binding

strEPadr = strEPAdr = "net.tcp://" + strServer + ":" + nPort.ToString() + "/MathService";

Create a chaneel through specified end point aadress

// Create End Point ep = new EndpointAddress(strEPAdr); // Create ChannelIMathService mathSvcObj = channelFactory.CreateChannel(ep);                

Invoke methods through channel and display output.

double dblResult = 0;

// Call Methods
switch (strOper)
{
    case "ADD": dblResult = mathSvcObj.AddNumber(dblVal1, dblVal2); break;
    case "SUB": dblResult = mathSvcObj.SubtractNumber(dblVal1, dblVal2); break;
    case "MUL": dblResult = mathSvcObj.MultiplyNumber(dblVal1, dblVal2); break;
    case "DIV": dblResult = mathSvcObj.DivideNumber(dblVal1, dblVal2); break;
}

//  Display Results.
Console.WriteLine("Operation {0} ", strOper );
Console.WriteLine("Operand 1 {0} ", dblVal1.ToString ( "F2"));
Console.WriteLine("Operand 2 {0} ", dblVal2.ToString("F2"));
Console.WriteLine("Result {0} ", dblResult.ToString("F2"));

// Close channel
channelFactory.Close();
 

Point of Interest

  • No configuration file,
  • there is no proxy generation using SvcUtil

Client Application Complete Code

// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace ConWCFMathClient
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Count() !=6 )
            {
                Console.WriteLine("Insufficient arguments supplied");
                Console.WriteLine("Service Host must be started as ConWCFMathClient <Host Machine> <TCP/HTTP> <Port#> <ADD/SUB/MUL/DIV> Num1 Num2");
                Console.WriteLine("Argument 1 >> IP address or the Machine name, where Service is hosted/running (localhost if running onm the same machine)");
                Console.WriteLine("Argument 2 >> Specifying the Binding type, which binding is used to Host the service. (Supported values are either HTTP or TCP),  without quotes");
                Console.WriteLine("Argument 3 >> Port Number a numeric value");
                Console.WriteLine("Argument 4 >> Operation permissible values are ADD/SUB/MUL/DIV without quotes");
                Console.WriteLine("Argument 5 >> Operand 1 for the operation ");
                Console.WriteLine("Argument 6 >> Operand 2 for the operation ");
                Console.WriteLine("\nExamples");
                Console.WriteLine("<Executable Name> 192.168.1.1 TCP 9001 ADD 1000 2000");
                Console.WriteLine("<Executable Name> 192.168.1.1 TCP 8001 SUB 500 1000");
                Console.WriteLine("<Executable Name> 192.168.1.1 HTTP 8001 MUL 500 1000");
                Console.WriteLine("<Executable Name> 192.168.1.1 HTTP 9001 DIV 3000 1000");
                Console.WriteLine("<Executable Name> localhost TCP 9001 ADD 4000.0  500.0");
                Console.WriteLine("<Executable Name> localhost TCP 8001 SUB 600.0 700.0");
                Console.WriteLine("<Executable Name> localhost HTTP 8001 MUL 1200.0 300.0");
                Console.WriteLine("<Executable Name> localhost HTTP 9001 DIV 2000.0 90.0");
                return;
            }

            string strAdr = args[0];
            string strBinding = args[1].ToUpper();
            bool bSuccess = ((strBinding == "TCP") || (strBinding == "HTTP"));
            if (bSuccess == false)
            {
                Console.WriteLine("\nBinding argument is invalid, should be either TCP or HTTP)");
                return;
            }

            int nPort = 0;
            bSuccess = int.TryParse(args[2], out nPort);
            if (bSuccess == false)
            {
                Console.WriteLine("\nPort number must be a numeric value");
                return;
            }

            string strOper = args[3].ToUpper();
            bSuccess = ((strOper == "ADD") || (strOper == "SUB") || (strOper == "MUL") || (strOper == "DIV"));
            if (bSuccess == false)
            {
                Console.WriteLine("\nOperation argument is invalid, should be ADD/SUB/MUL/DIV)");
                return;
            }

            //  Determine operand 1
            double dblNum1 = 0;
            bSuccess = double.TryParse(args[4], out dblNum1);
            if (bSuccess == false)
            {
                Console.WriteLine("\nOperand 1 must be a numeric value");
                return;
            }

            //  Determine operand 2
            double dblNum2 = 0;
            bSuccess = double.TryParse(args[5], out dblNum2);
            if (bSuccess == false)
            {
                Console.WriteLine("\nnOperand 2 must be a numeric value");
                return;
            }

            Evaluate(strAdr, strBinding, nPort, strOper, dblNum1, dblNum2);
        }

        private static void Evaluate(string strServer, string strBinding, int nPort, string strOper, double dblVal1, double dblVal2)
        {
            ChannelFactory<IMathService> channelFactory = null;
            EndpointAddress ep = null;

            string strEPAdr = "http://" + strServer + ":" + nPort.ToString() + "/MathService";
            try
            {
                switch (strBinding)
                {
                    case "TCP":
                    NetTcpBinding tcpb = new NetTcpBinding();
                    channelFactory = new ChannelFactory<IMathService>(tcpb);

                    // End Point Address
                    strEPAdr = "net.tcp://" + strServer + ":" + nPort.ToString() + "/MathService";
                    break;

                                        case "HTTP":
                    BasicHttpBinding httpb = new BasicHttpBinding();
                    channelFactory = new ChannelFactory<IMathService>(httpb);

                    // End Point Address
                    strEPAdr = "
http://" + strServer + ":" + nPort.ToString() + "/MathService";
                    break;
                }

                // Create End Point
                ep = new EndpointAddress(strEPAdr);

                // Create Channel
                IMathService mathSvcObj = channelFactory.CreateChannel(ep);
                double dblResult = 0;

                // Call Methods
                switch (strOper)
                {
                    case "ADD": dblResult = mathSvcObj.AddNumber(dblVal1, dblVal2); break;
                    case "SUB": dblResult = mathSvcObj.SubtractNumber(dblVal1, dblVal2); break;
                    case "MUL": dblResult = mathSvcObj.MultiplyNumber(dblVal1, dblVal2); break;
                    case "DIV": dblResult = mathSvcObj.DivideNumber(dblVal1, dblVal2); break;
                }
           
                //  Display Results.
                Console.WriteLine("Operation {0} ", strOper );
                Console.WriteLine("Operand 1 {0} ", dblVal1.ToString ( "F2"));
                Console.WriteLine("Operand 2 {0} ", dblVal2.ToString("F2"));
                Console.WriteLine("Result {0} ", dblResult.ToString("F2"));

                // Close channel
                channelFactory.Close();
            }
            catch (Exception eX)
            {
                // Something happended ..
                Console.WriteLine("Error while performing operation [" + eX.Message + "] \n\n Inner Exception [" + eX.InnerException + "]");
            }
        }
    }
}

//    Listing of IMathInterface.cs

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

namespace ConWCFMathClient
{
    [ServiceContract]
    public interface IMathService
    {
        [OperationContract]
        double AddNumber(double dblX, double dblY);
        [OperationContract]
        double SubtractNumber(double dblX, double dblY);
        [OperationContract]
        double MultiplyNumber(double dblX, double dblY);
        [OperationContract]
        double DivideNumber(double dblX, double dblY);
    }
}

Output

Running the Host Application as a TCP Service

image

Running the Client Application

image

Running the Host Application as a HTTP Service

Notewhile running the Service in HTTP Mode, you need to open command prompt in administrator mode.

image

Running the Client Application

image

September 12, 2013 Posted by | .NET, SOA, WCF | , , | Leave a comment

Creating a Self Hosted WCF Service

In this post I am going to explain how to create a simple WCF Service, with Self Hosting and consume it, there will be 4 parts of the project.

  1. A Class Library (MyMathServiceLib.dll): which will implement our business logic.
  2. Service Host Application (MathServiceHost.exe): Application which will host this class library as a WCF Service.
  3. A Windows Client Application (MyMathServiceClient.exe): Client Application which will use this service.
  4. A Web Client, that will use this Service.

Note:

part 1 and 2 can be merged into one, if one like so, but, for the sake of portability, keep them as separate modules. let’s start with creating the Class Library.

Part 1: Creating the Class Library

Start the Visual Studio, and click File->New->Project . Select the project template ‘Class Library" click OK.

image

Now let’s analyse the project created by wizard for us, and do little house keeping, before we write any code.

  • Class1.cs (The default class, created by wizard).

Assumption

We are going to create a Service as per following assumptions.

  • Interface will named as IMyMathService (IMyMathService.cs)
  • Service will be implemented as MyMathService (MyMathService.cs)

Little house keeping. (just to keep things organized)

  • Delete Class1.cs the project workspace.
  • Add an Interface (IMyMathService) IMyMathService.cs to the project.
  • Add an Class (MyMathService) MyMathService.cs to the project.
  • Add reference of System.ServiceModel to the  project.

Now, let’s define the Interface and its implementation of our old familiar class Library.

//  Listing of IMyMathService.cs,

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

namespace MyMathServiceLib
{
    [ServiceContract]
    public interface IMyMathService
    {
        [OperationContract]
        double Add(double dblNum1, double dblNum2);

        [OperationContract]
        double Subtract(double dblNum1, double dblNum2);

        [OperationContract]
        double Multiply(double dblNum1, double dblNum2);

        [OperationContract]
        double Divide(double dblNum1, double dblNum2);
    }
}

//  Listing of MyMathService.cs,

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

namespace MyMathServiceLib
{
    public class MyMathService : IMyMathService
    {
        public double Add(double dblNum1, double dblNum2)
        {
            return (dblNum1 + dblNum2);
        }

        public double Subtract(double dblNum1, double dblNum2)
        {
            return (dblNum1 – dblNum2);
        }

        public double Multiply(double dblNum1, double dblNum2)
        {
            return (dblNum1 * dblNum2);
        }

        public double Divide(double dblNum1, double dblNum2)
        {
            return ((dblNum2 == 0) ? 0 : (dblNum1 / dblNum2));
        }
    }
}

Part 2: Creating the Host Application

Our class library is ready, let’s write an Host application, which will expose this facility to the world as a WCF Service. lets’ Create a Console based application, for the sake of simplicity, name it MyMathServiceHost, as shown below.

image

a new Project MyMathServiceHost will be added to the workspace.

Assumption

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

  • Service will implement HTTP endpoint at Port 9001
  • Corresponding mex End Point  (IMetadatExchange) for the HTTP end point.  
  • Service will implement TCP endpoint at Port 9002
  • Corresponding mex End Point  (IMetadatExchange) for the TCP end point.  

Adding reference of the class library to the Host project

  • Add reference of the class library to the console project,as shown below.

image

  • Add reference of System.ServiceModel to the  project.

Creating the Service Configuration

Add a Application configuration file (App.config) to the Host Project. define the End Points and bindings according to the assumptions made at the start of the project.

  • will expose an end point with HTTP Binding at 9001
  • will expose an end point with TCP Binding at 9002
  • will expose, required mex (one for each binding) end points

below is he listing of the app.config file.

<?xml versio="1.0"?>
<configuration>

    <system.serviceModel>
      <services>
        <service name="MyMathServiceLib.MyMathService" behaviorConfiguration="myMathServiceBehave">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:9001/MyMathService"/>
              <add baseAddress="net.tcp://localhost:9002/MyMathService"/>
            </baseAddresses>
          </host>
          <endpoint address="http://localhost:9001/MyMathService" binding="basicHttpBinding" contract="MyMathServiceLib.IMyMathService"/>
          <endpoint address="net.tcp://localhost:9002/MyMathService" binding="netTcpBinding" contract="MyMathServiceLib.IMyMathService"/>
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
        </service>
      </services>
      <behaviors>
        <serviceBehaviors>
          <behavior name="myMathServiceBehave">
            <serviceMetadata httpGetEnabled="true"/>
          </behavior>
        </serviceBehaviors>
      </behaviors>
    </system.serviceModel>
</configuration>

Description
  • Application configuration files defines 2 endpoints, one for TCP and one for HTTP. and 1 mex end point for each.
  • Service behavior define, <serviceMetadata httpGetEnabled="true"/> that meta data should be available through a HTTP get request.

Write code to Host the Service.

Write the code to Host the Service in the Main function of the Open Program.cs, and let’s write the code.

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

namespace CalcServiceHost
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost svcHost = null;
            try
            {
                svcHost = new ServiceHost(typeof(MyMathServiceLib.MyMathService));
                svcHost.Open();
                Console.WriteLine("\n\nService is Running  at following address" );
                Console.WriteLine("\nhttp://localhost:9001/MyMathService");
                Console.WriteLine("\nnet.tcp://localhost:9002/MyMathService");
            }
            catch (Exception eX)
            {
                svcHost = null;
                Console.WriteLine("Service can not be started \n\nError Message [" + eX.Message + "]");
            }

            if (svcHost != null)
            {
                Console.WriteLine("\nPress any key to close the Service");
                Console.ReadKey();
                svcHost.Close();
                svcHost = null;
            }
        }
    }
}

explanation

as you can see from the above code,

  • Class Library is simply hosted inside a ServiceHost object, as all the End Points are defined in App.config file.

Part 3: Creating the Windows Client

Now when our service is self hosted and running, let us write a client Application, which can use this Service. lets’ Create a Console based application, for the sake of simplicity, name it MyMathServiceClient, as shown below.

image

newly created project will be added to the work space.

Generating proxy and config file.

Before we write the Client application, we need to generate the proxy for our Service, open a command prompt in Administrator mode. and execute the Host Application.

image

Open another command prompt, switch to the folder, where client project has been created, and generate the proxy and configuration file using the SVCUtil.exe utility. as shown below.

image

add both these files to the client project.

Calling the Service

Now write the code to use the proxy and call the service, here is the listing of the Program.cs.

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

namespace MyMathClient
{
    class Program
    {
        static void Main(string[] args)
        {
            double dblX = 2000.0;
            double dblY = 100.0;
            double dblResult = 0;

            try
            {
                Console.WriteLine("Using TCP Binding", dblX, dblY, dblResult);

                MyMathServiceClient mathClient1 = new MyMathServiceClient("NetTcpBinding_IMyMathService");

                dblResult = mathClient1.Add(dblX, dblY);
                Console.WriteLine("Calling Add >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                dblResult = mathClient1.Subtract(dblX, dblY);
                Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                dblResult = mathClient1.Multiply(dblX, dblY);
                Console.WriteLine("Calling Mul >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                dblResult = mathClient1.Divide(dblX, dblY);
                Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                Console.WriteLine("Using Basic HTTP Binding", dblX, dblY, dblResult);

                MyMathServiceClient mathClient2 = new MyMathServiceClient("BasicHttpBinding_IMyMathService");

                dblResult = mathClient2.Add(dblX, dblY);
                Console.WriteLine("Calling Add >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                dblResult = mathClient2.Subtract(dblX, dblY);
                Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                dblResult = mathClient2.Multiply(dblX, dblY);
                Console.WriteLine("Calling Mul >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

                dblResult = mathClient2.Divide(dblX, dblY);
                Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);
            }
            catch (Exception eX)
            {
                Console.WriteLine("There was an error while calling Service [" + eX.Message + "]");
            }
        }
    }
}

and here is the output.

image

Part 4: Creating a Web Client

Create a New Web Site, using the File –> New Web Site as shown below. name it MyMathWebClient.

image

 

Click OK,

Now we need to add a reference to our service to this web site, right click on the newly created web site project, and click on Add Service Reference. a dialog box will pop up.

  • Enter any (TCP/HTTP) endpoint address in the address box.
  • Name the namespace, where Service Proxy will be added to the project.

image

click OK, some changes will be made to your web.config file, and App_WebReferences folder will be added, under which a Service reference "MathServiceReference" will be added.

  • a Service reference named MyMathServiceReference will be added in Service References node of the client project.
  • some changes will be made to the web.config file,

let’s analyse the changes made to web.config. open the web.config, you will find the changes at the end of the file, see the <system.ServiceModel> section, as shown below.

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IMyMathService"/>
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="NetTcpBinding_IMyMathService"/>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="
http://localhost:9001/MyMathService&quot; binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMyMathService" contract="MathServiceReference.IMyMathService" name="BasicHttpBinding_IMyMathService"/>
      <endpoint address="net.tcp://localhost:9002/MyMathService" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IMyMathService" contract="MathServiceReference.IMyMathService" name="NetTcpBinding_IMyMathService">
        <identity>

          <!—this value will be different on your machine –!>
          <userPrincipalName value="PRAVEEN-WIN7\BriskTech"/>
        </identity>
      </endpoint>
    </client>
</system.serviceModel>

Open the Main page of the site (Default.aspx page), double click, that will create the Page_Load  handler for the Page, lets call our service in the page load handler.

protected void Page_Load(object sender, EventArgs e)
    {
        double dblX = 10000.0 ;
        double dblY = 2000.0 ;
        Response.Write ( "<p>Value 1 : " + dblX.ToString ( "F2"));
        Response.Write ( "<br>Value 2 : " + dblY.ToString ( "F2"));

        try
        {
            Response.Write("<p>Using TCP Binding");

            MathServiceReference.MyMathServiceClient mathProxy1 = new MathServiceReference.MyMathServiceClient("NetTcpBinding_IMyMathService");

            double dblResult = mathProxy1.Add(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            dblResult = mathProxy1.Subtract(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            dblResult = mathProxy1.Multiply(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            dblResult = mathProxy1.Divide(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            Response.Write("<p>Using Basic HTTP Binding");

            MathServiceReference.MyMathServiceClient mathProxy2 = new MathServiceReference.MyMathServiceClient("BasicHttpBinding_IMyMathService");

            dblResult = mathProxy2.Add(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            dblResult = mathProxy2.Subtract(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            dblResult = mathProxy2.Multiply(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

            dblResult = mathProxy2.Divide(dblX, dblY);
            Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));
        }
        catch (Exception eX)
        {
            Response.Write("There was an error while calling Service <p> <b>[" + eX.Message + "] </b>");
        }
    }

Build and run the web site, following output will be displayed.

image

that’s all folks.

September 9, 2013 Posted by | CodeProject, SOA, WCF | , , | Leave a comment

Creating Simple WCF Service with IIS Hosting

In this post I am going to explain how to create a simple WCF Service, with IIS Hosting and consume it, there will be two parts of the project.

  • A WCF Service (MyMathService.svc): will be hosted by IIS.
  • Client Application (MyMathClient.exe): Client Application which will use this service.

let’s start with creating the WCF Service.

Creating the WCF Service

Start the Visual Studio 2010 in administrator Mode (Run as Administrator), and click File->New->Web Site. Select the project template ‘WCF Service’ and Location as http. This will directly host the service in IIS and click OK. select the template “WCF Service”. 

image

Now let’s analyse the project created by wizard for us, and do little house keeping, before we write any code.

  • IService.cs (the interface definition of the service)
  • Service.cs (the implementation of the service).
  • web.config (Service configuration file).
  • Service.svc

Assumption

We are going to create a Service as per following assumptions.

  • Service will be named as "MyMathService" (MyMathService.svc)
  • Interface will named as IMyMathService (IMyMathService.cs)
  • Service will be implemented as MyMathService (MyMathService.cs)
  • Service will implement Http endpoint at Port 8001.
  • Service will also expose IMetadataExchange endpoint.  IMetadataExchange interface Exposes methods used to return metadata about a service.

Little house keeping. (just to keep things organized)

  • Rename IService.cs as IMyMathService.cs.
  • Rename Service.cs as MyMathService.cs.
  • Rename Service.svc as MyMathService.svc, and change its content as

Previous Content

<%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>

New Content

<%@ ServiceHost Language="C#" Debug="true" Service="MyMathService" CodeBehind="~/App_Code/MyMathService.cs" %>

Defining Configuration File

Changing web.config file.

Below is the listing of the configuration file, generated by visual studio wizard, as we know, that Services are defined in <System.servicemodel> section. Below is the listing of the configuration file, generated by visual studio wizard.  let’s define a service and endpoint, see the highlighted part.

<?xml version="1.0"?>
<configuration>

                 <configSections>
        . . . . . . . . .
         . . . . . . . . .
      </configSections>

    <system.web>
     . . . . . . . . .
     . . . . . . . . .
    </system.web>

  <system.serviceModel> 
<services>
     <service name="MyMathService" behaviorConfiguration="svcBehavior">  
        
<endpoint address=http://localhost:8001/MyMathService/MyMathService.svc" binding="wsHttpBinding" contract="IMyMathService">

          <identity> <dns value="localhost"/> </identity>
</endpoint>

      <endpoint address ="MEX" binding ="mexHttpBinding" contract="IMetadataExchange" /> 
   </service> 
</services>

   <behaviors>
      <serviceBehaviors>
        <behavior  name="svcBehavior">
          <!– 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>
   
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel> 

<system.codedom>
         . . . . . . . . .
         . . . . . . . . .
      </system.codedom>

   <system.webServer>
         . . . . . . . . .
         . . . . . . . . .
   </system.webServer>    

   <runtime>
         . . . . . . . . .
         . . . . . . . . .
   </runtime>

 
</configuration>

Explanation

See the highlighted text, as you can see service defines two endpoints, one is first end point defines an address(http://localhost:8001/MyMathService), binding(HTTP) and contract (IMyMathService), the other is MEX endpoint, MEX endpoint are defined to import Metadata (to be used by client applications) from a Service using utility SVCUtil.exe

<endpoint address ="http://localhost:8001/MyMathService&quot; binding ="basicHttpBinding" contract="IMyMathService" />

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

In the serviceBehaviors, a behavior named "svcBehavior" defines following attributes about the service.

<serviceMetadata httpGetEnabled="true"/>

metadata information about the service can disclosed through a get request (if this is false, SVCUtil.exe would not be able to obtain metadata information about the service).

<serviceDebug includeExceptionDetailsInFaults="true"/>

can be set true, to receive exception details in faults for debugging purposes, should be set to false, before deployment, to avoid disclosing exception information.

Defining Service Interface (IMyMathService.cs)

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

[ServiceContract]
public interface IMyMathService
{
    [OperationContract]
    double Add(double dblNum1, double dblNum2);

    [OperationContract]
    double Subtract(double dblNum1, double dblNum2);

    [OperationContract]
    double Multiply(double dblNum1, double dblNum2);

    [OperationContract]
    double Divide(double dblNum1, double dblNum2);
}

explanation

as one can see, there is one service contract (IMyMathService), and 4 operation contract to perform 4 basic math operations.

Implementing Service (MyMathService.cs)

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

public class MyMathService : IMyMathService
{
    public double Add(double dblNum1, double dblNum2)
    {
        return (dblNum1 + dblNum2);
    }

    public double Subtract(double dblNum1, double dblNum2)
    {
        return (dblNum1 – dblNum2);
    }

    public double Multiply(double dblNum1, double dblNum2)
    {
        return (dblNum1 * dblNum2);
    }

    public double Divide(double dblNum1, double dblNum2)
    {
        return ((dblNum2 == 0) ? 0 : (dblNum1 / dblNum2));
    }
}

explanation

here simply those 4 methods has been implemented.

Creating Client for the Service

Add a new project to the workspace, say a Console based application, name it MyMathClient, for instance.

image

newly created project will be added to the work space.

Generating proxy and config file.

right click on the newly created (client) project, and click on "Add Service Reference", as shown below.

image

a dialog box will be displayed as shown below. in the address bar type the address of the service,

image

Click OK,

  • A app.config (client side configuration) will be added to the project.
  • a Service reference named MyMathServiceProxy will be added in Service References node of the client project.

Calling the Service

Now write the code to use the proxy and call the service, here is the listing of the Program.cs.

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

namespace MyMathClient
{
    class Program
    {
        static void Main(string[] args)
        {
            double dblX = 2000.0 ;
            double dblY = 100.0 ;
            double dblResult = 0 ;
            MyMathServiceProxy.MyMathServiceClient mathClient = new MyMathServiceProxy.MyMathServiceClient();

            dblResult = mathClient.Add (dblX, dblY );
            Console.WriteLine("Calling Add >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);
           
            dblResult = mathClient.Subtract (dblX, dblY);
            Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

            dblResult = mathClient.Multiply(dblX, dblY);
            Console.WriteLine("Calling Mul >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

            dblResult = mathClient.Divide(dblX, dblY);
            Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);
        }
    }
}

and here is the output.

image

Creating a web Client for the Service

Add a new web site to the workspace, name it MyWebMathClient, for instance as shown below.

image

Add Service reference of the Math Service to the newly created website, as shown below

image

Adding this Service Reference, made a change in the web.config file of the Client Web site, if you open the web.config, you will find the following changes, at the bottom of the file.

<system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IMyMathService" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="
http://localhost/MyMathService/MyMathService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyMathService"
                contract="MyMathServiceReference.IMyMathService" name="WSHttpBinding_IMyMathService">
                <identity>

                   <!—this name can be different on your machine. –!>
                    <servicePrincipalName value="host/PRAVEEN-WIN7" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>

 

Open the Page_load Handler of the Default.aspx in the newly created (Client Web Site) and put the code as shown below.

protected void Page_Load(object sender, EventArgs e)
   {
       double dblX = 10000.0;
       double dblY = 2000.0;
       double dblResult = 0;
       Response.Write("<p>Value 1 : " + dblX.ToString("F2"));
       Response.Write("<br>Value 2 : " + dblY.ToString("F2"));

       try
       {
           Response.Write("<p>Using WS HTTP Binding");

           MyMathServiceReference.MyMathServiceClient mathProxy2 = new MyMathServiceReference.MyMathServiceClient("WSHttpBinding_IMyMathService");

           dblResult = mathProxy2.Add(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

           dblResult = mathProxy2.Subtract(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

           dblResult = mathProxy2.Multiply(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

           dblResult = mathProxy2.Divide(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));
       }
       catch (Exception eX)
       {
           Response.Write("There was an error while calling Service <p> <b>[" + eX.Message + "] </b>");
       }
   }

and when you run this web site, you will get following output.

image

September 6, 2013 Posted by | .NET, CodeProject, SOA, WCF | , , , | 1 Comment