For a WCF service or client proxy, it is common to receive SoapHeaders within the coming request or returned response messages. SoapHeader has a mustUnderstand attribute that indicates to the target endpoint (or intermediate message processor) whether the SoapHeader must be processed. The following screenshot shows a typical SOAP message that contains a SoapHeader with the mustUnderstand
attribute set to 1
(true).

Also for a XML Web Service or WCF service, we can dynamically insert SoapHeaders at runtime or statically apply them at design-time (which will be described via WSDL or service metadata).
By default, a WCF endpoint will perform validation on all the SoapHeaders within incoming messages, and if there are any unknown SoapHeaders (not predefined) which have a mustUnderstand
attribute as 1
(or true), a validation exception will be raised by the runtime. However, sometimes it is useful to suppress this validation so that the WCF service or client proxy can gracefully handle unknown SoapHeaders that are dynamically added.
If you are not familiar with SoapHeaders and the mustUnderstand
attribute, or how to set this attribute via the WCF programming model, you can take a look at the following references first:
- SOAP Header Element
- SoapHeader.MustUnderstand Property
http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapheader.mustunderstand.aspx
By injecting MustUnderstandBehavior
into our WCF endpoint’s behavior collection, we can suppress the validation and raising of exceptions on unknown SoapHeaders with mustUnderstand=”1”
. The steps are as follows:
- First, we need to create a
MustUnderstandBehavior
type instance and set itsValidateMustUnderstand
property tofalse
(which can be done in thetype
constructor). - Second, we should locate the service/client endpoint instance on which we want to apply
MustUnderstandBehavior
. For the WCF service, we can useServiceHost.Description.Endpoints
collection to find the wanted endpoint. For the client proxy, we can directly use[ClientProxy].Endpoint
to get the endpoint instance. - After we get the endpoint instance, we can simply add the
MustUnderstandBehavior
instance into the endpoint instance’s Behaviors collection.The following code shows the complete steps for applying
MustUnderstandBehavior
in service hosting code:using (ServiceHost host = new ServiceHost(typeof(HeaderTestService))) { // Suppress the MustUnderstand header’s validation so that exception won’t be raised for unknown MustUnderstand headers MustUnderstandBehavior mubehavior = new MustUnderstandBehavior(false); // Find the target endpoint we want ServiceEndpoint endpoint = host.Description.Endpoints.Find(typeof(IHeaderTestService)); // Add the MustUnderstandBehavior to our service endpoint’s Behavior collection endpoint.Behaviors.Add(mubehavior); }
When you encounter the ProtocolException
(as shown in the next screenshot), it is probably because the WCF service or client endpoint received an unknown SoapHeader that is marked as mustUnderstand=true
.

After applying MustUnderstandBehavior
(with ValidateMustUnderstand
set to false
), the runtime will ignore validation on any unknown SoapHeaders. But, we can still use code to access them from OperationContext, as follows:
StringBuilder sb = new StringBuilder();
sb.AppendFormat(“{0} headers in message\n”, OperationContext.Current.IncomingMessageHeaders.Count);
foreach (var header in OperationContext.Current.IncomingMessageHeaders)
{
sb.AppendFormat(“HeaderName:{0}, MustUnderstand={1}\n”, header.Name, header.MustUnderstand);
}
In this recipe, we demonstrated how to inject the MustUnderstandBehavior
for a self-hosting scenario. However, in many cases, our WCF service will be hosted on IIS server via .svc
endpoints. In such cases, we can use a custom ServiceHostFactory
class to add the behavior injecting code logic. You can have a look at the article Extending Hosting Using ServiceHostFactory at http://msdn.microsoft.com/en-us/library/aa702697.aspx.
- Customizing IIS ServiceHost via ServiceHostFactory in Chapter 3
- Complete source code for this recipe can be found in the
\Chapter
2\recipe7\
folder