Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C#
Article

WCF (Windows Communication Foundation) Example

Rate me:
Please Sign up or sign in to vote.
4.76/5 (52 votes)
14 Dec 2006CPOL6 min read 736.5K   40.9K   175   89
A simple example of WCF (Windows Communication Foundation): a simple client/server solution.

Sample Image

Introduction

The reason for publishing this article is that I think that a lot of people are going to use the new .NET 3.0 WCF. It is simple to use, and seems very powerful. I have spend a lot of time debugging this program, and I hope that this article will prevent other people from getting the same headache that I had because of a funny security exception that I would get all the time. Use the code directly or as an inspiration. I assume that the reader is familiar with client/server coding, and will therefore not get into details. It is said that WCF is very dynamic regarding the transfer methods, and can be configured to use almost any communication standard which makes it suitable for many client/server applications. It does not matter if you use HTTP, TCP etc., to transfer data, and the optional SSL / Encryption makes the WCF even more suited for large scale solutions.

Background

The project is straightforward, really. The source contains some files that I used to develop the application. The source contains the ServiceLibrary that is the contract compiled into a simple DLL. Don't confuse the difference between the contract and the proxy. The contract is a sort of a way to communicate, and the proxy is a way to get access to another remote contract. The other two libraries are almost self-explaining, the WCFClient and the WCFService. The goal was to create a dynamic client server solution that is not bound by configuration files etc., but is more dynamic. Plus don't underestimate the fun writing the code :) Thanks to Gedebuk, Denmark.

The Proxy.cs code is auto-generated by svcutil.exe. If you need to re-create the Proxy.cs, start the service and run the command: "C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\svcutil.exe" http://localhost:8001/MyService /out:Proxy.cs.

Using the code

The code consists of two folders that are loaded into one project file.

How did I create the project?

In this section, I will describe how I created the project. The steps are listed in sequence and are numbered.

1) Creating the ServiceLibrary.cs

I created the project by starting off with the ServiceLibrary. This library is compiled into a DLL which is used on the client (or clients for that matter). In WCF terms, this is the contract that the client must obey in order to be able to communicate with the server. This contract is in fact an interface that the client(s) communicates through. The ServiceLibrary contains all the methods that can be called by the client. In this example, it also holds the implementation for the service. The DataContract has the mark [DataContract] that indicates that it's an object that can be transferred. In WCF, it does not matter if it is a simple type, like a string, or a complex type like an object that is transferred over the wire. Below is a copy/paste from my contract.

C#
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace ServiceLibrary
{
    // You have created a class library to
    // define and implement your WCF service.
    // You will need to add a reference to this
    // library from another project and add 
    // the code to that project to host the
    // service as described below.  Another way
    // to create and host a WCF service is by
    // using the Add New Item, WCF Service 
    // template within an existing project such
    // as a Console Application or a Windows 
    // Application.

    [ServiceContract()]
    public interface IService1
    {
        [OperationContract]
        string MyOperation1(string myValue);
        [OperationContract]
        string MyOperation2(DataContract1 dataContractValue);
        [OperationContract]
        string HelloWorld(string str);
    }

    public class service1 : IService1
    {
        public string MyOperation1(string myValue)
        {
            return "Hello: " + myValue;
        }
        public string MyOperation2(DataContract1 dataContractValue)
        {
            return "Hello: " + dataContractValue.FirstName;
        }
        public string HelloWorld(string str)
        {
            return "Helloworld from " + str;
        }
    }

    [DataContract]
    public class DataContract1
    {
        string firstName;
        string lastName;

        [DataMember]
        public string FirstName
        {
            get { return firstName; }
            set { firstName = value; }
        }
        [DataMember]
        public string LastName
        {
            get { return lastName; }
            set { lastName = value; }
        }
    }
}

The code is something that the Visual Studio project generates for me. I've only added the HelloWorld part of this code. The VS environment did also generate a how-to on Adding a Service Reference. I've skipped that and deleted those parts. You can either configure the program from a configuration file that is a part of Visual Studio, or add the configuration in the code, or code the configuration. I have chosen to configure the service inside the code. One would argument about the ease of changing an XML file instead of recompiling the project if changes in the client/server relation occurs, but I have chosen to do this in order for the program to be able to configure itself in future implementations. This code will act as a core function in a rather large client/server solution where computers will contact other computers randomly via WCF. This requires the program to be able to change the runtime, and is the main reason for this code to be controlled in-code.

2) Creating the Service-Host Application

The service-host application is the program that holds the service that has the actual objects. This is the server if you like to call it that.

I created a Windows Forms project and added the following code:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace WCFService
{
    public partial class MainForm : Form
    {
        private ServiceHost host = null;
        private string urlMeta, urlService = "";

        public MainForm()
        {
            InitializeComponent();
            Append("Program started ...");
        }

        void host_Opening(object sender, EventArgs e)
        {
            Append("Service opening ... Stand by");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                // Returns a list of ipaddress configuration
                IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());

                // Select the first entry. I hope it's this maschines IP
                IPAddress _ipAddress = ips.AddressList[0];

                // Create the url that is needed to specify
                // where the service should be started
                urlService = "net.tcp://" + 
                    _ipAddress.ToString() + ":8000/MyService";

                // Instruct the ServiceHost that the type
                // that is used is a ServiceLibrary.service1
                host = new ServiceHost(typeof(ServiceLibrary.service1));
                host.Opening += new EventHandler(host_Opening);
                host.Opened += new EventHandler(host_Opened);
                host.Closing += new EventHandler(host_Closing);
                host.Closed += new EventHandler(host_Closed);

                // The binding is where we can choose what
                // transport layer we want to use. HTTP, TCP ect.
                NetTcpBinding tcpBinding = new NetTcpBinding();
                tcpBinding.TransactionFlow = false;
                tcpBinding.Security.Transport.ProtectionLevel = 
                   System.Net.Security.ProtectionLevel.EncryptAndSign;
                tcpBinding.Security.Transport.ClientCredentialType = 
                   TcpClientCredentialType.Windows;
                tcpBinding.Security.Mode = SecurityMode.None;
                // <- Very crucial

                // Add a endpoint
                host.AddServiceEndpoint(typeof(
                   ServiceLibrary.IService1), tcpBinding, urlService);

                // A channel to describe the service.
                // Used with the proxy scvutil.exe tool
                ServiceMetadataBehavior metadataBehavior;
                metadataBehavior = 
                  host.Description.Behaviors.Find<ServiceMetadataBehavior>();
                if (metadataBehavior == null)
                {
                    // This is how I create the proxy object
                    // that is generated via the svcutil.exe tool
                    metadataBehavior = new ServiceMetadataBehavior();
                    metadataBehavior.HttpGetUrl = new Uri("http://" + 
                          _ipAddress.ToString() + ":8001/MyService");
                    metadataBehavior.HttpGetEnabled = true;
                    metadataBehavior.ToString();
                    host.Description.Behaviors.Add(metadataBehavior);
                    urlMeta = metadataBehavior.HttpGetUrl.ToString();
                }

                host.Open();
            }
            catch (Exception ex1)
            {
                Console.WriteLine(ex1.StackTrace);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            host.Close();
        }

        void host_Closed(object sender, EventArgs e)
        {
            Append("Service closed");
        }

        void host_Closing(object sender, EventArgs e)
        {
            Append("Service closing ... stand by");
        }

        void host_Opened(object sender, EventArgs e)
        {
            Append("Service opened.");
            Append("Service URL:\t" + urlService);
            Append("Meta URL:\t" + urlMeta + " (Not that relevant)");
            Append("Waiting for clients...");
        }

        private void Append(string str)
        {
            textBox1.AppendText("\r\n" + str);
        }
    }
}

The interesting part is of course the button1_Click which creates the service and makes the service public to other clients. Now for other clients to connect to this service, the service needs a contract. The contract is not something that one would write themselves, and that's why I use the scvutil.exe tool. On my PC, the tool is located at C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\svcutil.exe. In order to make the contract object (that is actually the proxy that clients connect to), we need to generate Proxy.cs (the name of the file is not relevant at all, could be foo.cs as well). This will happen in step 3.

3) Building the Proxy Object for Clients to Use

The proxy object is built from the service description that is located on port 8001 (check the code). It reads the meta data from the service, and constructs the contract that is needed by clients when they want to communicate with the service.

  1. First, start the service and hit the "Start service" button. This creates the service. All meta info is published for other clients or tools to read them.
  2. Second, run "C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\svcutil.exe" http://localhost:8001/MyService /out:Proxy.cs. This creates two files. A Proxy.cs file and an XML config file. I discard the config file because I'll configure the service inside the program. You should consider putting the "C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\svcutil.exe" http://localhost:8001/MyService /out:Proxy.cs in a bat file to make it easier for yourself. I have included my bat file for you to see. It resides in the "ProxyGenerator" folder.

    Next, I create a simple client and add relevant code to it.

4) Creating a Client Application and Adding Relevant Code to it

Now, we create a simple standard client program as a Windows Forms apllication. Once the files are generated (Proxy.cs and output.config <- can be suppressed), I add the Proxy.cs to my client program which is called WCFClient. Now, the client knows the contract and is able to obey it in order to create a communication channel to the service. One could compile the Proxy.cs into a DLL and simply add the DLL to the client (a cleaner way to add something that is crucial as a communication contract or interface, I think). For demonstration, we leave the Proxy.cs as it is and add it to the client project. Next, and the last step: we need to add some simple client code in order to retrieve the service proxy object. My client code looks like this:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;

namespace WCFClient
{
    public partial class Form1 : Form
    {
        string endPointAddr = "";

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text != "")
            {
                endPointAddr = "net.tcp://" + textBox2.Text + 
                               ":8000/MyService";
                NetTcpBinding tcpBinding = new NetTcpBinding();
                tcpBinding.TransactionFlow = false;
                tcpBinding.Security.Transport.ProtectionLevel = 
                  System.Net.Security.ProtectionLevel.EncryptAndSign;
                tcpBinding.Security.Transport.ClientCredentialType = 
                  TcpClientCredentialType.Windows;
                tcpBinding.Security.Mode = SecurityMode.None;

                EndpointAddress endpointAddress = 
                   new EndpointAddress(endPointAddr);

                Append("Attempt to connect to: " + endPointAddr);

                IService1 proxy = 
                  ChannelFactory<IService1>.CreateChannel(
                  tcpBinding, endpointAddress);

                using (proxy as IDisposable)
                {
                    Append("Message from server: " + 
                      (proxy.HelloWorld(textBox1.Text) + 
                      " back to you :)"));
                }   
            }
        }

        private void Append(string str)
        {
            textBox3.AppendText("\r\n" + str);

Points of Interest

Well, I really had a lot of fun working with the code and writing the article. The most impressive thing, in my opinion, is that the transport layer very easily can be modified to use HTTP instead of TCP. I did not point that out in the article but that's also something nice to have. Being able to switch the transport layer from TCP (Secure SSL) into HTTP with some simple code, that's amazing! I did have some problems, though. The tcpBinding.Security.Mode = SecurityMode.None; is very crucial on both sides. I'm not sure what it does, but it does not turn off the security completely as I have read in my references. There is still SSL encryption, but on a lower level. It is possible to add certificates to the connection, which also makes the connection more secure.

History

  • December 13th 2006 - Project completed.

License

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


Written By
Web Developer
Denmark Denmark
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMy vote of 5 Pin
teamoo26-Jun-16 20:37
teamoo26-Jun-16 20:37 
QuestionError when recompiling Pin
Ciuchinobello14-Feb-14 1:12
Ciuchinobello14-Feb-14 1:12 
AnswerRe: Error when recompiling Pin
BoHansen7619-Mar-14 1:24
BoHansen7619-Mar-14 1:24 
GeneralMy vote of 4 Pin
Mohammad Sanati8-May-13 10:53
Mohammad Sanati8-May-13 10:53 
GeneralRe: My vote of 4 Pin
BoHansen7619-Mar-14 1:25
BoHansen7619-Mar-14 1:25 
QuestionGreat article. Can the service be hosted in IIS Pin
Member 998569718-Apr-13 11:17
Member 998569718-Apr-13 11:17 
AnswerRe: Great article. Can the service be hosted in IIS Pin
BoHansen7618-Apr-13 19:07
BoHansen7618-Apr-13 19:07 
AnswerRe: Great article. Can the service be hosted in IIS Pin
BoHansen7619-Mar-14 1:28
BoHansen7619-Mar-14 1:28 
GeneralMy vote of 5 Pin
Albert Nizamutdinov9-Apr-13 23:57
Albert Nizamutdinov9-Apr-13 23:57 
GeneralMy vote of 5 Pin
SAHasani19615-Jan-13 23:59
SAHasani19615-Jan-13 23:59 
GeneralRe: My vote of 5 Pin
BoHansen7618-Apr-13 19:07
BoHansen7618-Apr-13 19:07 
QuestionCool and it works as a windows 8 store app Pin
Uwe Eichkorn12-Jan-13 10:27
Uwe Eichkorn12-Jan-13 10:27 
AnswerRe: Cool and it works as a windows 8 store app Pin
BoHansen7618-Apr-13 19:08
BoHansen7618-Apr-13 19:08 
AnswerRe: Cool and it works as a windows 8 store app Pin
BoHansen7619-Mar-14 1:29
BoHansen7619-Mar-14 1:29 
Questionerror in source code Pin
dimple soni17-Dec-12 0:55
dimple soni17-Dec-12 0:55 
AnswerRe: error in source code Pin
BoHansen7618-Apr-13 19:09
BoHansen7618-Apr-13 19:09 
GeneralRe: error in source code Pin
charles92213-Jun-13 18:45
charles92213-Jun-13 18:45 
GeneralRe: error in source code Pin
BoHansen7613-Jun-13 19:33
BoHansen7613-Jun-13 19:33 
GeneralRe: error in source code / TCP error 10061 Pin
charles92214-Jun-13 7:05
charles92214-Jun-13 7:05 
Two things I changed based on numerous posts I've been reading where people had success:
1. IIS Manager, "Default Web Site", "Advanced Settings", "Enabled Protocols", add "net.tcp". (Apparently there has to be a comma between "http" and "net.tcp". A semicolon does not seem to be valid.)
2. Then under "Programs", "Turn Windows Features on or off", ".NET Framework 3.5.1", check the "HTTP Activation" and "Non-HTTP Activation" boxes. Then under "Services", two Net.Tcp services are now running that were not previously (after re-booting Win 7)

Now I'm getting a "URI error" on this line of code:
EndpointAddress endpointAddress = new EndpointAddress(endPointAddr);


After reading the first chapter of Michele Bustamante's "Learning WCF" book, I knew WCF was not going to be easy! Smile | :)

If I have a breakthrough, I'll post it.
GeneralRe: error in source code / TCP error 10061 Pin
charles92214-Jun-13 10:11
charles92214-Jun-13 10:11 
GeneralRe: error in source code / TCP error 10061 Pin
BoHansen7619-Mar-14 1:30
BoHansen7619-Mar-14 1:30 
GeneralRe: error in source code / TCP error 10061 Pin
BoHansen7614-Jun-13 10:15
BoHansen7614-Jun-13 10:15 
GeneralMany Thanks Pin
Damian McCracken1-Sep-12 5:35
Damian McCracken1-Sep-12 5:35 
GeneralRe: Many Thanks Pin
BoHansen7618-Apr-13 19:09
BoHansen7618-Apr-13 19:09 
Questionnice Pin
sulem30-Aug-12 20:55
sulem30-Aug-12 20:55 

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.