Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Dynamically change URL in a WCF Custom Behavior

Class is defined as follows:

public class BizTalkRESTTransmitHandler : IClientMessageInspector

I'm a method with this signature:

public object BeforeSendRequest(ref Message request, IClientChannel channel)

So I think I need to manipulate the channel object.

The reason is this is being using in BizTalk 2010 SendPort to support JSON. I 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; 

}

Above gives compile error: "System.ServiceModel.EndpointAddress.Uri" cannot be assigned to - it is ready only" RemoteAddress seems to be read only as well.

I have referenced these questions but they don't use channel object. Assign a URL to Url.AbsoluteUri in ASP.NET, and WCF change endpoint address at runtime But they don't seem to be dealing with 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 it gave this error: System.InvalidOperationException: Attempted to get contract type for IClientChannel, but that type is not a ServiceContract, nor does it inherit a ServiceContract.

like image 676
NealWalters Avatar asked Sep 02 '16 13:09

NealWalters


2 Answers

IClientMessageInspector is not the right place the manipulate the Channel, you should use IEndpointBehavior instead:

From MSDN

Implements methods that can be used to extend run-time behavior for an endpoint in either 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 the excelent post of Carlos Figueira about IEndpointBehavior: https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/04/wcf-extensibility-iendpointbehavior/

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

Hope it helps.

like image 61
Ricardo Pontual Avatar answered Nov 16 '22 12:11

Ricardo Pontual


Using the interface IEndpointBehavior, you'll have access to the ApplyClientBehavior method, which exposes the ServiceEndPoint instance. Now you can change the value for the Address by defining a new EndpointAddress instance.

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)
    {
    }
}
like image 2
Dieter Gobeyn Avatar answered Nov 16 '22 13:11

Dieter Gobeyn