2012-05-04 35 views
13

W mojej usłudze WCF, chcę edytować SOAP w BeforeSendRequest i AfterReceiveReply z IClientMessageInspector.EDYTUJ SOAP usługi WCF przy użyciu IClientMessageInspector

Stworzyłem niestandardowe Zachowanie tak:

public class MyBehavior : BehaviorExtensionElement, IEndpointBehavior 
{ 
} 

w klasie MyBehavior, I wdrożone metody IEndpointBehavior jak poniżej kodu:

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

MyInspector to nic innego jak klasy, który jest dziedziczony z IClientMessageInspector.

Teraz moje pytanie brzmi: ApplyClientBehavior of IEndpointBehavior nie zostaje zwolniony. Ale na klienta WCF kiedy dodać odniesienie do projektu, gdzie klasa MyBehavior jest obecny i napisać poniżej kod po stronie klienta:

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

To działa dobrze. Chodzi mi o to, że metoda Apply Client Behavior jest uruchamiana.

Nie chcę prosić moich klientów o ręczne dodanie tego zachowania i chcę, aby to się stało automatycznie. Jak mogę to osiągnąć?

Oto pełny kod:

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

a klasa serwisowy:

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

} 

Oto kod klienta:

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

Dzięki Suraj

+1

Prosimy o usprawiedliwienie ja, ponieważ jest to kod POC, nie ma kongu nazewniczego i wszystkie są śledzone ... :-) – user1312242

+1

Nie możesz wykonać tego samego w swojej usłudze za pomocą metod BeforeSendReply i AfterRecieveRequest of IDispatchMessageInspector (http://msdn.microsoft.com/pl -us/library/system.servicemodel.dispatcher.idispatchmessageinspector.aspx). Dzięki temu można go używać na poziomie usługi, a klient nie będzie musiał korzystać z IClientMessageInspector. Więcej informacji na temat inspektora wiadomości można znaleźć tutaj: http://msdn.microsoft.com/en-us/library/aa717047.aspx – Rajesh

+0

Oto kolejna próbka tego: http://stackoverflow.com/questions/29352015/how-can- i-create-custom-xml-namespace-attributes-when-consuming-a-legacy-soap-se –

Odpowiedz

6

ty można to zrobić, używając sekcji <behaviors> i <extensions> w pliku app.config dla swojego klienta.

Aby zarejestrować niestandardowe zachowanie dodać następujące sekcji <system.serviceModel> swojego pliku app.config:

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

potem w <endpoint> elementu jeśli sekcja <client> dodać następujący atrybut:

behaviorConfiguration="MyBehavior" 

Dla lepsze wyjaśnienie, sprawdź ten artykuł: Creating Custom WCF Endpoint Behavior

Powiązane problemy