Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I had to do something like this recently and what I ended up doing was creating a behaviour that implemented <code>IClientMessageInspector</code> and used the <code>BeforeSendRequest</code> method to create data for my header and then populate it into the SOAP request.</p> <pre><code>public class SoapHeaderBehaviour : BehaviorExtensionElement, IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { } public object BeforeSendRequest(ref Message request, IClientChannel channel) { var security = new Security(); // details irrelevant var messageHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", security, new ConcreteXmlObjectSerializer(typeof(Security)), true); request.Headers.Add(messageHeader); return null; } protected override object CreateBehavior() { return new SoapHeaderBehaviour(); } public override Type BehaviorType { get { return GetType(); } } } </code></pre> <p>ConcreteXmlObjectSerializer is a class I found on the internet somewhere (unfortunately can't seem to find it right now) that just worked. Here is the code for that:</p> <pre><code>public class ConcreteXmlObjectSerializer : XmlObjectSerializer { readonly Type objectType; XmlSerializer serializer; public ConcreteXmlObjectSerializer(Type objectType) : this(objectType, null, null) { } public ConcreteXmlObjectSerializer(Type objectType, string wrapperName, string wrapperNamespace) { if (objectType == null) throw new ArgumentNullException("objectType"); if ((wrapperName == null) != (wrapperNamespace == null)) throw new ArgumentException("wrapperName and wrapperNamespace must be either both null or both non-null."); if (wrapperName == string.Empty) throw new ArgumentException("Cannot be the empty string.", "wrapperName"); this.objectType = objectType; if (wrapperName != null) { XmlRootAttribute root = new XmlRootAttribute(wrapperName); root.Namespace = wrapperNamespace; this.serializer = new XmlSerializer(objectType, root); } else this.serializer = new XmlSerializer(objectType); } public override bool IsStartObject(XmlDictionaryReader reader) { throw new NotImplementedException(); } public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) { Debug.Assert(serializer != null); if (reader == null) throw new ArgumentNullException("reader"); if (!verifyObjectName) throw new NotSupportedException(); return serializer.Deserialize(reader); } public override void WriteStartObject(XmlDictionaryWriter writer, object graph) { throw new NotImplementedException(); } public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) { if (writer == null) throw new ArgumentNullException("writer"); if (writer.WriteState != WriteState.Element) throw new SerializationException(string.Format("WriteState '{0}' not valid. Caller must write start element before serializing in contentOnly mode.", writer.WriteState)); using (MemoryStream memoryStream = new MemoryStream()) { using (XmlDictionaryWriter bufferWriter = XmlDictionaryWriter.CreateTextWriter(memoryStream, Encoding.UTF8)) { serializer.Serialize(bufferWriter, graph); bufferWriter.Flush(); memoryStream.Position = 0; using (XmlReader reader = new XmlTextReader(memoryStream)) { reader.MoveToContent(); writer.WriteAttributes(reader, false); if (reader.Read()) // move off start node (we want to skip it) { while (reader.NodeType != XmlNodeType.EndElement) // also skip end node. writer.WriteNode(reader, false); // this will take us to the start of the next child node, or the end node. reader.ReadEndElement(); // not necessary, but clean } } } } } public override void WriteEndObject(XmlDictionaryWriter writer) { throw new NotImplementedException(); } public override void WriteObject(XmlDictionaryWriter writer, object graph) { Debug.Assert(serializer != null); if (writer == null) throw new ArgumentNullException("writer"); serializer.Serialize(writer, graph); } } </code></pre> <p>This is then hooked into the WCF client endpoint via the config file in 3 steps (all under the <code>system.serviceModel</code> node:</p> <p>Register the extension</p> <pre><code>&lt;extensions&gt; &lt;behaviorExtensions&gt; &lt;add name="ClientSoapHeaderAdderBehaviour" type="MyNamespace.SoapHeaderBehaviour, MyAssembly, Version=My.Version, Culture=neutral, PublicKeyToken=null" /&gt; &lt;/behaviorExtensions&gt; &lt;/extensions&gt; </code></pre> <p>Create an endpoint behaviour using it</p> <pre><code>&lt;behaviors&gt; &lt;endpointBehaviors&gt; &lt;behavior name="MyEndpointBehaviours"&gt; &lt;ClientSoapHeaderAdderBehaviour /&gt; &lt;/behavior&gt; &lt;/endpointBehaviors&gt; &lt;/behaviors&gt; </code></pre> <p>Attach your endpoint behaviour to your client endpoint</p> <pre><code>&lt;client&gt; &lt;endpoint address="blah" binding="basicHttpBinding" bindingConfiguration="blah" contract="blah" name="blah" behaviorConfiguration="MyEndpointBehaviours"/&gt; &lt;/client&gt; </code></pre> <p>Hope this helps you.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload