Default Message Contract

The Default Message Contract sample demonstrates a service where a custom user-defined message is passed to and from service operations. This sample is based on the Getting Started that implements a calculator interface as a typed service. Instead of the individual service operations for addition, subtraction, multiplication, and division used in the Getting Started, this sample passes a custom message that contains both the operands and the operator, and returns the result of the arithmetic calculation.

The client is a console program (.exe) and the service library (.dll) is hosted by Internet Information Services (IIS). Client activity is visible in the console window.

Note

The setup procedure and build instructions for this sample are located at the end of this topic.

In the service, a single service operation is defined that accepts and returns custom messages of type MyMessage. Although in this sample the request and response messages are of the same type, they could of course be different message contracts if necessary.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
    [OperationContract(Action="http://test/MyMessage_action",
                  ReplyAction="http://test/MyMessage_action")]
    MyMessage Calculate(MyMessage request);
}

The custom message MyMessage is defined in a class annotated with MessageContractAttribute, MessageHeaderAttribute and MessageBodyMemberAttribute attributes. Only the third constructor is used in this sample. Using message contracts allows you to exercise full control over the SOAP message. In this sample, the MessageHeaderAttribute attribute is used to put Operation in a SOAP header. The operands N1, N2 and the Result appear within the SOAP body because they have the MessageBodyMemberAttribute attribute applied.

[MessageContract]
public class MyMessage
{
    private string operation;
    private double n1;
    private double n2;
    private double result;

    //Constructor - create an empty message.

    public MyMessage() {}

    //Constructor - create a message and populate its members.

    public MyMessage(double n1, double n2, string operation,
                     double result)
    {
        this.n1 = n1;
        this.n2 = n2;
        this.operation = operation;
        this.result = result;
    }

    //Constructor - create a message from another message.

    public MyMessage(MyMessage message)
    {
        this.n1 = message.n1;
        this.n2 = message.n2;
        this.operation = message.operation;
        this.result = message.result;
    }

    [MessageHeader]
    public string Operation
    {
        get { return operation; }
        set { operation = value; }
    }

    [MessageBodyMember]
    public double N1
    {
        get { return n1; }
        set { n1 = value; }
    }

    [MessageBodyMember]
    public double N2
    {
        get { return n2; }
        set { n2 = value; }
    }

    [MessageBodyMember]
    public double Result
    {
        get { return result; }
        set { result = value; }
    }
}

The implementation class contains the code for the Calculate service operation. The CalculateService class obtains the operands and operator from the request message and creates a response message that contains the result of the requested calculation, as shown in the following sample code.

// Service class which implements the service contract.
public class CalculatorService : ICalculator
{
    // Perform a calculation.

    public MyMessage Calculate(MyMessage request)
    {
        MyMessage response = new MyMessage(request);
        switch (request.Operation)
        {
            case "+":
                response.Result = request.N1 + request.N2;
                break;
            case "-":
                response.Result = request.N1 - request.N2;
                break;
            case "*":
                response.Result = request.N1 * request.N2;
                break;
            case "/":
                response.Result = request.N1 / request.N2;
                break;
            default:
                response.Result = 0.0D;
                break;
        }
        return response;
    }
}

The generated client code for the client was created with the ServiceModel Metadata Utility Tool (Svcutil.exe) tool. The tool automatically creates message contract types in the generated client code if necessary. The /messageContract command option may be specified to force the generation of message contracts.

svcutil.exe /n:"http://Microsoft.ServiceModel.Samples,Microsoft.ServiceModel.Samples" /o:client\generatedClient.cs http://localhost/servicemodelsamples/service.svc/mex

The following sample code demonstrates the client using the MyMessage message.

// Create a client with given client endpoint configuration
CalculatorClient client = new CalculatorClient();

// Perform addition using a typed message.

MyMessage request = new MyMessage()
                    {
                        N1 = 100D,
                        N2 = 15.99D,
                        Operation = "+"
                    };
MyMessage response = ((ICalculator)client).Calculate(request);
Console.WriteLine("Add({0},{1}) = {2}", request.N1, request.N2, response.Result);

When you run the sample, the calculations are displayed in the client console window. Press ENTER in the client window to shut down the client.

Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714

Press <ENTER> to terminate client.

At this point, custom user-defined messages have passed between the client and the service operation. The message contract defined that the operands and results were in the message body and that the operator was in a message header. Message logging can be configured to observe this message structure.

To set up, build, and run the sample

  1. Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.