2012-05-04 10 views
13

En mi servicio WCF, quiero editar el SOAP en BeforeSendRequest y AfterReceiveReply de IClientMessageInspector.EDITAR SOAP de un servicio WCF utilizando IClientMessageInspector

he creado un comportamiento personalizado de esta manera:

public class MyBehavior : BehaviorExtensionElement, IEndpointBehavior 
{ 
} 

en la clase MyBehavior, he implementado método IEndpointBehavior Como continuación Código:

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

MyInspector no es más que la clase que se hereda de IClientMessageInspector.

Ahora, mi pregunta es: ApplyClientBehavior of IEndpointBehavior no se despide. Pero al cliente WCF, cuando agrego una referencia del proyecto en el que está presente la clase MyBehavior y escribir debajo de código en el lado del cliente:

c.Endpoint.Behaviors.Add(new MyBehavior()); 

Trabaja muy bien. Me refiero al método Apply Client Behavior que fue despedido.

No quiero pedirles a mis clientes que agreguen este Comportamiento de forma manual y quiero que esto suceda automáticamente. ¿Cómo puedo lograr esto?

Aquí está el código completo:

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; 
      } 
     } 
    } 
} 

y la clase de servicio es:

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!!"); 
     } 
    } 

} 

Aquí es el código de cliente:

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(); 
     } 
    } 

Gracias Suraj

+1

Disculpe yo como este es un código POC sin nombrar conv y todos son seguidos ... :-) – user1312242

+1

No se puede hacer lo mismo en su servicio con los métodos BeforeSendReply y AfterRecieveRequest de IDispatchMessageInspector (http://msdn.microsoft.com/en -us/library/system.servicemodel.dispatcher.idispatchmessageinspector.aspx). Al hacerlo, puede usarlo en su nivel de servicio y el cliente no necesitará usar el IClientMessageInspector. Más información sobre el inspector de mensajes aquí: http://msdn.microsoft.com/en-us/library/aa717047.aspx – Rajesh

+0

Aquí hay otra muestra de esto: http://stackoverflow.com/questions/29352015/how-can- i-create-custom-xml-namespace-attributes-when-consuming-a-legacy-soap-se –

Respuesta

6

Tú puede lograr esto usando las secciones <behaviors> y <extensions> en el archivo app.config para su cliente.

Para registrar su comportamiento personalizado añada lo siguiente a la sección <system.serviceModel> de su app.config archivo:

<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> 

Luego, en <endpoint> elemento si la sección <client> añadir el siguiente atributo:

behaviorConfiguration="MyBehavior" 

Para una mejor explicación, consulte este artículo: Creating Custom WCF Endpoint Behavior

Cuestiones relacionadas