Custom Message Handling with WCF (Part 2 of 2)

In part one, I introduced the concepts behind custom message handling in WCF. This post is all about showing these principles in code. Allow me to first introduce the service I will be working with, a slightly modified version of the service from the default Visual Studio WCF template:

[ServiceContract(Namespace = "https://lookingsharp.wordpress.com/demo/")]
public interface IMyService
{
    [OperationContract]
    CompositeType GetData(CompositeType composite);
}

[DataContract(Namespace = "https://lookingsharp.wordpress.com/demo/")]
public class CompositeType
{
    bool boolValue = true;
    string stringValue = "Hello ";

    [DataMember]
    public bool BoolValue
    {
        get { return boolValue; }
        set { boolValue = value; }
    }

    [DataMember]
    public string StringValue
    {
        get { return stringValue; }
        set { stringValue = value; }
    }
}

My ultimate goal for this post is to communicate with this service, without deserializing the response into a CompositeType object. This requires a custom WCF client, which I prefer to base on the code generated by the Svcutil tool. Running Svcutil against the metadata exposed by the service is done as follows:

C:\temp>Svcutil http://localhost:8731/MyServiceLibrary/MyService/mex
Microsoft (R) Service Model Metadata Tool
[Microsoft (R) Windows (R) Communication Foundation, Version 3.0.4506.2152]
Copyright (c) Microsoft Corporation.  All rights reserved.

Attempting to download metadata from 'http://localhost:8731/MyServiceLibrary/MyS
ervice/mex' using WS-Metadata Exchange or DISCO.
Generating files...
C:\temp\MyService.cs
C:\temp\output.config

C:\temp>

The service definition in MyService.cs generated by Svcutil is equivalent to this code (adjusted to fit the page):

[GeneratedCode("System.ServiceModel", "3.0.0.0")]
[ServiceContract(
    Namespace="https://lookingsharp.wordpress.com/demo/", 
    ConfigurationName="IMyService")]
public interface IMyService
{
    [OperationContract(
        Action="https://lookingsharp.wordpress.com/demo/IMyService/GetData", 
        ReplyAction="https://lookingsharp.wordpress.com/demo/IMyService/GetDataResponse")]
    CompositeType GetData(CompositeType composite);
}

The ConfigurationName property of the ServiceContract attribute refers to the name of the configuration generated in the output.config file.

Now, in order to prevent WCF from deserializing the response of this service, the return type of the GetData method must be Message, and the input parameter must be of type Message or of a type tagged with the MessageContract attribute. Message contracts are explained in the MSDN article “Using Message Contracts“.

According to the metadata of our service, requests are expected to have the following format:

<GetData xmlns="https://lookingsharp.wordpress.com/demo/">
	<composite>
		<BoolValue>True</BoolValue>
		<StringValue>SomeString</StringValue>
	</composite>
</GetData>

Mapping this request format to a WCF message contract is quite straight-forward. Simply reuse most of the CompositeType class generated by Svcutil and wrap it in a request class tagged with the MessageContract attribute, like this:

[MessageContract(
    WrapperName = "GetData",
    WrapperNamespace = "https://lookingsharp.wordpress.com/demo/")]
public class GetDataRequest
{
    [MessageBodyMember(
        Name = "composite",
        Namespace = "https://lookingsharp.wordpress.com/demo/")]
    public CompositeType Request { get; set; }
}

[DataContract(
    Name = "CompositeType",
    Namespace = "https://lookingsharp.wordpress.com/demo/")]
public class CompositeType
{
    [DataMember]
    public bool BoolValue { get; set; }

    [DataMember]
    public string StringValue { get; set; }
}

I can now modify the service contract generated by Svcutil to accept GetDataRequest objects as input and produce Message objects as output. This results in the following definition:

[ServiceContract(
    Namespace = "https://lookingsharp.wordpress.com/demo/",
    ConfigurationName = "IMyService")]
public interface IMyService
{
    [OperationContract(
        Action = "https://lookingsharp.wordpress.com/demo/IMyService/GetData",
        ReplyAction = "https://lookingsharp.wordpress.com/demo/IMyService/GetDataResponse")]
    Message GetData(GetDataRequest request);
}

As for implementing the actual WCF client, I simply inherit ClientBase<IMyService> and delegate requests to base.Channel:

public class MyServiceClient : ClientBase<IMyService>, IMyService
{
    public Message GetData(GetDataRequest request)
    {
        return base.Channel.GetData(request);
    }
}

By default, this client will use the configuration specified by IMyService. I copy the relevant content of the output.config file generated by Svcutil into my project’s app.config file.

That is it. A console application’s Main method using this client could like like this:

static void Main(string[] args)
{
    var client = new MyServiceClient();
    var request = new GetDataRequest
    {
        Request = new CompositeType
        {
            BoolValue = true,
            StringValue = "Hello "
        }
    };
    var response = client.GetData(request);

    Console.WriteLine(response.ToString());
    Console.ReadLine();
}

Feel free to download the complete source code for this post. (Note that the service requires administrative privileges.)

2 thoughts on “Custom Message Handling with WCF (Part 2 of 2)

Leave a comment