Windows Communication Foundation (Indigo) Hello World Tutorial
Through a long history of inter-application and inter-machine communication, we have seen a number of technologies appear. Some have been superceded, while some are merely wrapped in other frameworks and namespaces but continue to underpin newer, more advanced implementations. In the .net 1.x timelines, we were faced with 5 primary approaches to communicating remotely between applications. Each of these had value (hence their existence within the same framework) because each targeted a different set of problems. However, each functioned differently, having different programming models, hostiong structures and configuration implementations. Targeting these various platforms required a varied knowledgebase, and that was before the whole Services movement was really added to the mix.
Windows Communication Foundation (WinCF), aka “Indigo”, promises to be a unified, simplified, optimized, and advanced evolution of a number of communication technologies into a single cohesive model. It subsumes ASMX web services, WSE, .Net Remoting, Enterprise Services and MSMQ with the promise of making it much easier to implement each technology and to greatly reduce the effort in providing a service implementation between these disparate technologies. People much smarter than I have written more in-depth content and so for those who are interested, I’ve provided some references at the end of this document. Here in this tutorial I’m not going to try and re-hash their words, rather I’m going to provide you with simple step-by-step guidance to getting up and running with specific key aspects of the technology, from a simple “Hello World” to hopefully some quite advanced implementations.
This first tutorial will look at installing WCF (as part of the .net Framework 3.0), including the Visual Studio 2005 integration, and producing a first simple "Hello World" service to demonstrate some of the key concepts of the platform. The samples are all in C#, but I can spin off VB.Net equivalents if there is sufficient interest. Also, previous versions of this series (that targeted various pre-release versions of WCF) used Notepad and the command line to build and compile WCF services. This latest version makes use of Visual Studio because, especially with the RTM release, I suspect that is what most readers will be using. If you're interested in crafting your services by hand to explore the underpinnings of WCF more closely (or to obtain the asynchronous implementation, as you will see further down), let me know and I'll update the earlier samples. So, with that all covered, let's get to installing and using WCF!
Installing WCF
Windows Communication Foundation forms part of the .net Framework 3.0 runtime. This runtime is completely backwards compatible to Windows XP (SP2) and Windows 2003, and it allows you to support hosting and calling WCF services. In order to produce services, it is worthwhile installing both the Windows Vista SDK (of which the .net 3.0 SDK forms a part) and the Visual Studio integration add-on as well. Be aware, the latter Visual Studio installation is still officially in beta, but it works fine with 2003, despite being a bit feature-sparse, as we shall see.
On the Server Side
The Visual Studio integration install simplifies building services, but, in order to gain a bit more of an understanding of WCF, we're going to be doing a little more work in this first tutorial. Create a root folder for the tutorial (e.g. c:\development\samples\WCF\Tutorial 1\), then load Visual Studio, go the Add -> New Project dialog. Select Class Library, call it ServiceLayer, and create it under a ServiceSide sub-folder. This layer will contain our actual WCF service, but will contain no host implementation itself (e.g. web-http-xml or console-tcp-binary details). To enable the WCF features, Add References to System.ServiceModel and System.Runtime.Serialization. Delete the Class1.cs file and we shall now proceed to some actual code. Most service samples tend to place the interface and actual implementation together. With ASMX 2.0, we could already make use of a separate specific .net interface to define our service, and WCF specifically favours this approach. I'm also not a fan of having too many things in a single file, so we will be putting our classes and interfaces into their own files. Add a new interface called IHelloWorldService to the project, containing the following code:
using System;
using System.ServiceModel;
namespace Elegantware.net.Samples.DotNet3.WCF.Tutorial1.ServiceLayer
{
[ServiceContract]
interface IHelloWorldService
{
[OperationContract]
string SayHello(string name);
}
}
This interface defines exactly what type of work our service will be doing, and will quite literally form the definition of our service. We will refer directly to the IHelloWorld interface from our configuration file as specifying the contract of what our service will do. The only difference between this code and another .net interface is that parts of it are decorated with WCF attributes. The first attribute (“ServiceContract”) states that this interface will form the contract for a WCF service, while the second one (“OperationContract”) defines the method as an operation that the service will offer and perform. One ServiceContract can contain multiple OperationContracts and these will be translated by the framework into the appropriate wsdl tags, but all of this is entirely transparent to the developer.
Next comes our class – the implementation of our interface. This class appears below, and you should take note of two important aspects, which we will discuss below.
using System;
namespace Elegantware.net.Samples.DotNet3.WCF.Tutorial1.ServiceLayer
{
class HelloWorldService : IHelloWorldService
{
public string SayHello(string name)
{
return "Hello, " + name;
}
}
}
First of all, the class implements the interface (“Implements IHelloWorldService” for the vb.net’ers), just as we would expect. Secondly, it has no specific or unusual attributes of its own. It’s ability to provide the implementation for our WCF service is handled almost purely by our config file. Now, this is not technically entirely accurate. The class could itself have made use of the attributes we saw above, and in fact entirely removed the necessity of a separate interface. However, as mentioned ealier, I find the use of the interface to be a far cleaner approach because it allows us to clearly separate our API - our contract - from our implementation. Some further possibilities are also opened up, but these are beyond our Hello World stage.
The class can also be adorned with a ServiceBehaviour attribute that does not alter the contract per se but does affect how the service fulfils it. ServiceBehaviour also allows us to modify instancing, throttling, and a variety of other options. For our introductory purposes we will not be making use of it, and ths current example clearly highlights the simplicity of the WCF model.
Well, that effectively constitutes all of the code we need to write for our service! The next step is to compile our creation, and then to choose and configure a host. Add a new Empty Web Site to the solution called WebHost and add a reference to our service. From the Add New Item menu we can now choose to add a new WCF Service, but this will create extra code in App_Code folder that we don't want right now, so add a new "txt file" option called HelloWorldService.svc with the following content:
<%@ ServiceHost Language="C#" Debug="true" Service="Elegantware.net.Samples.DotNet3.WCF.Tutorial1.ServiceLayer.
HelloWorldService" %>
Note that the Service attribute references the fully-qualified name of our service implementation class.
The final step on the server side of our work is setting up the web.config file which will contain all of the configurations necessary to get our service up and running. Our web.config file is shown below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service name="Elegantware.net.Samples.DotNet3.WCF.Tutorial1.ServiceLayer.
HelloWorldService">
<endpoint address="" binding="basicHttpBinding" contract="Elegantware.net.Samples.DotNet3.WCF.Tutorial1.
ServiceLayer.IHelloWorldService" />
</service>
</services>
</system.serviceModel>
</configuration>
WCF configurations can consist of a large number of settings but we’re using only the most straightforward in our example. From it we can see that our settings reside within the system.ServiceModel structure, and we configure all of our WCF services within this tag. A large proportion of the WCF-specific work can happen in the config files rather than in code and, while it can all be done in code instead, having it in the config means it is all configurable at any time while the service is in production without requiring a new version to be deployed. If you've done much WCF research you may well have heard of the 'ABC's of WCF: Address, Binding and Contract, these being the primary building blocks of a WCF service, and they are essentially controlled via this config, as we shall see. We’re defining a name for our service, which must match our class that implements the service itself, and we also define our interface that describes the service (i.e. it’s “contract” of “what it can do”). The "address" attribute is empty because we access our service via the .svc URI directly when using ASP.Net hosting – in non ASP.Net hosts this needs to be specified explicitly. Finally, we’re making use of standard http, basic profile binding. Bindings allow us to configure security, reliability, transports, and more, and are also a topic we’ll hopefully cover in more depth in later articles.
Our next step is to to run our service and see how it appears in the browser. All being well, we should see something like the screenshot below:

Those who have written asmx services will may notice an immediate difference - there is no option by default to view the wsdl description. In fact, you cannot even add a reference to this service from a client at the moment for the same reason. During the WCF beta cycle this was not the case, but for security reasons with the final release WCF no longer provides the metadata for a service by default. It is not difficult to enable this feature, however, and just requires some amendments to our config file. The page itself describes the instructions for doing so, giving both step-by-step details as a well as a summary of the final view of the web config. What these changes do is allow for metadata exchange (or "mex") so that clients can access the metadata of your service. The following web.config contains the required amendments (your web.config may have changed if you run the application from within Visual Studio by having the <assemblies> tag added. The amended web.config below can still be used as this tag will again just be re-added as necessary by Visual Studio):
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service name="Elegantware.net.Samples.DotNet3.WCF.Tutorial1.ServiceLayer.HelloWorldService" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="" binding="basicHttpBinding" contract="Elegantware.net.Samples.DotNet3.WCF.Tutorial1.ServiceLayer.IHelloWorldService"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Browsing again to our service, we should now be presented with the following page:

Browsing to the link within the page - the one suffixed with "?wsdl", shows us the wsdl file our service and we can now refer clients to this page to create proxies, which is the next step in our tutorial.
The Client
In order for our service to have any value (well, as valuable as a “Hello World” service can be!), it must have something that consumes it, so we’ll now go about creating our client. Add a new console application to the solution called TestClient. Right-click on the new project, and select the new option Add Service Reference. Under Service URI, enter the path to your service (e.g. http://localhost:55959/WebHost/HelloWorldService.svc, but with whatever port number is assigned on your machine instead of 55959) and give it a better name under the 'Service reference name' section, such as 'HelloWorldService'. When you click Ok, a number of actions occur behind the scenes: references are added to the System.Runtime.Serialization and System.ServiceModel assemblies we looked at earlier, an app.config file is added (or updated) to the project, and a reference is added to the service itself, which consists of a proxy to invoke the remote service. Conceptually this is much like the Add Web Reference activities we had with asmx Web Services, so let us analyse in a little more detail exactly what is generated.
First up, we'll be analysing the proxy class itself. Incidentally, this class is visible by default (we don't need to Show All Files first as with asmx).
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.312
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestClient.HelloWorldService
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="TestClient.HelloWorldService.IHelloWorldService")]
public interface IHelloWorldService
{
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IHelloWorldService/SayHello", ReplyAction="http://tempuri.org/IHelloWorldService/SayHelloResponse")]
string SayHello(string name);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface IHelloWorldServiceChannel : TestClient.HelloWorldService.IHelloWorldService, System.ServiceModel.IClientChannel
{
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class HelloWorldServiceClient : System.ServiceModel.ClientBase<TestClient.HelloWorldService.IHelloWorldService>, TestClient.HelloWorldService.IHelloWorldService
{
public HelloWorldServiceClient()
{
}
public HelloWorldServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public HelloWorldServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public HelloWorldServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public HelloWorldServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public string SayHello(string name)
{
return base.Channel.SayHello(name);
}
}
}
There are a few initial points of interest that I noticed with this class. First of all, you can see that the code generator creates an interface that very closely matches our own, which is in turn implemented by the corresponding class. The class itself is declared as partial so it could be extended. Interestingly, it does not by default contain asynchronous versions of the web service calls like the Visual Studio Add Web Reference proxies did (the Beginxx and Endxx methods). This can be generated using the command-line svcutil.exe tool that comes with the SDK, using an example like:
C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\svcutil.exe http://localhost:55959/WebHost/HelloWorldService.svc?wsdl /out:c:\temp\HelloWorldService.cs /a /config:c:\temp\newAppConfig.config
For more info on this tool, have a look at the MSDN Documentation. It is surprising that this option does not appear to be available in Visual Studio, however. The code produced using this command appears below:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.312
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IHelloWorldService")]
public interface IHelloWorldService
{
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IHelloWorldService/SayHello", ReplyAction="http://tempuri.org/IHelloWorldService/SayHelloResponse")]
string SayHello(string name);
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IHelloWorldService/SayHello", ReplyAction="http://tempuri.org/IHelloWorldService/SayHelloResponse")]
System.IAsyncResult BeginSayHello(string name, System.AsyncCallback callback, object asyncState);
string EndSayHello(System.IAsyncResult result);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface IHelloWorldServiceChannel : IHelloWorldService, System.ServiceModel.IClientChannel
{
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class HelloWorldServiceClient : System.ServiceModel.ClientBase<IHelloWorldService>, IHelloWorldService
{
public HelloWorldServiceClient()
{
}
public HelloWorldServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public HelloWorldServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public HelloWorldServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public HelloWorldServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public string SayHello(string name)
{
return base.Channel.SayHello(name);
}
public System.IAsyncResult BeginSayHello(string name, System.AsyncCallback callback, object asyncState)
{
return base.Channel.BeginSayHello(name, callback, asyncState);
}
public string EndSayHello(System.IAsyncResult result)
{
return base.Channel.EndSayHello(result);
}
}
Once again, we have a partial class, so theoretically we could just compile them together. The catch is that both classes have the same interface and the same constructors, so they would require some editing. I’m curious as to what the purpose was in removing the asynch methods by default but have not yet found an explanation, meaning the command-line approach is the only route at this point to getting the code (other than creating the proxies by hand, but this is a definite step backwards).
The next step is to actually make use of the proxy, which we can do by using code similar to that shown when viewing the svc file in the browser (as in the previous image). This code appears below:
using System;
using System.Collections.Generic;
using System.Text;
using TestClient.HelloWorldService;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
HelloWorldServiceClient client = new HelloWorldServiceClient();
// Use the 'client' variable to call operations on the service.
Console.WriteLine(client.SayHello("Hilton"));
// Always close the client.
client.Close();
Console.ReadLine();
}
}
}
This is all that is required to consume our WCF service. In a second, we will run the application and see our results. Before we do, it is worthwhile to spend a few words looking at the app.config file for our client. The default generated config appears below (the port number, 55959 in this case, will differ on your machine, but the rest should remain the same):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IHelloWorldService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:55959/WebHost/HelloWorldService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IHelloWorldService"
contract="TestClient.HelloWorldService.IHelloWorldService"
name="BasicHttpBinding_IHelloWorldService" />
</client>
</system.serviceModel>
</configuration>
The config file may have an "<identity>" tag that will cause an exception and can be removed. We spoke earlier about the essential ABCs of WCF (address, binding and contract) and it is worth seeing that these are all that is required for basic WCF communication. To demonstrate this, run the application as is, and all should work fine, but then try with the following config, and it should run similarly well:
<?xml version="1.0" encoding="utf-8" ?><configuration> <system.serviceModel> <client> <endpoint address="http://localhost:55959/WebHost/HelloWorldService.svc" binding="basicHttpBinding" contract="TestClient.HelloWorldService.IHelloWorldService" /> </client> </system.serviceModel></configuration>
Congratulations on building your first WCF service and client. In this tutorial we looked at some of the basic attributes required for WCF, building and configuring a service, making it available and consuming it within a client. In the next tutorial we will expand on what we have learned and look at sending custom object over the wire.
Some Quick WinCF Links
Introduction to Building Windows Communication Foundation Services - http://msdn.microsoft.com/webservices/indigo/default.aspx?pull=/library/en-us/dnlong/html/introtowcf.asp
Willy-Peter's blog - http://dotnet.org.za/willy/
http://msdn2.microsoft.com/en-us/netframework/default.aspx
http://wcf.netfx3.com/
http://msdn.microsoft.com/webservices/
A Lap around Windows Communications Foundation - My Devdays WCF slides
IDesign - a variety of worthwhile WCF resources, including some WCF Coding Standards