2016-09-02 51 views
7

klasa jest zdefiniowana w następujący sposób:Jak dynamicznie zmienić adres URL w Behavior WCF niestandardowe

public class BizTalkRESTTransmitHandler : IClientMessageInspector 

Jestem metoda z tego podpisu:

public object BeforeSendRequest(ref Message request, IClientChannel channel) 

Więc myślę, że trzeba manipulować kanał obiekt.

Powodem tego jest użycie w BizTalk 2010 SendPort do obsługi JSON. Próbowałem to do tej pory:

if (channel.RemoteAddress.Uri.AbsoluteUri == "http://api-stage2.mypartner.com/rest/events/2/" 
    || channel.RemoteAddress.Uri.AbsoluteUri == "http://api.mypartner.com/rest/events/2/") 
{ 
    //TODO - "boxout" will become a variable obtained by parsing the message 
    Uri newUri = new Uri(channel.RemoteAddress.Uri.AbsoluteUri + "boxout"); 
    channel.RemoteAddress.Uri = newUri; 

} 

Powyżej podano skompilować błędu: „System.ServiceModel.EndpointAddress.Uri” nie można przypisać - jest gotowy tylko”RemoteAddress wydaje się być tylko do odczytu, a także

mam odwoływać te pytania, ale nie używają obiektu kanału Assign a URL to Url.AbsoluteUri in ASP.NET i WCF change endpoint address at runtime ale oni nie wydają się mieć do czynienia z obiektem kanału

Aktualizacja 1:.. próbowałem następujące:

//try create new channel to change URL 
WebHttpBinding myBinding = new WebHttpBinding(); 
EndpointAddress myEndpoint = new EndpointAddress(newURL); 
ChannelFactory<IClientChannel> myChannelFactory = new ChannelFactory<IClientChannel>(myBinding, myEndpoint); //Change to you WCF interface 
IClientChannel myNewChannel = myChannelFactory.CreateChannel(); 
channel = myNewChannel; //replace the channel parm passed to us 

ale dał ten błąd: System.InvalidOperationException: próbowali dostać typ umowne IClientChannel, ale ten typ nie jest ServiceContract, ani nie dziedziczą ServiceContract.

+0

Co z tworzeniem zupełnie nowego kanału, jak tutaj? Wygląda na przesadę. http://stackoverflow.com/questions/27782919/wcf-change-address-at-runtime-exception/27783784#27783784 – NealWalters

Odpowiedz

1

IClientMessageInspector nie jest właściwym miejscem manipulować kanał, należy użyć IEndpointBehavior zamiast:

Od MSDN

Implements methods that can be used to extend run-time behavior for an endpoint in either a service or client application.

Oto prosty przykład:

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
{ 
    Uri endpointAddress = endpoint.Address.Uri; 
    string address = endpointAddress.ToString(); 

    if (address == "http://api-stage2.mypartner.com/rest/events/2/" 
    || address == "http://api.mypartner.com/rest/events/2/") 
    { 
     //TODO - "boxout" will become a variable obtained by parsing the message 
     Uri newUri = new Uri(address + "boxout"); 
     ServiceHostBase host = endpointDispatcher.ChannelDispatcher.Host; 
     ChannelDispatcher newDispatcher = this.CreateChannelDispatcher(host, endpoint, newUri); 
     host.ChannelDispatchers.Add(newDispatcher); 
    } 
} 

Tutaj można przeczytać post excelent Carlos Figueira o IEndpointBehavior: https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/04/wcf-extensibility-iendpointbehavior/

Inną alternatywą jest wykonanie prostego Routing z WCF, tu jest związek z przykładu: WCF REST service url routing based on query parameters

Nadzieję, że to pomaga.

+0

Nagroda przyznana przez Bounty ... Niestety, jak powiedziałem temu facetowi, który odpowiedział, Muszę zmienić adres URL na podstawie danych w mojej wiadomości. W końcu zrobiłem to w Pipeline BizTalk. – NealWalters

2

Korzystając z interfejsu IEndpointBehavior, uzyskasz dostęp do metody ApplyClientBehavior, która udostępnia instancję ServiceEndPoint. Teraz możesz zmienić wartość adresu, definiując nową instancję EndpointAddress.

public class MyCustomEndpointBehavior : IEndpointBehavior 
{  
    public void AddBindingParameters(ServiceEndpoint serviceEndpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 
    } 
    public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, System.ServiceModel.Dispatcher.ClientRuntime behavior) 
    { 
     serviceEndpoint.Address = new System.ServiceModel.EndpointAddress("http://mynewaddress.com"); 
    } 
    public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
    { 
    } 
    public void Validate(ServiceEndpoint serviceEndpoint) 
    { 
    } 
} 
+0

Widzę, że prawdopodobnie działałoby na literał; ale nie wyjaśniłem w moim pytaniu - adres URL wymaga przyrostka na podstawie typu wiadomości. Tak więc wiadomość nie wydaje się być dostępna w tej wiadomości. [Zbudowałem już BizTalk Pipeline, który to robi, ale wolałbym to i program JSON/Conversion jeden, a nie na dwa.] – NealWalters

0

Mogę być trochę za późno, ale motyka to trochę pomaga.

Niedawno miałem podobny cel (również związany z biztalk), w którym potrzebowałem zmienić adres URL na podstawie wartości wysłanej w wiadomości. Próbowałem za pomocą metody ApplyDispatchBehavior, ale nigdy nie został wywołany, a także, nie mogłem zobaczyć, jak uzyskać dostęp do wiadomości stąd, dlatego zacząłem spojrzenie na metodę BeforeSendRequest (w klasie Inspector).

Oto co wymyśliłem:

object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
     var queryDictionary = HttpUtility.ParseQueryString(request.Headers.To.Query); 
     string parameterValue = queryDictionary[this.BehaviourConfiguration.QueryParameter]; 

     //Only change parameter value if it exists 
     if (parameterValue != null) 
     { 
      MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue); 

      request = buffer.CreateMessage(); 

      //Necessary in order to read the message without having WCF throwing and error saying 
      //the messas was already read 
      var reqAux = buffer.CreateMessage(); 

      //For some reason the message comes in binary inside tags <Binary>MESSAGE</Binary> 
      using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(reqAux.ToString().Replace("<Binary>", "").Replace("</Binary>", "")))) 
      { 
       ms.Position = 0; 
       string val = ExtractNodeValueByXPath(ms, this.BehaviourConfiguration.FieldXpath); 

       queryDictionary.Set(this.BehaviourConfiguration.QueryParameter, DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" + 
        this.BehaviourConfiguration.Message + (string.IsNullOrWhiteSpace(val) ? string.Empty : "_" + val) + ".xml"); 

       UriBuilder ub = new UriBuilder(request.Headers.To); 
       ub.Query = queryDictionary.ToString(); 
       request.Headers.To = ub.Uri; 
      } 
     } 

     return null; 
    } 

Więc, odkryłem, że brudząc z request.Headers.To mogę zmienić punkt końcowy.

Miałem kilka problemów z uzyskaniem treści wiadomości i większości przykładów w Internecie (pokazując, że używam MessageBuffer.CreateNavigator lub Message.GetBody < ciąg> który zawsze wyrzucał eksplikację, której nie mogłem obejść) nie dałoby mi wiadomość biztalk, ale raczej wiadomość mydła? ... nie jestem pewien, ale miał nagłówek, ciało i wewnątrz ciała był ciąg base64, który nie był moim biztalkowym komunikatem.

Ponadto, jak widać w Convert.FromBase64String(reqAux.ToString().Replace("<Binary>", "").Replace("</Binary>", "")), musiałem to zrobić brzydko zastępuje. Nie wiem dlaczego to jest w base64, prawdopodobnie w jakiejś konfiguracji WCF ?, ale robiąc to, mógłbym wtedy szukać swojej wartości.

UWAGA: Nie przetestowałem tego w pełni, ale jak dotąd działało to na moich przykładach.

Przy okazji, jakikolwiek pomysł na temat, w jaki sposób mogę zmienić mój system MemoryStream tak, aby stał się bardziej płynnym rozwiązaniem?