Wednesday, May 15, 2013

Self Hosting in WCF using c#


What is Self Hosting ?

WCF provides the user to host the service in any application (e.g. console application, Windows form etc.). Very interestingly developer is responsible for providing and managing the life cycle of the host process. Service can also be in-pro i.e. client and service in the same process. Now let's us create the WCF service which is hosted in Console application.

Step 1: 

Create a solution with three projects.
1. SelfHostingWCF (WCF Service Library)
2. Host (Console Application)
3. Client  (Console Application)


Step 2: Delete IService1.cs, Service1.cs from SelfHosttingWCF application and add ICalculator.cs, Calculator.cs and modify App.config file in SelfHosttingWCF application as given below.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="default" name="SelfHostingWCF.Calculator">

        <endpoint address="basic" binding="basicHttpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.tcp://localhost:8888/Service/tcp" binding="netTcpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.pipe://localhost/Service/pipe" binding="netNamedPipeBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/Service" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

**********************************************************************

using System.ServiceModel;



namespace SelfHostingWCF
{
    [ServiceContract]
    public interface ICalculator
    {
        [OperationContract]
        int Add(int n1,int n2);
    }
}

**********************************************************************

namespace SelfHostingWCF
{
    public class Calculator : ICalculator
    {

        int ICalculator.Add(int n1, int n2)
        {
            return n1 + n2;
        }
    }
}

**********************************************************************

Step 3: Copy App.config file from SelfHostingWCF application and paste it to Host application and modify it as follows.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="default" name="SelfHostingWCF.Calculator">

        <endpoint address="basic" binding="basicHttpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.tcp://localhost:8888/Service/tcp" binding="netTcpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.pipe://localhost/Service/pipe" binding="netNamedPipeBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Step 4: Add two references in Host application first one from Projects 'SelfHostingWCF' and second one from .Net 'System.ServiceModel'  and modify the Program.cs file as follows.

using System;
using System.ServiceModel;

namespace Host
{
    public class Program
    {
        static void Main(string[] args)
        {
            //Create base address dynamically..
            Uri baseAddress = new Uri("http://localhost:8080/Service");

            using (ServiceHost host = new ServiceHost(typeof(SelfHostingWCF.Calculator), baseAddress))//if baseAddress is already declared in App.Config file in such case you do not have need to pass second parameter.
            {
                //Create endpoint dynamically.
                host.AddServiceEndpoint(typeof(SelfHostingWCF.ICalculator), new WSHttpBinding(), "ws");

                foreach (var item in host.Description.Endpoints)
                {
                    Console.WriteLine(item.Address); 
                }

                Console.WriteLine("Servive is up and running at {0}",DateTime.Now.ToShortDateString());
                Console.Read();
            }
        }
    }
}

Step 5: Set the Host application as Start up project and press F5, If every thing goes well you will get this.


Service is hosted, now we need to implement the proxy class for the client. There are different ways of creating the proxy
  1. Using SvcUtil.exe, we can create the proxy class and configuration file with end points.
  2. Adding Service reference to the client application.
  3. Implementing ClientBase<T> class
Of these three methods, Implementing ClientBase<T> is the best practice. If you are using rest two method, we need to create proxy class every time when we make changes in Service implementation. But this is not the case for ClientBase<T>. It will create the proxy only at runtime and so it will take care of everything.

Extend the ClientBase<TChannel> class to create a custom WCF client object that can be used to connect to a service. Typically, the WCF client base class is extended by a tool such as the ServiceModel Metadata Utility Tool (Svcutil.exe) on your behalf. 

The ClientBase<TChannel> class can be used quickly and easily by developers who prefer objects to the use of the interfaces and the System.ServiceModel.ChannelFactory<TChannel> class. In all cases this class wraps or exposes the methods and functionality of the System.ServiceModel.ChannelFactory<TChannel> class and the System.ServiceModel.IClientChannel interface.

Step 6: Add two references in Client application first one from Projects 'SelfHostingWCF' and second one from .Net 'System.ServiceModel'  and modify the Program.cs file as follows.

using System;
using System.ServiceModel;
using System.Threading;
using SelfHostingWCF;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread.Sleep(1000);
            ICalculator proxy = new ClientProxy(new BasicHttpBinding(BasicHttpSecurityMode.None), new EndpointAddress("http://localhost:8080/Service/basic"));
            //ICalculator proxy = new ClientProxy(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8888/Service/tcp"));
            Console.WriteLine("Sum of two numbers... 5+5 =" + proxy.Add(5, 5));
            Console.ReadLine();
        }
    }

    public class ClientProxy : ClientBase<ICalculator>, ICalculator
    {
        public ClientProxy()
        {
        }

        public ClientProxy(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public ClientProxy(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public ClientProxy(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public ClientProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
        {
        }

        protected override ICalculator CreateChannel()
        {
            return base.CreateChannel();
        }

        int ICalculator.Add(int n1, int n2)
        {
            return base.Channel.Add(n1, n2);
        }
    }
}

Step 7: Right click on project solution select Properties perform following changes.


Step 8: Press F5










 
Post a Comment