Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Wcf with WS-Addressing March 2004

DZone's Guide to

Wcf with WS-Addressing March 2004

·
Free Resource

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 DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

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

X

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

{{ parent.tldr }}

{{ parent.urlSource.name }}