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());
IChannelFactoryfactory =
binding.BuildChannelFactory();
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)
{
Listelems = new List ();
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.