Search code examples
wcf

ClientMessageInspector not firing through config but working through code


I am trying to inject security information in header in ClientMessageInspector. I add the necessary behavior information in config. And yet the request does not go through Client Message Inspector as in call the BeforeSendRequest. Interestingly if I add the behavior in code, it works and fires the BeforeSendRequest. Can someone please tell why it is not going through client message inspector BeforeSendRequest through config.

Working in Code as follows:-

DealioLibClient dealioServiceProxy = new DealioLibClient();

dealioServiceProxy.Endpoint.EndpointBehaviors.Add(new AuthBehavior());

Not working through Config:-

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

      <bindings>
        <basicHttpBinding>
          <binding name="SOAPEndPoint1" />
        </basicHttpBinding>
      </bindings>
      <client>
        <endpoint address="http://localhost:90/DealioCapLinkSvc/DealioCapLinkSvc.svc/soap"
          binding="basicHttpBinding" bindingConfiguration="SOAPEndPoint1"
          contract="DealioService.IDealioLib" name="SOAPEndPoint1" />
      </client>
<behaviors>
        <serviceBehaviors>
            <behavior>
                <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
                <serviceDebug includeExceptionDetailInFaults="False" />
            </behavior>
        </serviceBehaviors>
        <!-- Security Behavior -->
        <endpointBehaviors>
            <behavior name="authBehavior">
                <authBehavior />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <extensions>
        <behaviorExtensions>
            <add name="authBehavior" type="CanadaDealio.AuthBehavior, CanadaDealio , Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
    </extensions>
    </system.serviceModel>
</configuration>

Below are the Auth Behavior and Client Message Inspector:-

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace CanadaDealio
{
    public class AuthBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {

        }

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

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {

        }

        public void Validate(ServiceEndpoint endpoint)
        {

        }

        protected override object CreateBehavior()
        {
            return new AuthBehavior();
        }

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

Below is Client Message Inspector:-

namespace CanadaDealio
{
    public class ClientMessageInspector : IClientMessageInspector
    {
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {

        }

        public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel)
        {
            // I do my logic here

            return null;
        }
    }
}

Auth Header:-

namespace CanadaDealio
{
    public class AuthHeader : MessageHeader
    {
        private const string HEADER_NAME = "AuthHeader";
        private const string NAME_SPACE = "http://jll.security.service";
        private readonly AuthToken _token;

        public AuthHeader(AuthToken token)
        {
            _token = token;
        }

        public override string Name
        {
            get { return HEADER_NAME; }
        }

        public override string Namespace
        {
            get { return NAME_SPACE; }
        }

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            /* NOTE: XML Serializer applies encoding, making the request not so readable. Keeping it her for future reference.
            XmlSerializer serializer = new XmlSerializer(typeof(AuthToken));
            StringWriter textWriter = new StringWriter();
            serializer.Serialize(textWriter, this._token);
            textWriter.Close();
            string text = textWriter.ToString();
             * */

            writer.WriteElementString("UserID", _token.UserID);
            writer.WriteElementString("Token", _token.Token);
        }
    }
}

Below is Auth Token:-

namespace CanadaDealio
{
    [DataContract]
    public class AuthToken
    {
        [DataMember]
        public string UserID { get; set; }

        [DataMember]
        public string Token { get; set; }
    }
}

Solution

  • We need to add the Endpoint Behavior configuration to the Client Endpoint so that the Behavior Extension could take effect.

    <endpoint address="http://localhost:1300/" binding="basicHttpBinding"
                    bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
                    name="BasicHttpBinding_IService" behaviorConfiguration="authBehavior" />