Jeff D
Jeff D

Reputation:

Add a header to a REST WCF request - EnvelopeNone does not support adding Message Headers exception

I'm trying to add a custom header to a wcf client hitting a standard, RESTful endpoint. I am trying to add some kind of header that will just allow me to trace requests from one layer to the next. Here's how I've tried to implement it:

public class DynatracePurePathHeaderAppender : IClientMessageInspector, IEndpointBehavior
 {
  object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
  {
   var dynaHeader = MessageHeader.CreateHeader("Action", "ns.yellowbook.jeff", "dynatrace",false);
   request.Headers.Add(dynaHeader);
   return null;
  }

  void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
  {
   return;
  }

  public void Validate(ServiceEndpoint endpoint){}

  public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters){}

  public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher){}

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

public class DynatracePurePathHeaderAppenderElement : BehaviorExtensionElement
 {
  protected override object CreateBehavior()
  {
   return new DynatracePurePathHeaderAppender();
  }

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

I then configure the client successfully, but when this runs, I get the following exception:

System.InvalidOperationException: Envelope Version 'EnvelopeNone (http://schemas.microsoft.com/ws/2005/05/envelope/none)' does not support adding Message Headers.

Anyone have any suggestions on how to insert this little barium meal?

Upvotes: 5

Views: 8122

Answers (3)

Denis
Denis

Reputation: 12087

I know this is late but I ran across this post so decided to fill this in, in case I ever need to remember this again. This worked for me:

  1. Create the Message Inspector:

    Public Class AuthenticationHeader
      Implements IClientMessageInspector
    
    Private itsUser As String
    Private itsPass As String
    
    Public Sub New(ByVal user As String, ByVal pass As String)
        itsUser = user
        itsPass = pass
    End Sub
    
    Public Sub AfterReceiveReply(ByRef reply As Message, correlationState As Object) Implements IClientMessageInspector.AfterReceiveReply
        Console.WriteLine("Received the following reply: '{0}'", reply.ToString())
    End Sub
    
    Public Function BeforeSendRequest(ByRef request As Message, channel As IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest
        Dim hrmp As HttpRequestMessageProperty = request.Properties("httpRequest")
        Dim encoded As String = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(itsUser + ":" + itsPass))
        hrmp.Headers.Add("Authorization", "Basic " + encoded)
        Return request
      End Function
    End Class
    
  2. Write the Behavior:

    Public Class AuthenticationHeaderBehavior
    Implements IEndpointBehavior
    
    Private ReadOnly itsUser As String
    Private ReadOnly itsPass As String
    
    Public Sub New(ByVal user As String, ByVal pass As String)
        MyBase.New()
        itsUser = user
        itsPass = pass
    End Sub
    
    Public Sub AddBindingParameters(endpoint As ServiceEndpoint, bindingParameters As BindingParameterCollection) Implements IEndpointBehavior.AddBindingParameters
    End Sub
    
    Public Sub ApplyClientBehavior(endpoint As ServiceEndpoint, clientRuntime As ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior
        clientRuntime.MessageInspectors.Add(New AuthenticationHeader(itsUser, itsPass))
    End Sub
    
    Public Sub ApplyDispatchBehavior(endpoint As ServiceEndpoint, endpointDispatcher As EndpointDispatcher) Implements IEndpointBehavior.ApplyDispatchBehavior
    End Sub
    
    Public Sub Validate(endpoint As ServiceEndpoint) Implements IEndpointBehavior.Validate
    End Sub
    End Class
    
  3. Add it to your endpoint:

      Dim binding As New WebHttpBinding(WebHttpSecurityMode.Transport)
      binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None
    
      ChlFactory = New WebChannelFactory(Of IMyServiceContract)(binding, New Uri(url))
      ChlFactory.Endpoint.Behaviors.Add(New WebHttpBehavior())
      ChlFactory.Endpoint.Behaviors.Add(New AuthenticationHeaderBehavior(user, pass))
      Channel = ChlFactory.CreateChannel()
    

Upvotes: 0

Eugene Osovetsky
Eugene Osovetsky

Reputation: 6541

I assume you mean HTTP header and not a SOAP header? If so, MessageHeader has nothing to do with this.

Try something like this:

HttpRequestMessageProperty hrmp = new HttpRequestMessageProperty();
//Set hrmp.Headers, then:
request.Properties.Add(HttpRequestMessageProperty.Name, hrmp);

In general, the WCF REST support is not really optimized on the client side (it was created mostly to allow people to create REST services). For much better client-side REST support, check out HttpClient in the WCF REST Starter Kit.

Upvotes: 5

Denis Besic
Denis Besic

Reputation: 3147

In the method BeforeSendReply you need get Response:

var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;

When you have instance of response than you can easily add any header you want:

httpHeader.Headers.Add("my Custom Header", "My Value");

Upvotes: 2

Related Questions