EDIT SOAP of a WCF Service using IClientMessageInspector

soap, wcf

Solution

You can accomplish this using the `<behaviors>` and `<extensions>` sections in the `app.config` file for your client.

To register your custom behavior add the following to the `<system.serviceModel>` section of your `app.config` file:

<behaviors>
  <endpointBehaviors>
    <behavior name="MyBehavior">
      <myBehavior/>
    </behavior>
  </endpointBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add name="myBehavior" type="MethodChangeService.MyBehavior, MethodChangeService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>

Then in `<endpoint>` element if the `<client>` section add the following attribute:

behaviorConfiguration="MyBehavior"

For more info on this, check out: Configuring and Extending the Runtime with Behaviors

Problem

In my WCF Service, I want to edit the SOAP in BeforeSendRequest and AfterReceiveReply of IClientMessageInspector. I have created a custom Behavior like this: ``` public class MyBehavior : BehaviorExtensionElement, IEndpointBehavior { } ``` in the class MyBehavior, I implemented IEndpointBehavior method Like below code: ``` public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { MyInspector inspector = new MyInspector(); clientRuntime.MessageInspectors.Add(inspector); } ``` MyInspector is nothing but the class which is inherited from IClientMessageInspector. Now, my question is: ApplyClientBehavior of IEndpointBehavior is not getting fired. But at wcf client, when I add a reference of the project where the MyBehavior class is present and write below code at client side: ``` c.Endpoint.Behaviors.Add(new MyBehavior()); ``` It works fine. I mean the Apply Client Behavior method getting fired. I dont want to ask my clients to add this Behavior manually and I want this to happen automatically. How can I achive this? Here is the full code: ``` using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Xml; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using System.ServiceModel.Channels; using System.IO; namespace MethodChangeService { public class MyInspector : IClientMessageInspector { public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { XmlDocument doc = new XmlDocument(); MemoryStream ms = new MemoryStream(); XmlWriter writer = XmlWriter.Create(ms); reply.WriteMessage(writer); writer.Flush(); ms.Position = 0; doc.Load(ms); ChangeMessage(doc, false); ms.SetLength(0); writer = XmlWriter.Create(ms); doc.WriteTo(writer); writer.Flush(); ms.Position = 0; XmlReader reader = XmlReader.Create(ms); reply = Message.CreateMessage(reader, int.MaxValue, reply.Version); } public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) { string action = request.Headers.GetHeader<string>("Action", request.Headers[0].Namespace); if (action.Contains("GetData")) { XmlDocument doc = new XmlDocument(); MemoryStream ms = new MemoryStream(); XmlWriter writer = XmlWriter.Create(ms); request.WriteMessage(writer); writer.Flush(); ms.Position = 0; doc.Load(ms); ChangeMessage(doc, true); ms.SetLength(0); writer = XmlWriter.Create(ms); doc.WriteTo(writer); writer.Flush(); ms.Position = 0; XmlReader reader = XmlReader.Create(ms); request = Message.CreateMessage(reader, int.MaxValue, request.Version); } request.Headers.Action += "1"; return null; } void ChangeMessage(XmlDocument doc, bool flag) { XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable); nsManager.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/"); nsManager.AddNamespace("tempuri", "http://tempuri.org/"); XmlNode node = doc.SelectSingleNode("//s:Body", nsManager); if (node != null) { if (flag) node.InnerXml = node.InnerXml.Replace("GetData", "GetData1"); else node.InnerXml = node.InnerXml.Replace("GetData1Response", "GetDataResponse").Replace("GetData1Result", "GetDataResult"); } } } public class MyBehavior : BehaviorExtensionElement, IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { //endpoint.Behaviors.Add(new MyBehavior()); } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { MyInspector inspector = new MyInspector(); clientRuntime.MessageInspectors.Add(inspector); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } protected override object CreateBehavior() { return new MyBehavior(); } public override Type BehaviorType { get { Type t = Type.GetType("MethodChangeService.MyBehavior"); return t; } } } } ``` and the Service class is: ``` using System; using System.Configuration; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; using System.ServiceModel.Description; using System.ServiceModel.Configuration; using System.ServiceModel.Dispatcher; using System.ServiceModel.Channels; using System.IO; using System.Xml; namespace MethodChangeService { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together. public class HardcoadedService : IHardcoadedService { public string GetData(int i) { return string.Format("you entered {0}",i); } public string GetData1() { return string.Format("You got redirected to another method!!"); } } } ``` Here is the client code: ``` class Program { static void Main(string[] args) { HardcoadedServiceClient c = new HardcoadedServiceClient(); c.Endpoint.Behaviors.Add(new MyBehavior()); string s = c.GetData(3); Console.WriteLine(s); Console.ReadKey(); } } ```

Original source