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>();
}