{"id":4599,"date":"2017-01-29T20:23:21","date_gmt":"2017-01-29T20:23:21","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=4599"},"modified":"2017-01-29T20:23:21","modified_gmt":"2017-01-29T20:23:21","slug":"remoting-in-c-legacy-code","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/remoting-in-c-legacy-code\/","title":{"rendered":"Remoting in C# (legacy code)"},"content":{"rendered":"<p>In another post I looked at remoting using WCF but what were things like before WCF (or what&#8217;s an alternative to WCF)? I thought I&#8217;d post just the bare bones for getting a really simple service and client up and running.<\/p>\n<p><strong><em>Note: Microsoft recommends new remoting code uses WCF, so this post is more for understanding legacy code.<\/em><\/strong><\/p>\n<p><em>Note: I am not going to go into the lifecycle, singletons\/single instances etc. here, I&#8217;m just going to concentrate on the code to get something working.<\/em><\/p>\n<p><strong>The Server<\/strong><\/p>\n<p>As per my previous post on WCF remoting, we&#8217;re going to simply create a console application to act as our server, so go ahead an create one (mine&#8217;s named OldRemoteServer) and then add the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic interface IRemoteService\r\n{\r\n   void Write(string message);\r\n}\r\n<\/pre>\n<p>into a file of it&#8217;s own, then our client can link to it in our client&#8217;s Visual Studio solution.<\/p>\n<p>Here&#8217;s an implementation for the above<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class RemoteService : MarshalByRefObject, IRemoteService\r\n{\r\n   public void Write(string message)\r\n   {\r\n      Console.WriteLine(message);\r\n   }\r\n}\r\n<\/pre>\n<p><em>Note: The implementation needs to be derived from MarshalByRefObject or the class needs to be marked with the Serializable attribute or implement ISerializable which obviously makes sense. We&#8217;re solely going to look at MarshalByRefObject implementation for now as these will be passed by reference to the client, whereas the serializable implementations are aimed at passing by value.<\/em><\/p>\n<p>Now let&#8217;s put some code in the Main method of our Console app.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar channel = new TcpChannel(1002);\r\nChannelServices.RegisterChannel(channel, false);\r\n\r\nRemotingConfiguration.RegisterWellKnownServiceType(\r\n  typeof(RemoteService), \r\n  &quot;Remote&quot;, \r\n   WellKnownObjectMode.Singleton);\r\n\r\n\/\/ now let's ensure the console remains open\r\nConsole.ReadLine();\r\n<\/pre>\n<p>In the above code we&#8217;re using a Tcp channel with the port number 1002 and in the RegisterWellKnownServiceType, we&#8217;re registering the service type (this should be the implementation, not the interface) and supply a name &#8220;Remote&#8221; for it. In this case I&#8217;m also setting it to be a Singleton.<\/p>\n<p>You&#8217;ll need to add a reference to System.Runtime.Remoting and the following using clauses<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing System.Runtime.Remoting;\r\nusing System.Runtime.Remoting.Channels;\r\nusing System.Runtime.Remoting.Channels.Tcp;\r\n<\/pre>\n<p><strong>The Client<\/strong><\/p>\n<p>Create another Console application to simply test this and add the file with the IRemoteService interface.<\/p>\n<p><em>I&#8217;ve simply added it by selecting the client solution, the Add&#8230; | Existing Item, locate the file and instead of clicking the Add button select the dropdown to Add As Link. Then if you change the interface it&#8217;ll be immediately reflected in the client &#8211; ofcourse in a more complex application we&#8217;d have the interfaces in their own assembly.<\/em><\/p>\n<p>Now to get the client to call the server we simply place the following in the Main method of the Console app.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar obj = (IRemoteService)Activator.GetObject(\r\n   typeof(IRemoteService), \r\n   &quot;tcp:\/\/localhost:1002\/Remote&quot;);\r\n\r\nobj.Write(&quot;Hello World&quot;);\r\n<\/pre>\n<p>In the above you&#8217;ll see that we use the Activator to get an object and supply the type, then the next line shows we&#8217;re using the Tcp channel, port 1002 as set up in the server and the name from the server we game our object &#8220;Remote&#8221;. <\/p>\n<p>This creates a transparent proxy which we then simply call the interface method Write on.<\/p>\n<p><strong>Configuration<\/strong><\/p>\n<p>In the above example code I&#8217;ve simply hard-coded the configuration details but ofcourse we can create a .config file to instead handle such configurations. <\/p>\n<p>Let&#8217;s replace all the server Main method code with the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nRemotingConfiguration.Configure(&quot;Server.config&quot;, false);\r\n<\/pre>\n<p>Add an App.config to the project, we&#8217;re going to rename it Server.config for this example and ensure that the files&#8217;s properties (in Visual Studio) are set to Copy Always (or Copy if newer) to ensure the copy in the bin folders is upto date.<\/p>\n<p>Now here&#8217;s the Server.config which recreates the singleton, tcp, port 1002 settings previously handled in code<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;\r\n&lt;configuration&gt;\r\n  &lt;system.runtime.remoting&gt;\r\n  &lt;application&gt;\r\n    &lt;service&gt;\r\n      &lt;wellknown\r\n        type=&quot;OldRemoteServer.RemoteService, OldRemoteServer&quot;\r\n        objectUri=&quot;Remote&quot;\r\n        mode=&quot;Singleton&quot; \/&gt;\r\n    &lt;\/service&gt;\r\n    &lt;channels&gt;\r\n      &lt;channel ref=&quot;tcp&quot; port=&quot;1002&quot;\/&gt;\r\n    &lt;\/channels&gt;\r\n  &lt;\/application&gt;\r\n\r\n  &lt;\/system.runtime.remoting&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n<p>Now if you run the server and then the client, everything should work as before. <\/p>\n<p>Next up, let&#8217;s set the client up to use a configuration file&#8230;<\/p>\n<p>So we&#8217;ll add an App.config file to the client now, but let&#8217;s name it Client.config and again set the Visual Studio properties to ensure it&#8217;s always copied to the bin folder.<\/p>\n<p>Add the following to the configuration file<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;\r\n&lt;configuration&gt;\r\n  &lt;system.runtime.remoting&gt;\r\n    &lt;application&gt;\r\n      &lt;client&gt;\r\n        &lt;wellknown \r\n          type=&quot;OldRemoteServer.RemoteService, OldRemoteServer&quot; \r\n          url=&quot;tcp:\/\/localhost:1002\/Remote&quot; \/&gt;\r\n      &lt;\/client&gt;\r\n    &lt;\/application&gt;\r\n  &lt;\/system.runtime.remoting&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n<p>It might seem a little odd that we&#8217;re declaring the type as the implementation within the server code, but the reason will hopefully become clear.<\/p>\n<p>Add a reference within the client to the RemoteServer (if you have the implementation in a DLL, all the better, we didn&#8217;t do that, so I&#8217;m referencing the server EXE itself). This now give us access to the implementation of the RemoteService.<\/p>\n<p>Change the client Main method to <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nRemotingConfiguration.Configure(&quot;Client.config&quot;, false);\r\n\r\nvar obj = new RemoteService();\r\nobj.Write(&quot;Hello World&quot;);\r\n<\/pre>\n<p>don&#8217;t forget to add the using clause<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing System.Runtime.Remoting;\r\n<\/pre>\n<p>This bit might seem a little strange, based upon what we&#8217;ve previously done and how we&#8217;ve kept a separation of interface and implementation. Aren&#8217;t we now simply creating a local instance of the RemoteService, you might ask. <\/p>\n<p>Well try it, run the server and then the client and you&#8217;ll find .NET has created a transparent proxy for us and calls to the RemoteService will in fact go to the server. <\/p>\n<p>Whilst this makes things very easy, I must admit I prefer to not reference the implementation of the RemoteService. <\/p>\n<p><strong>What about named pipes?<\/strong><\/p>\n<p>Let&#8217;s now look at the changes to use the IPC protocol (for implementing named pipes) in .NET remoting. I&#8217;ll just briefly cover the changes required to implement this.<\/p>\n<p>To start with let&#8217;s rewrite the server and client in code. So first the Main method in the server should now look like<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar channel = new IpcChannel(&quot;ipcname&quot;);\r\nChannelServices.RegisterChannel(channel, false);\r\n\r\nRemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteService),\r\n   &quot;Remote&quot;,\r\n   WellKnownObjectMode.Singleton);\r\n\r\nConsole.ReadLine();\r\n<\/pre>\n<p>So the only real difference from the Tcp implementation is the use of an IpcChannel and the name supplied instead of a port.<\/p>\n<p>The client then looks like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar obj = (IRemoteService)Activator.GetObject(\r\n   typeof(IRemoteService), \r\n   &quot;ipc:\/\/ipcname\/Remote&quot;);\r\n\r\nobj.Write(&quot;Hello World&quot;);\r\n<\/pre>\n<p>Simple enough.<\/p>\n<p>Now let&#8217;s change the code to use a configuration file.<\/p>\n<p>The server Main method should now look like this<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nRemotingConfiguration.Configure(&quot;Server.config&quot;, false);\r\nConsole.ReadLine();\r\n<\/pre>\n<p>and the Server.config should look like this<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;\r\n&lt;configuration&gt;\r\n  &lt;system.runtime.remoting&gt;\r\n  &lt;application&gt;\r\n    &lt;service&gt;\r\n      &lt;wellknown\r\n        type=&quot;OldRemoteServer.RemoteService, OldRemoteServer&quot;\r\n        objectUri=&quot;Remote&quot;\r\n        mode=&quot;Singleton&quot; \/&gt;\r\n    &lt;\/service&gt;\r\n    &lt;channels&gt;\r\n      &lt;channel ref=&quot;ipc&quot; portName=&quot;ipcname&quot;\/&gt;\r\n    &lt;\/channels&gt;\r\n  &lt;\/application&gt;\r\n\r\n  &lt;\/system.runtime.remoting&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n<p>The client code should be<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nRemotingConfiguration.Configure(&quot;Client.config&quot;, false);\r\nvar obj = new RemoteService();\r\nobj.Write(&quot;Hello World&quot;);\r\n<\/pre>\n<p>and it&#8217;s Client.config should look like this<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;\r\n&lt;configuration&gt;\r\n  &lt;system.runtime.remoting&gt;\r\n    &lt;application&gt;\r\n      &lt;client&gt;\r\n        &lt;wellknown \r\n          type=&quot;OldRemoteServer.RemoteService, OldRemoteServer&quot; \r\n          url=&quot;ipc:\/\/ipcname\/Remote&quot; \/&gt;\r\n      &lt;\/client&gt;\r\n    &lt;\/application&gt;\r\n  &lt;\/system.runtime.remoting&gt;\r\n&lt;\/configuration&gt;\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In another post I looked at remoting using WCF but what were things like before WCF (or what&#8217;s an alternative to WCF)? I thought I&#8217;d post just the bare bones for getting a really simple service and client up and running. Note: Microsoft recommends new remoting code uses WCF, so this post is more for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3,155],"tags":[],"class_list":["post-4599","post","type-post","status-publish","format-standard","hentry","category-c","category-remoting"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4599","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=4599"}],"version-history":[{"count":8,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4599\/revisions"}],"predecessor-version":[{"id":4616,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4599\/revisions\/4616"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=4599"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=4599"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=4599"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}