Introduction to WCF - Part 3 - WCF Tools

03 May 2011

WCF Service Configuration Editor

Visual Studio 2010 and the .NET 4 Framework provide a number of productivity utilities related to WCF. We've already encountered the Service Model Metadata Tool (svcutil.exe) a command-line tool which is used by Visual Studio's Add Service Reference to create a proxy from a WCF service's metadata. If required, the developer can also use svcutil.exe directly from the command-line if additional control of proxy creation is required.

The Service Configuration Editor provides a GUI-based approach to the creation and modification of the app.config files used to configure WCF services. To review how useful this tool can be, we'll add a new WCF host console application project to the existing HelloService solution.

  1. Open the WCF service host console application (e.g. the HelloService solution) we created in part 2
  2. Add another console application project (name it Host2)
  3. Add a reference to System.ServiceModel
  4. Add a reference to the HelloService project
  5. Open Program.cs and modify it as follows:
  6. using System.ServiceModel;
    using System.ServiceModel.Description;
    
    namespace Host2
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (ServiceHost host = new ServiceHost(typeof(HelloService.Hello)))
                {
                    host.Open();
    
                    Console.WriteLine("Service (Host2) running. [Enter] to close");
                    Console.ReadLine();
    
                    host.Close();
                }
            }
        } 
    }
    

  7. Select the Host2 project in Solution Explorer then select Tools | WCF Service Configuration Editor:
  8. The editor is displayed. Create a new (empty) app.config file by selecting File | New Config (Ctrl+N)
  9. Save the configuration file by selecting File | Save As - name the file app.config, and make sure the file is saved in the root directory of the Host2 project
  10. Close the editor and note that the app.config is not added to the project - to manually add it, right-click Host2 and select Add Existing Item. Browse to the app.config file and add it to the project
  11. If you open the app.config file you’ll see it contains the following:
  12. Right-click the app.config file and select Edit WCF Configuration
  13. First, create a New Service using the New Service Element Wizard:
  14. The editor needs to know the type of the service. You can either type HelloService.Hello (notice at this point the editor wants the CLR type, not the interface) or (which saves typo's) you can browse for the assembly containing the type - browse to HelloService.dll and open it:
  15. Once you open the assembly in the Type Browser the dialog will show you the interface(s):
  16. Select the appropriate interface and click Open
  17. Click Next >. The next page allows you to select the correct service contract:
  18. Click Next >. Select the desired binding - select HTTP and click Next >:
  19. Select the appropriate level of interop required (Advanced (which supports WCF) for our example) or Simplex (one-way) communication. Then click Next >:
  20. If required, provide the address for the service - here we'll leave the address field empty (we'll supply as base address later). Click Next >
  21. The wizard summarizes the configuration – click Finish to complete the process
  22. Save the changes to the app.config file, then switch back to the 'raw' view of the file in Visual Studio. You should see something like the following has been created:
  23. <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <system.serviceModel>
            <services>
                <service name="HelloService.Hello">
                    <endpoint 
                        address="" 
                        binding="ws2007HttpBinding"
                        bindingConfiguration="" 
                        contract="HelloService.IHello" />
                </service>
            </services>
        </system.serviceModel>
    </configuration>
    

  24. Switch back to the configuration editor, expand the HelloService.Hello node and select Host:
  25. Click the New button to add a base address for the service - set the address to be http://localhost:9002:
  26. Expand the Endpoints collection node for the service and provide a name for the service (e.g. HttpBinding):
  27. Review the Binding we created. Notice that the binding is set to ws2007HttpBinding, whereas the binding created automatically for our other host was wsHttpBinding:
  28. We now need to create a metadata exchange endpoint (if we don't, clients will not be able to retrieve the information necessary for proxy creation). Right-click the Endpoints node and select New Service Endpoint
  29. Create the endpoint as follows:
  30. Finally, we need to add a couple of service behaviours for Mex and Debug. Expand the Advanced node, right-click on Service Behaviours and select New Service Behaviour Configuration:
  31. Gotcha Warning!

    When you create the new set of behaviours the WCF configuration editor will name it "NewBehavior0". It's important that you remove this name and make it an empty string. If you don't you’ll get an exception:

    System.InvalidOperationException: The contract name 'IMetadataExchange' could not be found in the list of contracts implemented by the service Hello. Add a ServiceMetadataBehavior to the configuration file or to the ServiceHost directly to enable support for this contract.

    So, this works fine:

    <behavior name="">
      <serviceMetadata httpGetEnabled="true" />
    </behavior>
    

    But this causes the host to throw an exception:

    <behavior name="NewBehavior0">
      <serviceMetadata httpGetEnabled="true" />
    </behavior>
    

  32. Add serviceDebug and serviceMetadata behaviors:
  33. Select serviceMetadata and set the following properties:
  34. Select serviceDebug and set the following properties:
  35. Save the changes and close the editor. The app.config file should now look similar to the following:
  36. <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <system.serviceModel>
            <behaviors>
                <serviceBehaviors>
                    <behavior name="">
                        <serviceMetadata httpGetEnabled="true" />
                        <serviceDebug includeExceptionDetailInFaults="true" />
                    </behavior>
                </serviceBehaviors>
            </behaviors>
            <services>
                <service name="HelloService.Hello">
                    <endpoint address="" 
                              binding="ws2007HttpBinding" 
                              name="HttpBinding" 
                              contract="HelloService.IHello" />
                    <endpoint address="mex" 
                              binding="mexHttpBinding" 
                              name="MexHttpBinding" 
                              contract="IMetadataExchange" />
                    <host>
                        <baseAddresses>
                            <add baseAddress="http://localhost:9002" />
                        </baseAddresses>
                    </host>
                </service>
            </services>
        </system.serviceModel>
    </configuration>
    

  37. We're now ready to test service Host2. Set Host2 to be the only start-up project and run the solution
  38. Now try adding a Service Reference to Host2 to the Client application. You should find it works exactly as with our previous example
  39. Also, try accessing the service using a browser at http://localhost:9002:

Simplified Configuration

In .NET 4 you can take advantage of simplified configuration. All services are provided with default endpoints for each protocol (these are defined in the <protocolMapping> section of machine.config).

For example, the following configuration works in .NET 4:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <system.serviceModel>
            <services>
                <service name="HelloService.Hello">
                    <host>
                        <baseAddresses>
                            <add baseAddress="http://localhost:9003" />
                        </baseAddresses>
                    </host>
                </service>
            </services>
        </system.serviceModel>
    </configuration>
    

Notice that we simply define a base address - no endpoints, behaviours, etc. We can use the same hosting code as with previous hosts:

    using System.ServiceModel;
    using System.ServiceModel.Description;
    
    namespace HostSimpleConfig
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (ServiceHost host = new ServiceHost(typeof(HelloService.Hello)))
                {
                    host.Open();
    
                    Console.WriteLine("Service (Host3) running. [Enter] to close");
                    Console.ReadLine();
    
                    host.Close();
                }
            }
        } 
    }
    

However, if you access the service via a browser you get:

.NET 4 also provides default MEX behaviour configuration. To enable mex, simple add the following to the app.config file - note that they key thing is NOT to provide a name for the behaviour (otherwise you’ll have to provide the long-hand configuration suggested by the service host help-text shown in the browser above):

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <system.serviceModel>
            <services>
                <service name="HelloService.Hello">
                    <host>
                        <baseAddresses>
                            <add baseAddress="http://localhost:9003" />
                        </baseAddresses>
                    </host>
                </service>
            </services>
    
            <behaviors>
              <serviceBehaviors>
                <behavior>
                  <serviceMetadata httpGetEnabled="true" />
                </behavior>
              </serviceBehaviors>
            </behaviors>
          
        </system.serviceModel>
    </configuration>
    

This concludes part two of our introduction to WCF. In part four we'll take a look at working with non-HTTP bindings.