Changing URL dynamically in WCF user behavior

The class is defined as follows:

public class BizTalkRESTTransmitHandler : IClientMessageInspector 

I use this signature:

 public object BeforeSendRequest(ref Message request, IClientChannel channel) 

So, it seems to me that I need to manipulate the channel object.

The reason is that this is used in BizTalk 2010 SendPort to support JSON. I have tried this so far:

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

The compilation error above is: "System.ServiceModel.EndpointAddress.Uri" cannot be assigned - it is only ready "RemoteAddress is also read.

I refer to these questions, but they do not use the channel object. Assign the Url.AbsoluteUri URL in ASP.NET and the WCF Change Endpoint Address at Run Time But they do not seem to be dealing with the channel object.

Update 1: I tried the following:

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

but he gave this error: System.InvalidOperationException: Trying to get the contract type for IClientChannel, but this type is not ServiceContract and does not inherit ServiceContract.

+7
wcf biztalk biztalk-2010
source share
3 answers

IClientMessageInspector not suitable for Channel management, use IEndpointBehavior :

From MSDN

Implements methods that can be used to extend runtime behavior for an endpoint in a service or client application.

Here is a simple example:

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

Here you can read Carlos Figueira's excellent post about IEndpointBehavior : https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/04/wcf-extensibility-iendpointbehavior/

Another alternative is to implement simple routing with WCF, here is a link to an example: WCF REST service URL based on request parameters

Hope this helps.

+1
source share

Using the IEndpointBehavior interface, you will gain access to the ApplyClientBehavior , which provides an instance of ServiceEndPoint . Now you can change the value for the address by specifying a new instance of 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) { } } 
+2
source share

I may be a little late, but a hoe it helps a little.

I recently had a similar goal (also related to biztalk) where I needed to change the url based on some value sent by message. I tried using the ApplyDispatchBehavior method, but it was never called, and also, I could not see how to access the message from here, so I started looking for the BeforeSendRequest method (in the Inspector class).

Here is what I came up with:

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

So, I found that messing around with request.Headers.To , I could change the endpoint.

I had several problems getting the contents of the message and most of the examples on the Internet (showing that using MessageBuffer.CreateNavigator or Message.GetBody <string>, which always threw an exploit that I could not get around) would not give me a biztalk message, but rather soap message? ... not sure, but he had a headline

The body and inside the body had some base64 string, which was not my biztalk message.

Also, as you can see in Convert.FromBase64String(reqAux.ToString().Replace("<Binary>", "").Replace("</Binary>", "")) , I had to make it ugly substitution. I don’t do why this happens in base64, maybe in some WCF configuration ?, but by doing this, I could find my value.

NOTE. I have not fully tested this, but so far this has worked for my examples.

By the way, any idea that I can switch MemoryStream with this way will become a more streaming solution?
0
source share

All Articles