metadevblog

Windows Phone 7 App Development

WCF–Service Behaviours, Bindings and Contracts

leave a comment »

WCF is now a very mature technology and one that I have used a great deal over the last few years, in fact it has been core to most of my recent work both professionally and with personal development projects.

I can’t however be the only one to have struggled with getting the triumvirate of behaviours, bindings and contracts to work together when creating a web service without at least tearing some of my hair out.

I don’t know if there is something different in WCF 4.0 or its just ‘clicked’ for me finally but I managed to create two web services in a hurry last night and get them working by actually understanding the XML.  So while it is still fresh in my mind I’m going to write it down…

One of the pitfalls with using WCF is the number of different parts that need to be created before it can be tested end to end.  There are also some ‘gotchas’ that need to be avoided along the way.

Exposing data via WCF requires a data service.  I typically use XML for both sending and receiving data to/from services, so before any description of setting up WCF can be given it is first of all necessary to create a data service that will provide some information.

The data service is a pre-requisite because WCF binds to a service interface that will be exposed at the service endpoint (an example HTTP service endpoint is http://localhost:1234/DataService which will be described below).

In order to expose the service endpoint the service provider is hosted within a ServiceHost object.  ServiceHost is a core windows technology that is also a core part of IIS.  ServiceHost can be hosted within any persistent application, even a console application, but it provides excellent functionality when used with a Windows Service.

I have used Visual Studio 2010 and .NET 4.0, all the code is in c#.

The first part of this article will cover the creation of the data service provider.  The configuration of the service will follow and then I will create a simple application to access the service.

The next part of this article to follow will add another service so that Silverlight can be used to access the data service.

ConsoleApplicationWCF.sin


Create a new console application in VS2010; make sure you call it ConsoleApplicationWCF.

IDataService.cs


Add a new class called IDataService.cs and then paste this code in (you will probably get some errors reported which can be cleared by adding System.XML.Linq.dll and System.ServiceModel.dll to the projects references)

using System.ServiceModel;
using System.Xml.Linq;

namespace ConsoleApplicationWCF
{
    [ServiceContract]
    public interface IDataService
    {
        [OperationContract]
        XElement GetDateTime();
    }
}

This will create the DataService interface which will be referenced in the WCF service endpoint contract as ConsoleApplicationWCF.IDataService.  Note that it is necessary to include the namespace when identifying the endpoint in the definition.

The [ServiceContract] and [OperationsContract] are code decorations that are used during compilation to build the service interface.  The [ServiceContract] decoration identified IDataService as the contract that will be used in the service definition.  The [OperationContract] will allow the GetDataTime() method to be accessed via the service.

DataService.cs

Add a new class called DataService.cs and then paste in this code to implement the interface.  Notice that the service is returning a Linq XElement.

using System;
using System.Xml.Linq;

namespace ConsoleApplicationWCF
{
    public class DataService : IDataService
    {
        public XElement GetDateTime()
        {
            XElement result = new XElement("Data");
            result.Add(new XElement("Date", DateTime.Now.Date.ToString()));
            result.Add(new XElement("Time", DateTime.Now.TimeOfDay.ToString()));

            return result;
        }
    }
}

Program.cs

Now replace the Program.cs stub code that was generated when the project was created with this code:

using System; 
using System.ServiceModel; 
namespace ConsoleApplicationWCF 
{ 
    class Program 
    { 
        private static ServiceHost dataService;

        static void Main(string[] args) 
        { 
            try 
            { 
                dataService = new ServiceHost(typeof(DataService)); 
                dataService.Open(); 
            } 
            catch (Exception e) 
            { 
                Console.WriteLine("Unable to start DataService:" + e.ToString()); 
            }

            Console.WriteLine("Service started at http://localhost:1234/DataService"); 
            Console.ReadLine();
        } 
    } 
} 

The WCF DataService is hosted directly in the Console by ServiceHost. When implementing this within a Windows Service the code can be pretty much lifted verbatim and put into the OnStart event which will then start the WCF DataService when the Windows Service starts.

 

App.config

The key to getting WCF to work is a correct service configuration file.  Add an empty App.config file to the project and then paste the following XML into the file.  This configuration is about as simple as can be defined for a basic HTTP data service.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DataServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="DataServiceBehavior" name="ConsoleApplicationWCF.DataService">
        <endpoint address="" binding="basicHttpBinding" contract="ConsoleApplicationWCF.IDataService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/DataService" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>


The actual WCF definition is within the <system.serviceModel> element but it is being wrapped within a <configuration> element that is used by App.Config which the console application can access directly as part of its implementation structure.

The <system.serviceModel> element contains two main regions which allow for multiple <behaviours> and <services> to be defined.  The <behaviour> define how a <service> will function.

The service <behaviour> for a WCF data service requires that httpGet is enabled.  I also enable includeExceptionDetailInFaults on the basis that you can never have too much information about what has gone wrong and you can always switch it off later.

Creating the <service> itself is usually where it all goes wrong as there are so many parts to it; any one of which will cause an error (or worse no service).

The <service> element contains one or more <endpoint> elements and a <host> element.

<service>   
  <endpoint />   
  <host /> 
</service>

Note that a service can have multiple endpoint definitions.  This is important as the endpoints provide different data depending on their configuration.

The service behaviour uses the behaviourConfiguration to map a behaviour to the service using the behaviour attribute name.

<behavior name="DataServiceBehavior"> 
<service behaviorConfiguration="DataServiceBehavior"  …

The name of the service should be the same as the name in the interface and should include the namespace.

<service behaviorConfiguration="DataServiceBehavior" name="ConsoleApplicationWCF.DataService">

The service exposes two endpoints one is used to access the data, the other is used get the metadata that describes the service.  This second service is vital as it simplifies the whole process of making use of the service by auto-generating a while bunch of plumbing files that hide away most of the complexity of WCF.

The first <endpoint> is for the data service.  It is exposing the service as HTTP and it is using the IDataService contract that has been defined. The namespace should be used in the definition of the contract.

<endpoint address="" binding="basicHttpBinding" contract="ConsoleApplicationWCF.IDataService">

The dns specifies “localhost”.  This is perfectly valid but it should not be confused with using the name of your machine.  You should change both the dns and the actual endpoint if you want to use a machine name.

The second endpoint is for getting the service metadata that will be used to generate the WCF service support files in a client application.  The service metadata can be accessed by invoking the service endpoint in a browser along with the ?wsdl parameter (the parameter triggers access to the MEX endpoint).  Eg

http://localhost:1234/DataService?wsdl

Finally the address of the service can be defined.  I tend to use the same name as the service contract for my services and also leave them open ended – ie no terminating /

That’s about it for this posting.  The code should compile and run and will show the following console:

image

Written by metadevblog

March 23, 2011 at 9:22 am

Posted in WCF

Tagged with ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: