{"id":21,"date":"2005-05-23T23:15:13","date_gmt":"2005-05-24T06:15:13","guid":{"rendered":"http:\/\/kennyw.com\/indigo\/21"},"modified":"2005-05-23T23:15:13","modified_gmt":"2005-05-24T06:15:13","slug":"channels-103-addressing-the-world","status":"publish","type":"post","link":"https:\/\/kennyw.com\/?p=21","title":{"rendered":"Channels 103: Addressing the World"},"content":{"rendered":"<p>The next step in our custom transport walk-through is to create our channel managers.  This includes an <code><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms405876.aspx\">IChannelFactory<\/a><\/code> for our client side channels, and an <code><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms405883.aspx\">IChannelListener<\/a><\/code> for our service-side channels.<\/p>\n<p>Both IChannelFactory and IChannelListener derive from <code>IChannelManager<\/code>.  IChannelManager is responsible for tracking channels that are created or accepted.  IChannelManager also has a property to control the MessageVersion supported for Messages sent or received on its channels.  Lastly, it requires you to specify a Scheme to use for message addressing.<\/p>\n<p>Which leads me to a crucial aspect in defining a channel, namely: what is your addressing model?<\/p>\n<p>For layered channels, the addressing model is simply that of the channels they are layered on top of.  Such implementations look like:<\/p>\n<div class=\"code\">\n<div class=\"indent1\"><code class=\"keyword\">public override string<\/code> Scheme<br \/>\n        { <\/p>\n<div class=\"indent1\"><code class=\"keyword\">get<\/code> { <code class=\"keyword\">return<\/code> InnerListenerFactory.Scheme; }<\/div>\n<p> }<\/p>\n<p><code class=\"keyword\">public override void<\/code> SetUri(Uri uri)<br \/>\n        { <\/p>\n<div class=\"indent1\"><code class=\"keyword\">return<\/code> InnerListenerFactory.SetUri(uri); <\/div>\n<p> }<\/p>\n<p><code class=\"keyword\">public override void<\/code> SetUniqueUri()<br \/>\n        { <\/p>\n<div class=\"indent1\"><code class=\"keyword\">return<\/code> InnerListenerFactory.SetUniqueUri(); <\/div>\n<p> }\n<\/p><\/div>\n<\/div>\n<p>For transport channels, it&#8217;s an area that takes some thought.  While HTTP has a <a href=\"http:\/\/www.w3.org\/Addressing\/URL\/4_1_HTTP.html\">pre-defined syntax and semantic<\/a>, when writing a new transport you need to define both of these.  Concretely, this includes a <a href=\"http:\/\/www.w3.org\/Addressing\/schemes\">scheme<\/a> and its associated <a href=\"http:\/\/www.faqs.org\/rfcs\/rfc3986.html\">URI syntax<\/a>.  This work is closely related to how you bind your protocol to SOAP.<\/p>\n<p>The first item to consider is how your client Channels will resolve the URI.  For example, HTTP takes the host name and TCP port of the URI (based on the defined <a href=\"http:\/\/www.faqs.org\/rfcs\/rfc3986.html\">URI grammar<\/a>), uses DNS to resolve the host name into an IP Address, establishes a TCP connection to the resulting (IP Address, port), and sends an HTTP request using the path portion of the URI in our POST request.<\/p>\n<p>The second factor in your URI design is how to match an incoming URI to an IListenerFactory (which will dispatch to a service).   IListenerFactory URIs are broken down into 2 parts: a base address and a relative address.  The base address is defined by your hosting environment (ServiceHost&lt;T&gt;, IIS vroot, etc). Individual endpoints then define a simple relative address.  Note that an endpoint can be configured with a full URI, but this is only necessary in a few corner cases.  This model allows for the host to be decoupled from its endpoints, and also allows the transport to optimize the network resources it uses (i.e. we only require at <em>most<\/em> one per base address, and can share that resource among relative endpoints).<\/p>\n<p>Given these requirements, we define our URI syntax for UDP as:<\/p>\n<div class=\"indent1\"><code>soap.udp:\/\/ host [\":\" port] path-absolute<\/code><\/p>\n<p>where <em>host<\/em>, <em>port<\/em>, and <em>path-absolute<\/em> are defined in the ABNF of <a href=\"http:\/\/www.faqs.org\/rfcs\/rfc3986.html\">RFC 3986<\/a>.<\/div>\n<p>For example: <code>soap.udp:\/\/localhost:7000\/service\/endpoint<\/code><\/p>\n<p>Our UdpOutputChannel will take the hostname (localhost) and convert it to an IP Address:<\/p>\n<div class=\"code\">\n<div class=\"indent1\">\n            <code class=\"keyword\">switch<\/code> (remoteAddress.Uri.HostNameType)<br \/>\n            {<\/p>\n<div class=\"indent1\">\/\/ &#8230;<br \/>\n                <code class=\"keyword\">case<\/code> UriHostNameType.IPv4:<br \/>\n                <code class=\"keyword\">case<\/code> UriHostNameType.IPv6:<\/p>\n<div class=\"indent1\">remoteIP = IPAddress.Parse(remoteAddress.Uri.Host);<br \/>\n                        <code class=\"keyword\">break<\/code>;<\/div>\n<p>                <code class=\"keyword\">case<\/code> UriHostNameType.Basic:<br \/>\n                <code class=\"keyword\">case<\/code> UriHostNameType.Dns:<\/p>\n<div class=\"indent1\">{<br \/>\n                        IPHostEntry hostEntry = Dns.GetHostEntry(remoteAddress.Uri.Host);<br \/>\n                        if (hostEntry.AddressList.Length > 0)<br \/>\n                        {<br \/>\n                            remoteIP = hostEntry.AddressList[0];<br \/>\n                        }<br \/>\n                        \/\/ &#8230;<br \/>\n                    }<br \/>\n                        <code class=\"keyword\">break<\/code>;<\/div>\n<\/div>\n<p>}<\/p><\/div>\n<\/div>\n<p>We will then use the resulting IP Address along with the UDP port from the URI (7000), construct a UDP socket to that remote endpoint, and set:<\/p>\n<div class=\"code\">message.To = RemoteUri (soap.udp:\/\/localhost:7000\/service\/endpoint).<\/div>\n<p>When our UdpListenerFactory (which is on the receiving end of the UDP socket) deserializes the message, it will compare the incoming message.To against its Uri and only accept the message if the two values match.  More advanced implementations could factor out the listening socket into a shared app-domain wide resource that dispatches to the appropriate UdpListenerFactory based on the To of the incoming message.<\/p>\n<p>With our transport addressing model crisply defined, we continue  on to actually sending and receiving Messages over UDP!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The next step in our custom transport walk-through is to create our channel managers. This includes an IChannelFactory for our client side channels, and an IChannelListener for our service-side channels. Both IChannelFactory and IChannelListener derive from IChannelManager. IChannelManager is responsible for tracking channels that are created or accepted. IChannelManager also has a property to control [&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":[26,80,85,91],"class_list":["post-21","post","type-post","status-publish","format-standard","hentry","category-indigo","tag-channel","tag-transports","tag-wcf","tag-work"],"_links":{"self":[{"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/posts\/21","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=21"}],"version-history":[{"count":0,"href":"https:\/\/kennyw.com\/index.php?rest_route=\/wp\/v2\/posts\/21\/revisions"}],"wp:attachment":[{"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kennyw.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}