Share via


It's All in the BindingContext

The binding context stores all of the dynamic information needed when the construction of the channel stack is in progress. When we go to build a channel stack from a binding, we first need to stamp out a set of binding elements. Think of this as constructing a custom binding from the instantaneous settings of the binding you're building it from. If we change the original binding in the future, that doesn't affect the binding elements we created. The same is true in reverse. If we change the binding elements, it doesn't affect the original binding or any other binding elements created from that binding.

The other piece we need is a bag to hold all of the miscellaneous settings we encounter. That bag is the binding parameter collection. You'll initially populate the bag through design-time configuration of the binding and contract. More likely though, you'll use someone else's code that will populate the bag by examining your service description and pulling interesting bits off to place into the collection. Then, any settings that need to be pushed down the channel stack during creation are put into the collection until a channel lower in the stack needs them. This replaces the old method of stashing any extra binding elements in the UnhandledBindingElements collection.

 public class BindingContext
{
   public BindingContext(CustomBinding binding, BindingParameterCollection parameters);
   public BindingContext(CustomBinding binding, BindingParameterCollection parameters, Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode);

   public CustomBinding Binding { get; }
   public BindingParameterCollection BindingParameters { get; }
   public Uri ListenUriBaseAddress { get; set; }
   public ListenUriMode ListenUriMode { get; set; }
   public string ListenUriRelativeAddress { get; set; }
   public BindingElementCollection RemainingBindingElements { get; }

   public IChannelFactory<TChannel> BuildInnerChannelFactory<TChannel>();
   public bool CanBuildInnerChannelFactory<TChannel>();
   public BindingContext Clone();
   public T GetInnerProperty<T>() where T : class;
}

The listen address mostly does what it says and provides the server side of a connection with an indication of the address to listen on. There is some magic that goes on when you only specify part of the listen address and rely on us to generate the rest for you automatically. For some particularly clever transports, you can get away with specifying nothing at all for the listen address. If the ListenUriBaseAddress is null and the ListenUriMode is set to Unique, it means that the transport should generate the entire base address from scratch including details like the hostname and port.

The remaining methods are straightforward for delegating to from your channel implementation. Rather than directly using the inner channel underlying your channel to chain the construction process, you delegate the building or querying operation to the inner channel through the binding context. You have access to the binding elements that go into making the inner channel for examination, but you don't have to worry about the actual instance.

Next time: Some Changes for Channels and Transports in the June CTP, Part 2