Wcf with WS-Addressing March 2004
Join the DZone community and get the full member experience.
Join For FreeWcf 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"); } } }
Published at DZone with permission of Yaron Naveh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments