IOutputChannel over IRequestChannel

Link. August 29, 2007. Comments [4]. Posted in: WCF

Udi Dahan ranted a bit about the WCF transport channel model and it's extensive use of generics. More to the point, Udi was running into some trouble trying to simply send a message, one way, over an arbitrary transport channel that could either be one way or not. The problem he runs into is dealing in a generic fashion with the different Channel Shapes that WCF exposes.

I commented on his blog that maybe it would be possible for him to use a custom binding and using the OneWayBindingElement binding element to "change" the shape of the underlying, two-way channel into a single-way channel he could use by just coding against the IOutputChannel interface. Udi responsed:

"I’m trying to write transports for NServiceBus which will make use of the WCF bindings. So, since BasicHttpBinding only supports IRequestChannel and not IOutputChannel I have to deal with this. It’s just nuts that there isn’t some more useful shared interface between them." 

From his description, I gather that Udi is (with good intentions of keeping things simple) equating channels with standard bindings, but this isn't quite so. The BasicHttpBinding is just a binding; not a channel itself. However, this standard binding will certainly force a matched two-way channel shape (IRequestChannel) based on the underlying transport channel used (HttpTransportChannel/HttpsTransportChannel).

There's nothing inherently wrong about creating a new binding that is based on one of the standard channels but has extra binding elements layered on top. Here's a sample:

EndpointAddress epa =
   new EndpointAddress("http://localhost:8254/myservice/myserv.svc");

WSHttpBinding wsHttp = new WSHttpBinding(SecurityMode.None, false);

CustomBinding binding = CreateOneWayBinding(wsHttp);
// could also be
// CreateOneWayBinding(new BasicHttpBinding());

IChannelFactory<IOutputChannel> factory =
   binding.BuildChannelFactory<IOutputChannel>();
factory.Open();
IOutputChannel channel = factory.CreateChannel(epa);

Message myMessage = Message.CreateMessage(
   binding.MessageVersion, "Process", "some sample contents"
   );
channel.Open();
channel.Send(myMessage);
channel.Close();
factory.Close();

The CreateOneWayBinding() method used in the sample above is fairly simple:

static CustomBinding CreateOneWayBinding(Binding baseBinding)
{
   List<BindingElement> elems = new List<BindingElement>();
   elems.Add(new OneWayBindingElement());
   elems.AddRange(baseBinding.CreateBindingElements());
   return new CustomBinding(elems);
}

It basically creates a new CustomBinding based on the binding elements of the original binding (in this case one of the standard ones) and then layers the OneWayBindingElement, channel shape changing element on top.

Note: For some reason, this would not work if message security was enabled with the WSHttpBinding, but I didn't spent too much time looking at what the issue was, but otherwise works fine with the WSHttpBinding, BasicHttpBinding and NetTcpBinding, which is enough to make it useful on its own.



Tuesday, August 28, 2007 11:57:04 PM (SA Pacific Standard Time, UTC-05:00)
I've tried this and it doesn't work for me over BasicHttp (I haven't checked the rest). The exception that I get is "System.Net.HttpListenerException: The process cannot access the file because it is being used by another process..."

Any ideas?
Wednesday, August 29, 2007 6:20:33 AM (SA Pacific Standard Time, UTC-05:00)
Udi:

The code I posted sure works for a *client*-side channel (I tested it, and I'd be happy to send you the sample code if you want it). I'm curious, though, are you trying to create this way a *server*-side channel? Otherwise, HttpListener shouldn't get involved at all!

If you don't mind sharing some code, I'd be happy to take a look at...
Wednesday, August 29, 2007 4:26:26 PM (SA Pacific Standard Time, UTC-05:00)
Oh, I see. I'm looking for server-side channels. That's why it isn't working for me.
Wednesday, August 29, 2007 4:52:51 PM (SA Pacific Standard Time, UTC-05:00)
Udi: Any reason why you need to manipulate the stack at the channel level on the receive side? Sounds to me like it's easier to just use a generic one-way service contract with a catch-all operation and let ServiceHost do its thing normally; but if you can clarify your needs, I'm sure we can find something more suited to them.
Comments are closed.

Syndicate

About

Tomas Restrepo is a software developer located in Colombia, South America. His interests include .NET, Connected Systems, PowerShell and lately dynamic programming languages. More...

tomasrestrepo @ twitter My Flickr photostream My saved links on delicious My Technorati Profile

email: tomas@winterdom.com
msn: tomasr@passport.com

View my profile on LinkedIn

MVP logo

Ads


Categories

Statistics

Total Posts: 1035
This Year: 105
This Month: 4
This Week: 2
Comments: 802

Archive

Other

Copyright © 2002-2008, Tomas Restrepo.

Powered by: newtelligence dasBlog 2.1.8139.823

Sign In