Creating CustomBindings programatically
I had another revelation earlier, when going over Nicholas Allen's explanation of the GetProperty<T> method and BindingContexts:
The Binding objects supplied by the WCF framework are only a wrapper. They have no logic in them. They mean nothing. They do nothing except allow access to the internal properties of their BindingElements. The BindingElements are the ones who do the real work.
There. It's a bit harsh, but it had to be said. Took me a while to wrap my head around it. It's syntactic sugar, since it's easier to do this:
NetTcpBinding binding = new NetTcpBinding();
binding.ReaderQuotas.MaxArrayLength = 512000;
than:
CustomBinding binding = new CustomBinding(new TransactionFlowBindingElement(), new BinaryMessageEncodingBindingElement(), new WindowsStreamSecurityBindingElement(), new TcpTransportBindingElement());
new BindingContext(binding, new BindingParameterCollection()).GetInnerPropertyProperty<XmlDictionaryReaderQuotas>().MaxArrayLength = 512000;
The two, however, are equivalent. You can think of the NetTcpBinding class as a pre-selected 'kit' with several predefined selections, whereas the CustomBinding is a do-it-yourself set. The basic building blocks, though, are the same.
The problem with this is that if I want to deviate from the given settings, I have to start from scratch. Let's say I have the NetTcpBinding which by default uses the BinaryMessageEncodingBindingElement. If I want to replace that with a TextMessageEncodingBindingElement for some reason, or maybe the CompressionMessageEncodingBindingElement that is a part of the SDK samples for WCF, I can't do that with the NetTcpBinding. I have to create my own custom binding based on the NetTcpBinding and modify it there.
Luckily, it's not that hard, and simpler than the ugly bit of code I had earlier:
note: The CompressionMessageEncodingBindingElement encapsulates the encoder that actually encodes the message.
// Create a custom binding based on NetTcp
CustomBinding compressingTcpBinding = new CustomBinding(new NetTcpBinding());
// Find the current MessageEncoding binding and its position in the BindingElement stack.
BinaryMessageEncoderBindingElement currentEncoder = compressingTcpBinding.Find<BinaryMessageEncoderBindingElement>();
int encoderIndex = compressingTcpBinding.Elements.IndexOf(currentEncoder);
// Create the new Encoder
CompressionMessageEncoderBindingElement compressionEncoder = new CompressionMessageEncoderBindingElement(currentEncoder);
// Add it to the stack instead of the current encoder.
compressingTcpBinding.Elements.SetItem(encoderIndex, compressionEncoder);
There - a perfect little NetTcpBinding clone with the Encoder neatly replaced, and all done by code, so we have a better idea of what actually happens there.
Nicholas Allen has promised an upcoming article about the binding element stack - waiting expectantly.