Boilerplate code for custom Encoder Binding Elements

Part of the process involved in writing a custom MessageEncoder is hooking your encoder up to a binding stack. This is accomplished using a subclass of MessageEncodingBindingElement. The way our build process works is that we will take the first BindingElement within a Binding, and call [Can]CreateChannel[Factory|Listener]() on it. By default, these 4 calls will simply delegate to the BindingElement “below” them in the stack.

This default behavior is not exactly what you want in your MessageEncodingBindingElement. While most binding elements add an item to the channel stack, Message Encoders are an “adjunct” binding element. That is, they provide parameters to other binding elements (in this case the transport). The way that parameters are provided to other parts of the build process is through BindingParameters. For example, a MessageEncodingBindingElement can add itself to the BindingParameters collection:

context.BindingParameters.Add(this);

And later the TransportBindingElement can fish out the encoder when it is building the relevant factory/listener:

Collection<MessageEncodingBindingElement>messageEncoderBindingElements
= context.BindingParameters.FindAll<
MessageEncodingBindingElement>();

Unfortunately, the base MessageEncodingBindingElement does not take care of adding itself to the BindingParameters collection in its default [Can]Build methods. Therefore, every subclass needs to add the following four boilerplate overrides. Furthermore, it will be a breaking change to fix this in V2, so it’s unclear if we will be able to fix this in the next release 🙁

public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.BuildInnerChannelFactory<TChannel>();
}

public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.BuildInnerChannelListener<TChannel>();
}

public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.CanBuildInnerChannelFactory<TChannel>();
}

public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.CanBuildInnerChannelListener<TChannel>();
}

Leave a Reply

Your email address will not be published. Required fields are marked *