{"id":170,"date":"2007-03-06T10:54:02","date_gmt":"2007-03-06T17:54:02","guid":{"rendered":"http:\/\/kennyw.com\/indigo\/170"},"modified":"2007-03-06T10:54:02","modified_gmt":"2007-03-06T17:54:02","slug":"boilerplate-code-for-custom-encoder-binding-elements","status":"publish","type":"post","link":"https:\/\/kennyw.com\/?p=170","title":{"rendered":"Boilerplate code for custom Encoder Binding Elements"},"content":{"rendered":"<p>Part of the process involved in writing a custom <code class=\"classname\">MessageEncoder<\/code> is hooking your encoder up to a binding stack.  This is accomplished using a subclass of <code class=\"classname\">MessageEncodingBindingElement<\/code>.  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 &#8220;below&#8221; them in the stack.<\/p>\n<p>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 &#8220;adjunct&#8221; 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 <code>BindingParameters<\/code>.  For example, a MessageEncodingBindingElement can add itself to the BindingParameters collection:<\/p>\n<p><code>context.BindingParameters.Add(<\/code><code class=\"keyword\">this<\/code>);<\/p>\n<p>And later the TransportBindingElement can fish out the encoder when it is building the relevant factory\/listener:<\/p>\n<p><code class=\"classname\">Collection<\/code><code>&lt;<\/code><code class=\"classname\">MessageEncodingBindingElement<\/code><code>&gt;messageEncoderBindingElements<br \/>\n                = context.BindingParameters.FindAll&lt;<\/code><code class=\"classname\">MessageEncodingBindingElement<\/code><code>&gt;();<\/code><\/p>\n<p>Unfortunately, the base <code class=\"classname\">MessageEncodingBindingElement<\/code> does not take care of adding itself to the BindingParameters collection in its default [Can]Build methods.  Therefore, <strong>every<\/strong> subclass needs to add the following four boilerplate overrides. Furthermore, it will be a breaking change to fix this in V2, so it&#8217;s unclear if we will be able to fix this in the next release \ud83d\ude41<\/p>\n<p>        <code class=\"keyword\">public override <\/code><code class=\"classname\">IChannelFactory<\/code><code>&lt;TChannel&gt; BuildChannelFactory&lt;TChannel&gt;(<\/code><code class=\"classname\">BindingContext<\/code><code> context)<br \/>\n        {<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">if<\/code><code> (context == <\/code><code class=\"keyword\">null<\/code>)<code><br \/>\n&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">throw new <\/code><code class=\"classname\">ArgumentNullException<\/code><code>(\"context\");<br \/>\n&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;context.BindingParameters.Add(<\/code><code class=\"keyword\">this<\/code><code>);<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code><code> context.BuildInnerChannelFactory&lt;TChannel&gt;();<br \/>\n        }<\/p>\n<p>        <\/code><code class=\"keyword\">public override <\/code><code class=\"classname\">IChannelListener<\/code><code>&lt;TChannel&gt; BuildChannelListener&lt;TChannel&gt;(<\/code><code class=\"classname\">BindingContext<\/code><code> context)<br \/>\n        {<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">if<\/code><code> (context == <\/code><code class=\"keyword\">null<\/code>)<code><br \/>\n&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">throw new <\/code><code class=\"classname\">ArgumentNullException<\/code><code>(\"context\");<br \/>\n&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;context.BindingParameters.Add(<\/code><code class=\"keyword\">this<\/code><code>);<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code><code> context.BuildInnerChannelListener&lt;TChannel&gt;();<br \/>\n        }<\/p>\n<p>        <\/code><code class=\"keyword\">public override <\/code><code class=\"keyword\">bool<\/code><code> CanBuildChannelFactory&lt;TChannel&gt;(<\/code><code class=\"classname\">BindingContext<\/code><code> context)<br \/>\n        {<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">if<\/code><code> (context == <\/code><code class=\"keyword\">null<\/code>)<code><br \/>\n&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">throw new <\/code><code class=\"classname\">ArgumentNullException<\/code><code>(\"context\");<br \/>\n&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;context.BindingParameters.Add(<\/code><code class=\"keyword\">this<\/code><code>);<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code><code> context.CanBuildInnerChannelFactory&lt;TChannel&gt;();<br \/>\n        }<\/p>\n<p>        <\/code><code class=\"keyword\">public override <\/code><code class=\"keyword\">bool<\/code><code> CanBuildChannelListener&lt;TChannel&gt;(<\/code><code class=\"classname\">BindingContext<\/code><code> context)<br \/>\n        {<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">if<\/code><code> (context == <\/code><code class=\"keyword\">null<\/code>)<code><br \/>\n&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">throw new <\/code><code class=\"classname\">ArgumentNullException<\/code><code>(\"context\");<br \/>\n&nbsp;&nbsp;}<\/p>\n<p>&nbsp;&nbsp;context.BindingParameters.Add(<\/code><code class=\"keyword\">this<\/code><code>);<br \/>\n&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code><code> context.CanBuildInnerChannelListener&lt;TChannel&gt;();<br \/>\n        }<br \/>\n<\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"class_list":["post-170","post","type-post","status-publish","format-standard","hentry","category-indigo"],"_links":{"self":[{"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/posts\/170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=170"}],"version-history":[{"count":0,"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/posts\/170\/revisions"}],"wp:attachment":[{"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}