Question

I am consuming a WCF service which has multiple operations, this service requires me to add outgoing message properties whenever I call any of its operations.

At the moment i am just adding the properties every time i call the service inside the code.

Here is my code to do it:

using (new OperationContextScope(client.InnerChannel))
{
      OperationContext.Current.OutgoingMessageProperties.Add("P1", "Test User");
      OperationContext.Current.OutgoingMessageProperties.Add("P2", "Test Type");
      response = client.process(request);
}

How can I create a WCF extension that adds these message properties dynamically?

I have few knowledge about the extension but not enough to intercept and add these headers.

Was it helpful?

Solution

To add some headers to a message automatically you have to implement IClientMessageInspector. It will allow you to change anything for an outgoing message.

EDIT 2:

public class ClientMessageInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        //following example is for adding http header.   
        //If you have another protocol you can add any other message  
        //manipulation code instead.

        //HttpResponseMessageProperty.Name returns "httpResponse".

        HttpResponseMessageProperty httpProp = null;
        if (request.Properties.ContainsKey(HttpResponseMessageProperty.Name))
        {
            httpProp = (HttpResponseMessageProperty)request.Properties[HttpResponseMessageProperty.Name];
        }
        else
        {
            httpProp = new HttpResponseMessageProperty();
            request.Properties.Add(HttpResponseMessageProperty.Name, httpProp);
        }

        httpProp.Headers.Add("YouHeader", "YourValue");

        //as I mentioned you can change a message in a way you need
        request.Properties.Add("P1", "Test User");
        request.Headers.Add(MessageHeader.CreateHeader("P1", "htt p://site.com/", "Test User"));

        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState) { }
}

public class ClientMessageInspectorBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new ClientMessageInspector());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {

    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

public class ClientMessageInspectorExtensionElement : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new ClientMessageInspectorBehavior();
    }

    public override Type BehaviorType
    {
        get
        {
            return typeof(ClientMessageInspectorBehavior);
        }
    }
}

And you config file should look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.serviceModel>
    <client>
          <endpoint 
            address="http://localhost:8000/CoolerService" 
            behaviorConfiguration="coolerBehaviour" 
            binding="webHttpBinding"
            contract="CoolerService.ICoolerService"
            name="coolerEndpoint">
          </endpoint>
    </client>

    <extensions>
      <behaviorExtensions>
        <add name="customHeaderAdder" type="Extensions.ClientMessageInspectorExtensionElement, Extensions" />
      </behaviorExtensions>
    </extensions>

    <behaviors>
      <endpointBehaviors>
        <behavior name="coolerBehaviour">
          <customHeaderAdder />
        </behavior>
      </endpointBehaviors>
    </behaviors>

  </system.serviceModel>

</configuration>

OTHER TIPS

In my opinion you could simply set OperationContext.Current without creating an OperationScope like this:

OperationContext.Current = new OperationContext(client.InnerChannel);
OperationContext.Current.OutgoingMessageProperties.Add("P1", "Test User");

This might look like a bad practice at first but if you take a look at the documentation you will find that the OperationContext.Current property is actually scoped to the current thread (using the ThreadStatic attribute) and therefore thread safe.

Be aware that other instances of client in the same thread would not add the message properties since the OperationContext is bound to the clients channel.

Implement the IClientMessageInspector like the earlier answer said, but if you want to add HTTP headers, use similar code block like what you've used - inside the BeforeSendRequest.

using (new OperationContextScope((IContextChannel)channel))
{
      OperationContext.Current.OutgoingMessageProperties.Add("P1", "Test User");
      OperationContext.Current.OutgoingMessageProperties.Add("P2", "Test Type");
      response = client.process(request);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top