Windows Communication Foundation (Indigo) Hello World Tutorial - Hilton Giesenow's Jumbled Mind

Hilton Giesenow's Jumbled Mind

the madness that is...

News

This is my little spot in cyberspace where you will find a collection of random (but mostly software-related) thoughts and ideas that are frightening in their shining brilliance (or something like that ;->).
 
Please enjoy your stay and feel free to Contact Me.
 
Microsoft MVP

.Net Links

BlogRoll

Misc. Links

Syndication

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

Posted: Feb 06 2006, 08:16 PM by hiltong | with 39 comment(s)
Filed under:

Comments

Hilton Giesenow's Jumbled Mind said:

Building on our look at the ServiceContract and DataContract attributes, we round off our look at the essential contract work in WCF using the MessageContract attribute.
# June 19, 2006 10:41 PM

Hilton Giesenow's Jumbled Mind said:

Whew, I finally managed to bash out the 3rd tutorial in my WCF series. It's taken me&amp;nbsp;a while to...
# June 19, 2006 10:49 PM

OS said:

I implemented the tutorial and everything works but it takes 27 seconds (seriously) to execute the SayHello Method. Why does this take so long?
# October 13, 2006 7:03 PM

hiltong said:

I've been playing with some of this stuff again recently, and I've also noticed the latest builds are _considerably_ slower than it used to be. I'll see if I can find anything...

# November 1, 2006 12:39 PM

Jeff said:

I think you're missing a space: needs to be ------ I'm getting a "The type 'HG.RnD.WinFX.WCF.HelloWorld', provided as the Service attribute value in the ServiceHost directive could not be found." error message. My DLL in the Bin folder does have the correct namespace and type (they appear in intellisense when I reference the DLL.) Any idea of what I've done wrong?
# December 5, 2006 6:11 PM

hiltong said:

Good spotting, Jeff. I'm updating the tuts at the moment (for the last time, finally) for RTM. The first should be done in a couple of days. Where are you seeing them in the intellisense (in what file)

# December 5, 2006 7:24 PM

Jeff said:

I die at the "OK, all being well" point of the tutorial. The only thing I know that I did different was to compile the code from VS.Net-- the command line compile wasn't cooperating. Opening a new throwaway project and adding the DLL as a reference, typing "HG." triggers intellisense and I can get to HelloWorld properly. I just tried implementing MSDN's Calculator tutoral-- it's giving me a "Parser Error Message: The required directive 'ServiceHost' is missing." Trying to set up the same project from the WCF Samples gives me a "The type 'Microsoft.ServiceModel.Samples.CalculatorService', provided as the Service attribute value in the ServiceHost directive could not be found." Looks like I'm doing the same wrong dumb thing there.... Wait a second... I just pulled the C# version of Calculator into VS.Net 2005. Compiled... then copied the entire project/folders/everything into inetpub. Calling the service from the web browser now brings up the right response. (I think I neglected to copy a file over when I got that last error I mentioned.) This is an improvement! _Something_ works. Now... to try to get your tutorial to run the same....
# December 5, 2006 8:59 PM

Jeff said:

Okay... one step forward, two steps back: I can compile from the command line now, but I had to reference the full path to the System.ServiceModel.dll like this: csc.exe /r:"C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\System.ServiceModel.dll" /out:"C:\InetPub\WWWRoot\WCFHelloWorld\Service\Bin\HelloWorld.dll" /t:library "c:\InetPub\WWWRoot\WCFHelloWorld\Service\*.cs" So I do the following steps: 1) Create the directories in inetpub and set the properties through IIS 2) Compile the two .cs files to the bin folder 3) Put the .svc and web.config files in the Service folder. When I try to call the service from a web browser, I get the following error: The type 'HG.RnD.WinFX.WCF.HelloWorld', provided as the Service attribute value in the ServiceHost directive could not be found.
# December 7, 2006 10:18 PM

hiltong said:

Can you give me a better picture of what your folder structure looks like? It should be something like:

wwwroot\WCFHelloWorld\Service\[whatever].svc

wwwroot\WCFHelloWorld\Service\web.config

wwwroot\WCFHelloWorld\Service\bin\

wwwroot\WCFHelloWorld\Service\bin\[assembly].dll

Also, this might be easier by mail rather?? Just use the Email link at the top.

# December 8, 2006 3:12 AM

Jeff said:

I got it working now! After verifying that the folder stuctures were correct, I tried it again... and today I get a new error message stating that I needed to beef up my web config file. (I suspected yesterday that some sort of caching was going on-- the page wasn't 'thinking' about the request.) Anyways, after adding in a 'Behavior' with serviceMetadata httpGetEnabled="true", I get to the next stage! Time to run svcutil.exe! Woo hoo! I don't appear to be able to post code here, so I'll email it to you if you like. (BTW, your email page doesn't seem to be accepting posts-- either that or you have 5 emails on the way!!)
# December 8, 2006 4:12 PM

hiltong said:

Glad it's working! The metadata stuff is what I'm updating the tut with right now (as I'm typing this, in fact). I didn't get any emails, btw, but I'll look into the problem, thanks.

# December 8, 2006 5:03 PM

Jeff said:

Doh! I got svcutil to run... but it does not make Proxy methods-- I get Client methods instead. (HelloWorldClient instead of HelloWorldProxy for example.) It could be that my altered config file is incorrect. Here's my config file with parens instead of '>' and '<' signs: (?xml version="1.0" encoding="utf-8" ?) (configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0") (system.serviceModel) (services) (service name="HG.RnD.WinFX.WCF.HelloWorld") (endpoint address="" binding="basicHttpBinding" contract="HG.RnD.WinFX.WCF.IHelloWorld" /) (/service) (/services) (/system.serviceModel) (/configuration) It is unclear to me what you mean by "The only change I made to this generated class was to add the .net (not xml) namespace I used above 'HG.RnD.WinFX.WCF')." I've tried compiling various files-- the non-asynchronos version of mine, your codefiles as posted, etc. but they won't do it. If I change the method name of the client to call the generated method instead of the Proxy method, then that compiles, but when it runs I get: C:\Inetpub\wwwroot\WCFHelloWorld\Client>consolehelloworld Unhandled Exception: System.InvalidOperationException: Could not find default en dpoint element that references contract 'IHelloWorld' in the ServiceModel client configuration section. This might be because no configuration file was found fo r your application, or because no endpoint element matching this contract could be found in the client element. at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceE ndpoint serviceEndpoint, String configurationName) at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configuration Name) at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configuration Name, EndpointAddress address) at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationNam e, EndpointAddress remoteAddress) at System.ServiceModel.ClientBase`1..ctor() at WCFHelloWorldClient.Program.Main(String[] args) I renamed the generated config file to "app.config" but it isn't being picked up. I'm running .Net 3.0 on Windows XP. :(
# December 8, 2006 5:05 PM

hiltong said:

ah, that could be the problem - the config needs to sit in the same folder as the client exe, and have the same name, e.g.:

HelloWorldClient.exe needs a HelloWorldClient.exe.config. Try renaming again and see if it works?

# December 8, 2006 5:13 PM

Shannon Sellers said:

Thanks for putting this together. I am just starting trying to get my head around WCF, and was starting to think my head was not big enough. After finding some of my dumb mistakes, like "}" out of place, it worked as advertised! Thanks again for your efforts.
# December 24, 2006 8:27 PM

hiltong said:

Glad it worked, and thanks for the feedback! It takes a while to put one of these together so it's good to hear it's of value.

# December 25, 2006 11:57 AM

Jim White said:

After you build the application, you say "All being well...", and the app runs in the browser! Is there a big piece of the puzzle missing here? How did you go from a class library under C:\... to hosting under asp.net. I am sorry if I missed something.
# December 26, 2006 3:03 AM

Jim White said:

Oops. Please ignore my previous comments. I missed the part about the new web service project. My bad. Works like a charm!
# December 26, 2006 3:09 AM

Hilton Giesenow's Jumbled Mind said:

Following some emails and comments, I&#39;ve updated tutorial 1 in the WCF Hello World series to RTM

# December 26, 2006 10:54 AM

Jason Bock said:

I think your metadata images from the web application are transposed; they should be switched around.

# January 17, 2007 4:26 PM

hiltong said:

Well spotted, Jason, thanks. I've updated accordingly.

# January 17, 2007 4:48 PM

Kyle said:

I'm getting the following error and can't figure out why:

The type 'WCFLastTry.ServiceLayer.HelloWorldService', provided as the Service attribute value in the ServiceHost directive could not be found

I saw that someone else was getting the same or similar error but I couldn't figure out form the posts what the problem was.

Thanks

# January 19, 2007 6:56 PM

hiltong said:

Hi Kyle,

Confirm that both the class name and namespaces are absolutely identical between the various files. There are a bunch of different places that the fully-qualified name goes, and I've mis-typed them a few times, as some more astute readers have noticed (thanks Andrew).

# January 30, 2007 11:07 PM

AndreB said:

Thanks for the tutorial. I'm always looking out for "bare essentials" in walkthroughs and this one is great stuff. Looking forward in anticipation for the follow-up. Just a note: the version on the svcutil that I've got (3.0.4506.30) takes "out:" as parameter and not "output:".

# February 1, 2007 11:54 AM

Shashi said:

The type 'DerivativesCalculatorService.Calculator', provided as the Service attribute value in the ServiceHost directive could not be found.

I have also added

<behaviors>

     <serviceBehaviors>

       <behavior name="MyServiceTypeBehaviors">

         <serviceMetadata httpGetEnabled="true"/>

       </behavior>

     </serviceBehaviors>

   </behaviors>

to the web.config file but this does not help

# February 20, 2007 1:40 PM

hiltong said:

For the first part, make sure you have the service available to the markup in the svc file. Is the service in an external assembly, as in my examples here? If so, make sure it is refenced by the project and therefore contained in the bin folder. If it is part of the web project itself, you need to set the CodeBehind property in the '<%@ ServiceHost' tag, e.g. CodeBehind="~/App_Code/Service.cs", instead of the 'Service' property.

For the 2nd part - what exactly are you trying to do? View the metadata? If so, make sure you have set the 'behaviorConfiguration' property in the 'service' element, as well as have the 2nd 'IMetadataExchange' endpoint element defined within the 'service' element.

Hope that helps!

Hilton

# February 20, 2007 2:36 PM

hiltong said:

One more point on the 1st part - make sure if the service class is in an external assembly that you get the full class and namespace correct.

# February 20, 2007 2:37 PM

Barry said:

Great tutorial!  Being new to services I tried a few including the ones on the Microsoft site with no success.  This one worked the first time.  Thanks!

# March 10, 2007 6:21 AM

Selva said:

Very good tutorial for wcf beginners.

# May 25, 2007 11:34 AM

Manoj Chavan said:

Can we define two [DataContract] in WCF Interface? If not what's the alternative?

# February 1, 2008 10:11 PM

hiltong said:

I'm not sure what you mean? Do you mean you want to return 2 different domain objects from the web method? Have you had a look at the 3rd article in the series at dotnet.org.za/.../windows-communication-foundation-tutorial-part-3-messaging-messagecontracts.aspx ? I think it will cover what you need.

Hilton

# February 4, 2008 6:02 PM

SomeOne said:

I just realized that if I coppied from an article the quotes for the Service.svc where what some calls the apple quotes not this " but the other kind. I can't even find on the keyboard.

When I edit the file in VS2008 it looked to be italic but it was the wrong quote.

Doing the internet search I find that there is a dumb quote and a smart quote.

“smart quotes”

"dumb quotes"

Whatch it. Because this my be one of those wierd bugs that gets fixed because on coppies and paste again but with dumb quotes.

# February 5, 2008 6:24 PM

Jos said:

It's a great tutorial and with me, it worked from the first time. But what I fail to understand is what is the advantage of WCF compared to the use of a classic asmx web service? The amount of code is about the same.

# February 10, 2008 4:23 PM

hiltong said:

Thanks Jos for the feedback. Depending on what you're trying to do, the code may very be the same. However, there are a number of _very important_ benefits that WCF offers over classic ASMX, and it's definitely worth finding out more about them. Very briefly, WCF offers:

1) a unified programming model. I've worked on systems where we need to provide an 'endpoint' (basically an API) in asmx, .net remoting, and msmq. Each one took a fair amount of time on it's own with dev, testing, maintenance, etc. With WCF, offering multiple interfaces over multiple technologies is literally just adding more lines to the config file.

2) Baked-in SOA support. If you're aiming for real SOA-type services, WCF offers considerably more support through the programming model. Tutorial 2 in this series will help build on your knowledge or serializing advanced types, but look into tutorial 3 (at dotnet.org.za/.../53552.aspx) to see more about messagecontracts, for instance, and what they do. In essence, message-based programming and aspects like versioning are made easier

3) Built-in support for WS-* specs. Following on from point 2, adding security and reliable messaging was a considerable undertaking in ASMX. This was easier with  the WSE extensions, but these were always an interim solution. The WS-* specs are now baked in to WCF, in large part just in the config file. For instance, coverting your service via the binding in the config to instantly turn on reliability and security is one single change. It was like 50 000+ lines in asmx 1.x!

I haven't given too many resources or pointers as this was just a quick post on some info. If you're interested, there is plently available on the net and I can give some more pointers if you need.

# February 10, 2008 4:58 PM

Bilbo said:

This is a wonderful tutorial for a beginner like me. I was able to get through it with no errors in your explanations or code except maybe one minor one. The proxy in the client (if I'm saying it right) was generated with a namespace of "TestConsole.HelloWorldService" but your code that uses the proxy (Program.cs in mine) is using TestClient.HelloWorldService. Am I missing something? Anyway thanks for the great tutorial and I'm going on to Part 2.

# March 7, 2008 6:47 PM

hiltong said:

Hi Bilbo,

Thanks for the feedback, and well spotted! The project should indeed be called TestClient as well, I'm making the edit at the moment. Incidentally, there are some small changes in the 2008/v3.5 version of WCF, so I'm hoping to put some material together soon. Thankfully, the changes all make things even easier.

Enjoy the series,

Hilton

# March 11, 2008 6:49 AM

Stephen said:

When I compile the web service and run it it tells me the assembly for ServiceLayer cannot be found!

# April 8, 2008 4:54 PM

Georgina said:

I had real problems getting the .svc to recognise the service. It's worth noting that the solution was to put