WCF WSDL Soap Header on all operations

18,116

Solution 1

The IEndpointBehavior has the following interface:

ApplyDispatchBehavior(ServiceEndpoint endPoint, EndPointDispatcher endpointDispatcher);

You can add Soap Headers to the wsdl for operations by iterating over the endpoint.Contract.Operations in the ApplyDispatchBehavior.

Here you have the complete solution that worked for me:

void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
    foreach (OperationDescription operationDescription in endpoint.Contract.Operations)
    {
        foreach (MessageDescription msgDescription in operationDescription.Messages)
        {
            AddSoapHeader(operationDescription, "SomeHeaderObject", typeof(SomeHeaderObject), SoapHeaderDirection.InOut);
        }
    }
}

internal static void AddSoapHeader(OperationDescription operationDescription, string name, Type type, SoapHeaderDirection direction)
{
    MessageHeaderDescription header = GetMessageHeader(name, type);
    bool input = ((direction & SoapHeaderDirection.In) == SoapHeaderDirection.In);
    bool output = ((direction & SoapHeaderDirection.Out) == SoapHeaderDirection.Out);

    foreach (MessageDescription msgDescription in operationDescription.Messages)
    {
            if ((msgDescription.Direction == MessageDirection.Input && input) ||
                    (msgDescription.Direction == MessageDirection.Output && output))
                    msgDescription.Headers.Add(header);
    }
}

internal static MessageHeaderDescription GetMessageHeader(string name, Type type)
{
    string headerNamespace = SoapHeaderHelper.GetNamespace(type);
    MessageHeaderDescription messageHeaderDescription = new MessageHeaderDescription(name, headerNamespace);
    messageHeaderDescription.Type = type;
    return messageHeaderDescription;
}

The SoapHeaderHelper can be found in the WcfExtras.

Solution 2

You might want to have a look at the WCFExtras project on CodePlex - it has some support for custom SOAP headers and stuff like that. Not 100% sure if it's capable of filling your need, but check it out!

Marc

UPDATE: have you looked into creating a WCF extension, e.g. something like a message inspector, on both the client and the server side?

The client side IClientMessageInspector defines two methods BeforeSendRequest and AfterReceiveReply while the server side IDispatchMessageInspector has the opposite methods, i.e. AfterReceiveRequest and BeforeSendReply.

With this, you could add headers to every message going across the wire (or selectively only to a few).

Here's a snippet from a IClientMessageInspector implementor we use to automagically transmit the locale information (language and culture info) across from the clients to the server - should give you an idea how to get started:

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
    International intlHeader = new International();
    intlHeader.Locale = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;

    MessageHeader header = MessageHeader.CreateHeader(WSI18N.ElementNames.International, WSI18N.NamespaceURI, intlHeader);
    request.Headers.Add(header);

    return null;
}
Share:
18,116
Linefeed
Author by

Linefeed

Updated on June 17, 2022

Comments

  • Linefeed
    Linefeed almost 2 years

    By defining an attribute that implements IContactBehavior and IWsdlExportExtension and set that attribute on your service contract, you can easily add Soap Headers to your wsdl (see http://wcfextras.codeplex.com/ for more information)

    But now I need to set a Soap Header contract in the wsdl on all Operationcontracts and this time I cannot set an attribute.

    Following code (called from IWsdlExportExtension.ExportEndPoint) doesn't work, but does work when called from the SoapHeaderAttributes (that executes an IWsdlExportExtension.ExportContract)

    foreach (OperationDescription operationDescription in context.ContractConversionContext.Contract.Operations)
    {
       AddSoapHeader(operationDescription, "SomeHeaderObject", typeof(SomeHeaderObject), SoapHeaderDirection.InOut);                    
    }
    
    internal static void AddSoapHeader(OperationDescription operationDescription, string name, Type type, SoapHeaderDirection direction)
    {
        MessageHeaderDescription header = GetMessageHeader(name, type);
        bool input = ((direction & SoapHeaderDirection.In) == SoapHeaderDirection.In);
        bool output = ((direction & SoapHeaderDirection.Out) == SoapHeaderDirection.Out);
    
        foreach (MessageDescription msgDescription in operationDescription.Messages)
        {
            if ((msgDescription.Direction == MessageDirection.Input && input) ||
                (msgDescription.Direction == MessageDirection.Output && output))
                msgDescription.Headers.Add(header);
        }
    }
    
    internal static MessageHeaderDescription GetMessageHeader(string name, Type type)
    {
        string headerNamespace = SoapHeaderHelper.GetNamespace(type);
        MessageHeaderDescription messageHeaderDescription = new MessageHeaderDescription(name, headerNamespace);
        messageHeaderDescription.Type = type;
        return messageHeaderDescription;
    }
    

    Anyone has an idea how to apply this code on all operations (without using attributes) and by doing this, adding the contract of the header to the wsdl ?

  • Linefeed
    Linefeed almost 15 years
    I was actually pointing out to WCFExtras myself, but I couldn't find out how to add a soap header to the wsdl on all operations without setting attributes.
  • Linefeed
    Linefeed almost 15 years
    I don't see how this applies on modifying the WSDL Contract. Can you clarify ?
  • Philippe
    Philippe almost 15 years
    I doesn't. Inspectors are nice, but what they do is not reflected in the WSDL contract, so the client has to be aware of it...
  • Alex S
    Alex S about 13 years
    You have foreach MessageDescription loop both in ApplyDispatchBehavior() and AddSoapHeader(). I believe the one in ApplyDispatchBehavior() should be removed.