Click here to Skip to main content
15,887,267 members
Articles / Programming Languages / C#
Tip/Trick

Create a Self-Hosted WCF Service - Beginner's Turorial For WCF

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
25 Oct 2015CPOL3 min read 14.9K   14   2
This tip documents problems encountered in the process of learning WCF and Computer Network.

Introduction

Because of my job, I need to learn WCF. This series of articles will record my learning process. If you are a beginner just like me, you can write the code in this tip by yourself. After we finish learning the fundamental steps, I will upload my source code. Besides, I am in the process of learning English, so if you find some mistakes in my tip, please tell me!

Create a WCF Service

Step 1: Create the Service Contract and its Implementation

Quote:

First let's start creating the service contract and its implementation. Create an IEcho interface, add the System.ServiceModel reference to project, add ServiceContract and OperationContract attribute to the class. These contracts will expose methods to the outside world for using the service.

C#
//IEcho.cs
using System.IO;
using System.ServiceModel;

name space EchoService
{
    [ServiceContract]
    public interface IEcho
    {
        [OperationContract]
        string Echo(string message);

        [OperationContract]
        Stream DownloadStream();

        [OperationContract]
        void UploadStream(Stream stream);
    }
}
C#
//Echo.cs
using System;
using System.IO;
using System.ServiceModel.Activation;

namespace EchoService
{
    public class EchoService : IEcho
    {
        public string Echo(string message)
        {
            return message;
        }

        public Stream DownloadStream()
        {
            byte[] buffer = new byte[1024];
            Random rand = new Random();
            rand.NextBytes(buffer);

            MemoryStream stream = new MemoryStream(buffer);
            return stream;
        }

        public void UploadStream(Stream stream)
        {
            int readResult;
            int bytesRead = 0;
            byte[] buffer = new byte[1000];
            do
            {
                readResult = stream.Read(buffer, 0, buffer.Length);
                bytesRead += readResult;
            }
            while (readResult != 0);

            stream.Close();
        }
    }
}

Service Contract

  1. It describes the client-callable operations exposed by the service.
  2. It maps the interface and methods of your service to a platform-independent description.
  3. It describes message exchange patterns. Some service operations might be one-way; others might require a request-reply pattern.

Step 2: Create a Console Application to Host the Service?

Quote:

Now we are ready with the service. Let's go for implementing the hosting process. Create a console application and name it as "SelfHosting.cs".

C#
//SelfHosting.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace SelfHostedTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string address = "http://localhost:8090/SelfHostService/EchoSerivce";

            Uri httpUrl = new Uri(address);

            ServiceHost host = new ServiceHost(typeof(SelfHostService.EchoSerivce), httpUrl);

            BasicHttpBinding binding = new BasicHttpBinding();
            host.AddServiceEndpoint(typeof(SelfHostService.IEchoSerivce), new BasicHttpBinding(), address);

            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            host.Description.Behaviors.Add(smb);

            host.Open();
            Console.WriteLine("Service is host at " + address);
            Console.WriteLine("Host is running... Press <Enter> key to stop");
            Console.ReadLine();
        }
    }
}

When a service is hosted in Internet Information Services(IIS) or Windows Process Activation Service(WAS), the base address of the service is provided by the hosting enviroment. In the self-hosted case, you must specify the base address yourself. You can use the code above to config the service, you can also use the App.config to config the service. Notice the code will override the App.config file configuration.

XML
<service
    name="SelfHostService.EchoService"
    behaviorConfiguration="EchoService">
  <host>
    <baseAddresses>
      <add baseAddress="http://localhost:8090/SelfHostService/EchoSerivce"/>
    </baseAddresses>
  </host>
  ...
</service>

ServiceHost

ServiceHost class is an important class to configure and expose a service for use by client-applications when you are not using IIS or WAS to host the service.

ServiceHost object is made to load a service, configure endpoint, apply security setting, and start listeners to handle incoming requests.

Note: Host process must be running before the client calls the service, which typically means you have to prelaunch it.

Step 3: Create a Client to Call the Service

Quote:

Service is hosted, now we need to implement the proxy class for the client. There are different ways of creating the proxy.

  • Using SvcUtil.exe, we can create the proxy class and configuration file with end points.
  • Adding Service reference to the client application.
  • Implementing ClientBase<T> class:
C#
//Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.Text;
using ComMethods;

namespace EchoServiceTester
{
        static void main()
        {
            RunTests()
        }

        private static void RunTests()
        {
            string address = string.Format("http://{0}/EchoService.svc/DefaultEcho", host);
            Binding binding = new BasicHttpBinding();
            InvokeServiceOperations(address, binding);
        }
 
        private static void InvokeServiceOperations(string address, Binding binding)
        {
            Console.WriteLine("Testing service operations 
            	using a binding with the following elements:");
            DescribeBinding(binding);

            TestEcho(address, binding);
            TestUploadStream(address, binding);
            TestDownloadStream(address, binding);

            Console.WriteLine("Test passed.");
        }
      
        static void DescribeBinding(Binding binding)
        {
            foreach (BindingElement element in (new CustomBinding(binding)).Elements)
            {
                Console.WriteLine(element.GetType().Name);
            }
        }

        static void TestEcho(string address, Binding binding)
        {
            ChannelFactory<IEcho> channelFactory = 
            	new ChannelFactory<IEcho>(binding, address);
            IEcho client = channelFactory.CreateChannel();
            ((IChannel)client).Open();

            Console.WriteLine("Invoking Echo... Response = {0}", 
            	client.Echo("Hello World!"));
            ((IChannel)client).Close();
        }

        static void TestUploadStream(string address, Binding binding)
        {
            byte[] buffer = new byte[1024];
            Random rand = new Random();
            rand.NextBytes(buffer);

            MemoryStream stream = new MemoryStream(buffer);

            ChannelFactory<IEcho> channelFactory = 
            	new ChannelFactory<IEcho>(binding, address);
            IEcho client = channelFactory.CreateChannel();
            ((IChannel)client).Open();

            Console.WriteLine("Invoking UploadStream...");
            client.UploadStream(stream);

            ((IChannel)client).Close();
        }

        static void TestDownloadStream(string address, Binding binding)
        {
            ChannelFactory<IEcho> channelFactory = 
            	new ChannelFactory<IEcho>(binding, address);
            IEcho client = channelFactory.CreateChannel();
            ((IChannel)client).Open();

            Console.WriteLine("Invoking DownloadStream...");
            Stream stream = client.DownloadStream();

            int readResult;
            int bytesRead = 0;
            byte[] buffer = new byte[1000];
            do
            {
                readResult = stream.Read(buffer, 0, buffer.Length);
                bytesRead += readResult;
            }
            while (readResult != 0);

            stream.Close();

            Console.WriteLine("Read {0} bytes.", bytesRead);

            ((IChannel)client).Close();
        }
}

Typically, to create a channel to a service endpoint, you can generate a client type with Svcutil.exe or Add Service Reference to create an instance of generated type. You can also create a channel by using the ChannelFactory<TChannel> class. Then, configure how the client can communicate with the service. Of these three methods, Implementing ClientBase<T> is the best practice. If you are using rest two methods, we need to create a proxy class every time 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Junior)
China China
Just graduated from collage. Now I am trying to practice my English. Sometimes I cannot present the ideas what in my mind. But I believe it will get better if I insist on write tech article

Comments and Discussions

 
Praisethanks Pin
cangcang27-Sep-16 23:10
cangcang27-Sep-16 23:10 
Questionthanks Pin
cangcang27-Sep-16 23:08
cangcang27-Sep-16 23:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.