Monday, April 19, 2010

How To: Build and Host a Remote Object in a Windows Service


Remote objects (that is, .NET objects accessed remotely using .NET Remoting technology) can be hosted in Windows services, custom executables, or ASP.NET. Clients communicate with remote objects hosted in custom executables or Windows services by using the TCP channel. Clients communicate with remote objects hosted in ASP.NET by using the HTTP channel.

This example shows how to write a simple "Hello World" remote application. The client passes a String to the remote object that appends the words "Hi There" to the string and returns the result back to the client. This code can be easily modified to execute a command or open an application on the remote server. In order to modify this sample to use HTTP rather than TCP, simply replace TCP with HTTP in the source files.

This example was compiled using C# in the 2.0 .Net Framework.

Overview
The “Hello World" client class interacts directly with the remote object class. The remote object class is installed on the remote server using the Windows Service Hosting Application.



Steps to create a remote object
1.       Create a Remote Client Class.
2.       Create the Remote Object Class.
3.       Create a Microsoft Windows Service Host Application.
4.       Install and start the Windows Service.


Step1: Create a Remote Client Class

using System;
using System.Data;
using System.Configuration;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace RemotingSamples
{
public class Client
{
public string Execute_Remote_Job()
{
//Create new client channel
foreach (IChannel channel in ChannelServices.RegisteredChannels)
{
   ChannelServices.UnregisterChannel(channel);
}
TcpChannel Chnl = new TcpChannel();
              
//Register Channel
ChannelServices.RegisterChannel(Chnl, false);

//Instansiate remote object

//Please replace localhost:8090 with the name and port number of your //remote server

HelloServer obj = (HelloServer)Activator.GetObject(typeof(RemotingSamples.HelloServer) , "tcp://localhost:8090/RemotingSamples.HelloServer");

//Call Remote object Method
String strRet = obj.RunMain_Job(“Hello World.”);

//**********Return the new string**************************

return strRet;

//*********************************************************
}
}
}



Step 2: Create a Remote Object

*Note: Derive the HelloServer class from MarshalByRefObject to make the class remotable.

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;

namespace RemotingSamples
{
public class HelloServer:MarshalByRefObject
{
//When you design a singleton object, override //InitializeLifetimeService and return a null object as the new lease, //indicating that this lease never expires
public override object InitializeLifetimeService()
{
return null;
}

//Create Remote object method here. This code can be easily modified to //execute a command or open an application on the remote server

public string RunMain_Job(string strHello)
{
            string strRet = "";
            strRet = strHello;

//************Append string and return it**************
           
strRet+= " Hi there";          
            return (strRet);
}
}
}




Step 3: Create a Microsoft Windows Service Host Application.
This procedure creates a Windows service application, which will be used to host the remote object. When the service is started it will configure the TCP remoting channel to listen for client requests.
Note   This procedure uses an Installer class and the Installutil.exe command line utility to install the Windows service. To uninstall the service, run Installutil.exe with the /u switch.

To create a Windows Service host application
1.           Add a new Visual C# Windows Service project called RemotingHost
2.           Use Solution Explorer to rename Service1.cs as RemotingHost.cs.
3.           Add the following code to RemotingHost.cs.

using System.Collections.Generic;
using System.ServiceProcess;
using System.Text;
using System.Runtime.Remoting;

namespace RemotingHost
{
    static class RemotingHost
    {
        ///
        /// The main entry point for the application.
        ///
        static void Main()
        {
            ServiceBase[] ServicesToRun;

            // More than one user Service may run within the same process. To add
            // another service to this process, change the following line to
            // create a second service object. For example,
            //
            //   ServicesToRun = new ServiceBase[] {new Service1(), new MySecondUserService()};
            //
            ServicesToRun = new ServiceBase[] { new HostService() };

            ServiceBase.Run(ServicesToRun);
        }
    }
}


4.           In RemotingHost.cs, rename the Service1 class as HostService and add the following code.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Runtime.Remoting;

namespace RemotingHost
{
    public partial class HostService : ServiceBase
    {
        public HostService()
        {
            InitializeComponent();          
        }

        protected override void OnStart(string[] args)
        {
            // TODO: Add code here to start your service.      
            System.Diagnostics.EventLog.WriteEntry(ServiceName, ServiceName + "::OnStart()");
            RemotingConfiguration.Configure(AppDomain.CurrentDomain.BaseDirectory.ToString() + "RemotingHost.exe.config",false);      
        }

        protected override void OnStop()
        {
            // TODO: Add code here to perform any tear-down necessary to stop your service.
            base.OnStop();          
        }
    }
}



5.           Add a new C# class file to the project and name it HostServiceInstaller.
6.           Add an assembly reference to the System.Configuration.Install.dll assembly and add the following code.


using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.ServiceProcess;
using System.Configuration.Install;

namespace RemotingHost
{
    [RunInstaller(true)]
    public class HostServiceInstaller : Installer
    {
        private ServiceInstaller HostInstaller;
        private ServiceProcessInstaller HostProcessInstaller;

        public HostServiceInstaller()
        {
            HostInstaller = new ServiceInstaller();
            HostInstaller.StartType = System.ServiceProcess.ServiceStartMode.Manual;
            HostInstaller.ServiceName = "RemotingHost";
            HostInstaller.DisplayName = "Remoting Host Service";
            Installers.Add(HostInstaller);
            HostProcessInstaller = new ServiceProcessInstaller();
            HostProcessInstaller.Account = ServiceAccount.User;
            Installers.Add(HostProcessInstaller);
        }
    }
}




7.           Within Solution Explorer, right-click RemotingHost, point to Add, and then click Add New Item.
8.           In the Templates list, click Text File and name the file app.config.
Configuration files with the name app.config are automatically copied by Visual Studio .NET as part of the build process to the output folder (for example, <projectdir>\bin\debug) and renamed as <applicationname>.config.

9.           Click OK to add the new configuration file.
10.       Add the following configuration elements to the new configuration file.

*Note make sure port number used is the same as in the client class


<configuration>
  <system.runtime.remoting>
    <application name="RemotingHost">
      <channels>
        <channel ref="tcp" port="8090">
          <serverProviders>
            <formatter ref="binary" />
          serverProviders>
        channel>
      channels>
      <service>
        <wellknown type=" RemotingSamples.HelloServer, RemotingSamples"
                        objectUri="RemotingSamples.HelloServer"
                        mode="Singleton" />
      service>
    application>
  system.runtime.remoting>
configuration>


Step 4: Install and start the Windows Service.
This procedure installs a Windows service using the installutil.exe utility and then starts the service.
Steps To install the Windows service
1.    Open a DOS command window and change directory to the folder which contains the executable file of your remote service.
D:\cd..

2.     If a pervious version has been installed please un-install this version first by running the installutil.exe\u utility to un-install the service.
Use the following in the command line to un-install.
installutil.exe/u RemotingHost.exe

3.    Run the installutil.exe utility to install the service.
Use the following line in the command line.
installutil.exe RemotingHost.exe

In the Set Service Login dialog box, enter user name and password
4.    View the output from the installutil.exe utility and confirm that the service is installed correctly.
5.     Close the DOS command window.


 Steps To Start the Windows service

1.       From the Administrative Tools program group in the control panel, start the Services MMC snap-in.
2.       In the Services list, find and right-click on RemotingHost, and then click Properties.
3.       Enter the full path to the service's configuration file into the Start parameters field.
Note:   A quick way to find the correct path is to select and copy the Path to executable field and paste it into the Start parameters field. Then add .config to the end of the string inside the quotation marks.
4.        Click Start to start the service.
5.        Click OK to close the Properties dialog box.
6.       Confirm that the service status changes to Started in the services list.