How to do it: Developing a WCF Service and host on a Windows Console Application

Code Samples
Table of Contents
Summary

WCF Service and Self-Hosting on Console Application

Note

Implementing a WCF Service to be hosted on custom managed application, the configuration file “App.Config” is only required  on the host project.

Operations
Project "Services.Definition", File "Common.Data.cs"

This file contains the definition of the complex class types sent on the service request and expected as service response

How to do it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace WCF
{
    [DataContract]
    public class Category
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Description { get; set; }
    }
}
Project "Services.Definition", Files "IwcfTestService.cs" and "wcfTestServiceImpl.cs"
How to do it

The file “IwcfTestService.cs” represents the interface of the service:

using System.ServiceModel;
using System.Collections.Generic;

namespace WCF
{
    #region  "Service definiton using DataContract on resources"

    /// <summary>
    /// Summary description for wcfTestService service contract
    /// </summary>
    [ServiceContract(Namespace="http://www.training.com")]
    public interface IwcfTestService
    {
        [OperationContract]
        Category getCategoryWithDataContractAsXML(string pId);

        [OperationContract]
        Category getCategoryWithDataContractAsJSON(string pId);

        [OperationContract]
        List<Category> getCategoriesWithDataContractAsXML();

        [OperationContract]
        List<Category> getCategoriesWithDataContractAsJSON();

        [OperationContract]
        int addCategoryWithDataContractAsXML(Category pCategory);

    #endregion

        #region  "Service definiton without using DataContract on resources"

        [OperationContract]
        string getCategoryAsXML(string pId);

        [OperationContract]
        string getCategoryAsJSON(string pId);

        [OperationContract]
        List<string> getCategoriesAsXML();

        [OperationContract]
        List<string> getCategoriesAsJSON();

        [OperationContract]
        int addCategory(string pName);

        #endregion

    }
}

The file “wcfTestServiceImpl.cs” represents one implementation of the service contract:

using System.Collections.Generic;
using System;

namespace WCF
{
    /// <summary>
    /// Summary description for wcfTestService service contract implementation
    /// </summary>
    public class wcfTestServiceImpl : IwcfTestService
    {

        #region  "Service definiton without using DataContract on resources"

        public string getCategoryAsXML(string pID)
        {
            //TODO: Put code here to retrieve category name...
            return loadCategory(Convert.ToInt32(pID));
        }

        public string getCategoryAsJSON(string pID)
        {
            //TODO: Put code here to retrieve category name...
            return loadCategory(Convert.ToInt32(pID));
        }

        public List<string> getCategoriesAsXML()
        {
            //TODO: Put code here to retrieve category names...
            return loadCategoryNames();
        }

        public List<string> getCategoriesAsJSON()
        {
            //TODO: Put code here to retrieve category names...
            return loadCategoryNames();
        }

        public int addCategory(string pName)
        {
            //TODO: Put code here to save category name
            return 10;
        }

        private string loadCategory(int pId)
        {
            return "This the category with name for ID " + pId.ToString();
        }

        private List<string> loadCategoryNames()
        {
            return new List<string>() { "Category #1", "Category #2" };
        }
        #endregion

        #region  "Service definiton using DataContract on resources"
        public Category getCategoryWithDataContractAsXML(string pId)
        {
            //TODO: Put code here to retrieve category...
            return loadCategoryWithDataContract(Convert.ToInt32(pId));
        }

        public Category getCategoryWithDataContractAsJSON(string pId)
        {
            //TODO: Put code here to retrieve category...
            return loadCategoryWithDataContract(Convert.ToInt32(pId));
        }

        public List<Category> getCategoriesWithDataContractAsXML()
        {
            //TODO: Put code here to retrieve category names...
            return loadCategoriesWithDataContract();
        }

        public List<Category> getCategoriesWithDataContractAsJSON()
        {
            //TODO: Put code here to retrieve category names...
            return loadCategoriesWithDataContract();
        }

        public int addCategoryWithDataContractAsXML(Category pCategory)
        {
            //TODO: Put code here to save category defintion
            return 10;
        }

        private Category loadCategoryWithDataContract(int pId)
        {
            return new Category { Id = 1, Name = string.Format("category #{0}", pId), Description = string.Format("test category #{0}", pId) };
        }

        private List<Category> loadCategoriesWithDataContract()
        {
            return new List<Category>() {
                            new Category { Id=1, Name="category #1", Description= "test category #1"},
                            new Category { Id=2, Name="category #2", Description= "test category #2"} };
        }
        #endregion

    }
}
Project "wcfConsoleApplicationHost", File "Main.cs"

The code on this file instantiates a service host handler and opens the communication channel for consumption.

How to do it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace WCF
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host= null;
            try
            {
                host = new ServiceHost(typeof(wcfTestServiceImpl));
                host.Open();
                Console.WriteLine("Test console host initiated: Press <enter> to close host application");
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Test console host could not be initiated or an error occurred during host life cycle: " + ex.ToString());
            }
            finally
            {
                if (host != null)
                {
                    if (host.State != CommunicationState.Closed) host.Close();
                }
            }

        }
    }
}
Project "wcfConsoleApplicationHost", File "App.config"

The configuration file configures :

  • service endpoints to use (address, contract implementation and binding);
  • host base address service endpoints;
How to do it
<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="defaultServiceBehavior" name="WCF.wcfTestServiceImpl">
        <endpoint address="soap"  behaviorConfiguration="webEndPointBehavior" binding="basicHttpBinding" contract="WCF.IwcfTestService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="soap"  binding="netTcpBinding" contract="WCF.IwcfTestService"/>
        <endpoint address="mex" bindingConfiguration="" binding="mexHttpBinding" contract="IMetadataExchange" />
        <endpoint address="mextcp" bindingConfiguration="" binding="mexTcpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:55545/training/wcf/app/testservice1"/>
            <add baseAddress="net.tcp://localhost:8000/training/wcf/app/testservice1"/>
          </baseAddresses>
        </host>
      </service>
    </services>

    <behaviors>
      <endpointBehaviors>
        <behavior name="webEndPointBehavior"/>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="defaultServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>