Over a million developers have joined DZone.

Wcf with WS-Addressing March 2004

·

Wcf supports two WS-Addressing versions – the August 2004 draft and the actual standard v 1.0. There is another wsa version which is used by some soap stacks (who said wse 2?) – the march 2004 draft. To turn this fact to a more practical  problem, you might need to write a wcf client to a (non Wcf) service which expects a request like this:

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing">

  <Header>

    <wsa:Action>http://myAction</wsa:Action>
    <wsa:MessageID>uuid:5024616c-d0r2-56h3-bjj7-ab10p89eee63</wsa:MessageID>
    <wsa:ReplyTo>
      <wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
    </wsa:ReplyTo>
    <wsa:To>http://server/Calc</wsa:To>
... 

(note the bold wsa version – wcf cannot emit it).

One straight forward way to do this with wcf is to push these headers to the soap using a message inspector. But what if you also need to sign the wsa headers with a digital signature?In this case you need to write a custom behavior which push the wsa headers to the IncomingSignatureParts property. The whole code looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Security;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using MyApplication.ServiceReference1;

namespace MyApplication
{

    public class SignMessageHeaderBehavior : Attribute, IEndpointBehavior
    {

        string action;

        List<XmlQualifiedName> headers;



        public SignMessageHeaderBehavior(List<XmlQualifiedName> headers, string action)
        {

            this.headers = headers;            

            this.action = action;

        }

        public void Validate(ServiceEndpoint endpoint)
        {

        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            var requirements = bindingParameters.Find<ChannelProtectionRequirements>();

            foreach (var h in headers)
            {                
                var part = new MessagePartSpecification(h);
                requirements.IncomingSignatureParts.AddParts(part, action);
            }
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {

        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {

            clientRuntime.MessageInspectors.Add(new AddHeaderMessageInspector());

        }

    }

    [DataContract(Namespace="http://schemas.xmlsoap.org/ws/2004/03/addressing")]
    public class ReplyToHeader
    {        
        [DataMember]
        public string Address { get; set; }
    }


    public class AddHeaderMessageInspector : IClientMessageInspector
    {

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {

            request.Headers.Add(MessageHeader.CreateHeader("Action", "http://schemas.xmlsoap.org/ws/2004/03/addressing", "http://myAction"));
            request.Headers.Add(MessageHeader.CreateHeader("MessageID", "http://schemas.xmlsoap.org/ws/2004/03/addressing", "uuid:5024616c-d0r2-56h3-bjj7-ab10p89eee63"));
            request.Headers.Add(MessageHeader.CreateHeader("ReplyTo", "http://schemas.xmlsoap.org/ws/2004/03/addressing", new ReplyToHeader() { Address = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous" }));
            request.Headers.Add(MessageHeader.CreateHeader("To", "http://schemas.xmlsoap.org/ws/2004/03/addressing", "http://server/Calc"));
            

            return request;

        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {

        }

    }

    class Program
    {

        static void Main(string[] args)
        {

            var c = new SimpleServiceSoapClient();

            var headers = new List<XmlQualifiedName>();
            headers.Add(new XmlQualifiedName("Action", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));
            headers.Add(new XmlQualifiedName("MessageID", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));
            headers.Add(new XmlQualifiedName("ReplyTo", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));
            headers.Add(new XmlQualifiedName("To", "http://schemas.xmlsoap.org/ws/2004/03/addressing"));

           c.Endpoint.Behaviors.Add(
                new SignMessageHeaderBehavior(headers, "http://tempuri.org/EchoString"));

            c.EchoString("123");

        }
    }
}

 

Topics:

Published at DZone with permission of Yaron Naveh, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}