In contrast to some other frameworks (Java RMI, J2EE EJB, COM+, and so on), .NET Remoting allows you to choose quite freely how you want to deploy your server application. You can publish the objects in any kind of managed application—console, Windows Forms, and Windows services—or host them in IIS.

Console Applications

Deploying servers as .NET console applications is the easiest way to get started; every example up to this point has been designed to run from the console. The features are easily observable: instant debug output, and starting, stopping, and debugging is possible using the IDE.

Production applications nevertheless have different demands: when using console applications, you need to start the program after logging onto a Windows session. Other possible requirements such as logging, authentication, and encryption are hard to implement using this kind of host.

Windows Services

If you don't want to host the objects in IIS, classic Windows services are the way to go. Visual Studio .NET (and the .NET Framework in general) makes it easy for you to develop a Windows service application. It takes care of most issues, starting from the installation of the service to encapsulating the communication between the service control manager and your service application.

Integrating remoting in Windows services can also be viewed from another standpoint: when your primary concern is to write a Windows service—for example, to provide access to privileged resources, you can easily implement the communication with your clients using .NET Remoting. This is somewhat different from conventional approaches in the days before .NET, which forced you to define distinct communication channels using named pipes, sockets, or the COM ROT.

Cross-process remoting on a local machine using a TCP channel ought to be fast enough for most applications.

Porting to Windows Services

In the .NET Framework, a Windows service simply is a class that extends System.ServiceProcess.ServiceBase. You basically only have to override onStart() to do something useful.

A baseline Windows service is shown in Listing 4-5.

Listing 4-5: A Baseline Windows Service

start example
 using System; using System.Diagnostics; using System.ServiceProcess; namespace WindowsService {    public class DummyService : System.ServiceProcess.ServiceBase    {       public static String SVC_NAME = "Some dummy service";       public DummyService ()       {          this.ServiceName = SVC_NAME;       }       static void Main()       {             // start the service             ServiceBase.Run(new DummyService());       }       protected override void OnStart(string[] args)       {             // do something meaningful       }       protected override void OnStop()       {             // stop doing anything meaningful ;)       }    } } 
end example

A service like this will not be automatically installed in the service manager, so you have to provide a special Installer class that will be run during the execution of installutil.exe (from the .NET command prompt).

Listing 4-6 shows a basic service installer that registers the service to be run using the System account and started automatically during boot-up.

Listing 4-6: A Basic Windows Service Installer

start example
 using System; using System.Collections; using System.Configuration.Install; using System.ServiceProcess; using System.ComponentModel; using WindowsService; [RunInstallerAttribute(true)] public class MyProjectInstaller: Installer {    private ServiceInstaller serviceInstaller;    private ServiceProcessInstaller processInstaller;    public MyProjectInstaller()    {       processInstaller = new ServiceProcessInstaller();       serviceInstaller = new ServiceInstaller();       processInstaller.Account = ServiceAccount.LocalSystem;       serviceInstaller.StartType = ServiceStartMode.Automatic;       serviceInstaller.ServiceName = DummyService.SVC_NAME;       Installers.Add(serviceInstaller);       Installers.Add(processInstaller);    } } 
end example

The installer has to be in your main assembly and has to have [RunInstallerAttribute(true)] set. After compiling the preceding C# files, you will have created a baseline Windows service that can be installed with installutil.exe.

When porting the Remoting server to become a Windows service, you might want to extend the base service to also allow it to write to the Windows event log. Therefore you have to add a static variable of type EventLog to hold an instance acquired during void Main(). As an alternative, you could also set the AutoLog property of the service and use the static method EventLog.WriteEntry().You will also have to extend onStart() to configure remoting to allow the handling of requests as specified in the configuration file. The complete source code for the Windows service–based remoting server is shown in Listing 4-7.

Listing 4-7: A Simple Windows Service to Host Your Remote Components

start example
 using System; using System.Diagnostics; using System.ServiceProcess; using System.Runtime.Remoting; namespace WindowsService {    public class RemotingService : System.ServiceProcess.ServiceBase    {       private static EventLog evt = new EventLog("Application");       public static String SVC_NAME = ".NET Remoting Sample Service";       public RemotingService()       {          this.ServiceName = SVC_NAME;       }       static void Main()       {          evt.Source = SVC_NAME;          evt.WriteEntry("Remoting Service intializing");          ServiceBase.Run(new RemotingService());       }       protected override void OnStart(string[] args)       {          evt.WriteEntry("Remoting Service started");          String filename = "windowsservice.exe.config";         RemotingConfiguration.Configure(filename);       }       protected override void OnStop()       {          evt.WriteEntry("Remoting Service stopped");       }    } } 
end example

In two separate classes, you'll then provide the implementation of the MarshalByRefObject CustomerManager and an installer, following the preceding sample.

When this program is run in the IDE, you'll see the biggest disadvantage to developing windows services, the message box that will pop up, telling you that you won't get automatic debugging support from Visual Studio .NET IDE (see Figure 4-7).

click to expand
Figure 4-7: Trying to start a Windows service from the IDE


You can change void Main() to not start this application as a service, but instead call onStart() while debugging within the IDE.

To install this application as a Windows service so that it can be started and stopped via the Services MMC snap-in or Server Explorer, you have to run installutil.exe, which is best done from a .NET command prompt. Running this application without the option /LogToConsole=false will produce a lot of information in case something goes wrong. You can see the command line for installing the service in Figure 4-8.

click to expand
Figure 4-8: Installing a service using installutil.exe

When using configuration files with Windows services, those files have to be placed in <%WINDIR%>\System32 (normally c:\winnt\system32) to be readable by the application, as this is the service's startup directory. Alternatively you can access the configuration file from the application's installation directory using the following line of code:

 RemotingConfiguration.Configure(     AppDomain.CurrentDomain.SetupInformation.ConfigurationFile) 

After successfully installing the service, you will be able to start it using the Microsoft Management Console, as shown in Figure 4-9.

click to expand
Figure 4-9: The service has been installed successfully.

After starting the service, you can see the output in the EventLog viewer, which is shown in Figure 4-10.

click to expand
Figure 4-10: The server's output in the EventLog

You can now use the same client as in the previous example to connect to the server. After stopping it in the MMC, you can uninstall the service with the installutil.exe /U option, as show in Figure 4-11.


After starting or stopping the service via MMC, the internal handle to it is not freed.When you deinstall the service, it will not be removed from the list of available services until after you close and reopen the MMC.

click to expand
Figure 4-11: Uninstalling a service using installutil.exe

Deployment Using IIS

Choosing IIS to host .NET Remoting components allows you to focus closely on application design without wasting any time with developing your own servers, authentication, and security channels, because IIS will take care of these features for you.

IIS can be configured to take care of a lot of aspects of real-world remoting. Authentication, including the use of Thread.CurrentPrincipal to employ role-based security checks, can be provided with standard Web-based methods. Depending on your architecture and security needs, either basic authentication or NT challenge/response can be chosen. Encryption can be implemented in a secure and simple way using SSL certificates, which need to be installed in IIS.

But hosting in IIS comes at a price; in particular, the performance counters won't give as high numbers as with other solutions. You'll also have to live with HTTP channel and abandon the option to switch to TCP channel, but you can still use either SOAP or binary encoding when hosting in IIS, as it is automatically configured this way!

Of course, your needs will dictate the solution to choose. If you expect several thousand calls per second, be sure to check if any version will meet your demands on the given hardware. If you're going to use the same server-side classes in your in-house LAN application and for publishing Web Services via SOAP, you can still set up a different server application using TCP channel for local use and handle the public access via IIS.

Nothing beats hosting of remote objects in IIS in terms of time to market. You just implement a MarshalByRefObject in a class library project, create a virtual directory in IISAdmin (MMC), create a virtual subdirectory called bin, and put your DLL there. You then have to create a configuration file called web.config and put this in your virtual directory. You don't even need to restart IIS when deploying your remoting components. When you want to update your server-side assembly, you can just overwrite it in the bin subdirectory, as neither the DLL nor the configuration file is locked by IIS.

When the configuration is changed by updating web.config, IIS will automatically reread this information and adopt its behavior. Moving from a staging or testing server to your production machine only involves copying this subdirectory from one host to the other. This is what Microsoft means when talking about xcopy deployment!

Designing and Developing Server-Side Objects for IIS

For the following examples, I employ the metadata approach, which I've shown you previously. I use SoapSuds with the -gc parameter to avoid namespace clashes between remote and local objects.

The server-side implementation is a little bit easier than the former ways of deployment because you only have to implement the MarshalByRefObject without any startup code for the server.

Listing 4-8 shows everything you need to code when using IIS to host your components.

Listing 4-8: Server-Side Implementation of the SAO

start example
 using System; using General; namespace Server {    class CustomerManager: MarshalByRefObject    {       public Customer getCustomer(int id)       {          Customer tmp = new Customer();          tmp.FirstName = "John";          tmp.LastName = "Doe";          tmp.DateOfBirth = new DateTime(1970,7,4);          return tmp;       }    } } 
end example

After compiling this assembly to a DLL, you can proceed with setting up Internet Information Server.

Preparing Internet Information Server

Before being able to use IIS as a container for server-side objects, you have to configure several aspects of IIS. At the very least you have to create a new virtual root and set the corresponding permissions and security requirements.

Creating a Virtual Root

An IIS virtual root will allow a certain directory to be accessed using an URL. You can basically specify that the URL http://yourhost/yourdirectory will be served from c:\somedirectory, whereas the standard base URL http://yourhost/ is taken from c:\inetpub\wwwroot by default.

You create virtual roots using the MMC, which you bring up by selecting Start Programs Administrative Tools Internet Services Manager. In the Internet Services Manager you will see Default Web Site if you're running workstation software (when using server software, you'll probably see more Web sites).

Right-click Default Web Site and choose New Virtual Directory. The Virtual Directory Creation Wizard appears. Use this wizard to specify an alias and the directory it will point to. For usage as a remoting container, the default security permissions (Read and Run scripts) are sufficient.

In the directory to which the new IIS virtual directory points, you have to place your .NET Remoting configuration file. As the server will automatically watch for this file and read it, you have to call it web.config—you cannot specify a custom name.

Below this directory you can now create a folder called bin\ and place your assemblies there. As an alternative, you can place your assemblies in the GAC using gacutil.exe, but remember that you have to specify the SAO assemblies' strong names in the configuration file in this case. This is normally not recommended if your server-side DLL is just used by a single application, but is needed to provide versioning services for CAOs, as you'll see in Chapter 6.

Deployment for Anonymous Use

Before being able to convert the former example to IIS-based hosting, you have to create a new directory and an IIS virtual directory called MyServer (this will be used in the URL to the remote objects) according to the description previously given.

In the Internet Services Manager MMC, open the properties by right-clicking the newly created virtual directory, choose the Directory Security tab, and click Edit. The window shown in Figure 4-12 will open, enabling you to set the allowed authentication methods. Make sure that Allow Anonymous Access is checked.

click to expand
Figure 4-12: Configuring authentication methods

In the configuration file, it's important that you don't specify an application name, as this property will be automatically determined by the name of the virtual directory.


When specifying channel information in a configuration file that will be used in IIS—for example, to provide a different sink chain—be sure not to include port numbers, as they will interfere with IIS' internal connection handling.When the server's load reaches a certain point, IIS may start more than one instance for handling remote object. If you have bound to a secondary port in your configuration file, this port will already be locked by the previous instance.

 <configuration>   <system.runtime.remoting>     <application>       <service>         <wellknown mode="Singleton"                    type="Server.CustomerManager, Server"                    objectUri="CustomerManager.soap" />       </service>     </application>   </system.runtime.remoting> </configuration> 

After putting the configuration file in your virtual directory, you have to copy the assemblies (both the shared one and the server's implementation) into its bin subdirectory. The resulting structure should be like this:






Assemblies that contain your remote objects and assemblies upon which your objects depend if they are not in the GAC.

The client is basically the same as in the previous examples. I use SoapSuds with the -gc and -nowp parameters to generate code for a nonwrapped proxy. From this output, I only took the server.cs and included it in the VS .NET solution.

The client itself is quite simple, as shown in Listing 4-9.

Listing 4-9: An Anonymous Client

start example
 using System; using System.Runtime.Remoting; using General;  // from General.DLL using Server; // from server.cs namespace Client {    class Client    {       static void Main(string[] args)       {          String filename = "client.exe.config";          RemotingConfiguration.Configure(filename);         CustomerManager mgr = new CustomerManager();          Console.WriteLine("Client.Main(): Reference to CustomerManager " +                              "acquired");          Customer cust = mgr.getCustomer(4711);          int age = cust.getAge();          Console.WriteLine("Client.Main(): Customer {0} {1} is {2} years old.",             cust.FirstName,             cust.LastName,             age);          Console.ReadLine();       }    } } 
end example

In contrast to the examples earlier in this chapter, the client's configuration file needs to be changed to contain the correct URL to the newly deployed components.

 <configuration>   <system.runtime.remoting>     <application>       <client>         <wellknown type="Server.CustomerManager, Client"                    url="http://localhost/MyServer/CustomerManager.soap" />       </client>     </application>   </system.runtime.remoting> </configuration> 

Advanced  .NET Remoting C# Edition
Advanced .NET Remoting (C# Edition)
ISBN: 1590590252
EAN: 2147483647
Year: 2002
Pages: 91
Authors: Ingo Rammer © 2008-2017.
If you may any questions please contact us: