I'm attempting to add a custom header to all SOAP requests over WCF. I found this fantastic article on how to do exactly this. My MessageHeader
class looks like this:
public class OperatorNameMessageHeader : MessageHeader
{
private string opName;
public const string HeaderName = "OperatorNameMessageHeader";
public const string HeaderNamespace = "http://schemas.microsoft.com/scout";
public override string Name { get { return HeaderName; } }
public override string Namespace { get { return HeaderNamespace; } }
public string OperatorName
{
get { return opName; }
set { opName = value; }
}
public OperatorNameMessageHeader()
{
}
public OperatorNameMessageHeader(string operatorName)
{
opName = operatorName;
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteElementString("OperatorName", opName);
}
}
One thing the article does not say is how to read the value on the server. According to this post, you can use OperationContext.Current.IncomingMessageHeaders
to read these headers. When I look at these MessageHeaders
under the debugger, I see 3 headers including my custom one. So, it's definitely showing up in the SOAP data. However, when I call GetHeader
:
OperatorNameMessageHeader test = msgHeaders.GetHeader<OperatorNameMessageHeader>(OperatorNameMessageHeader.HeaderName, OperatorNameMessageHeader.HeaderNamespace);
Then test.OperatorName
is null. Basically, I'm just getting back an empty OperatorNameMessageHeader
object that hasn't been deserialized from the data in the SOAP.
My next step was to run the WCF tracing tool. When I do this, I can verify the custom header is indeed being sent across the wire:
<MessageHeaders>
<ActivityId CorrelationId="66a7c5b6-3548-4f3c-9120-4484af76b64b" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">f9bef03b-4e7b-4e84-b327-5e79814d9933</ActivityId>
<OperatorNameMessageHeader xmlns="http://schemas.microsoft.com/scout">
<OperatorName>Correct Operator Name</OperatorName>
</OperatorNameMessageHeader>
<To d4p1:mustUnderstand="1" xmlns:d4p1="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:90/IRolesAndResourcesManager</To>
<Action d4p1:mustUnderstand="1" xmlns:d4p1="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IRolesAndResourcesManager/Authenticate</Action>
</MessageHeaders>
So, the server has the data, I just can't get to it. What's the solution to this problem?
I had the exact same problem, and was able to make it work as follows:
[DataContract(Namespace = OperatorNameMessageHeader.HeaderNamespace)]
public class OperatorNameMessageHeader
{
public const string HeaderName = "OperatorNameMessageHeader";
public const string HeaderNamespace = "http://schemas.microsoft.com/scout";
[DataMember]
public string OperatorName { get; set; }
}
With that, I can read the header as follows:
public static OperatorNameMessageHeader DeserializeSoap(string xml)
{
using (var reader = XmlReader.Create(new StringReader(xml)))
{
var m = System.ServiceModel.Channels.Message.CreateMessage(reader, int.MaxValue, MessageVersion.Soap11);
var operatorNameHeader = m.Headers.GetHeader<OperatorNameMessageHeader>(OperatorNameMessageHeader.HeaderName, OperatorNameMessageHeader.HeaderNamespace);
return operatorNameHeader;
}
}
Notice I'm using WCF to deserialize the XML string and therefore needed to use the [DataContract]
and [DataMember]
attributes - without them, it won't work. Not sure if you need to actually derive from MessageHeader
for your case, but for me that isn't necessary in order to read custom headers.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With