Miscellaneous .Net Remoting Features


The final section of this chapter explores the following .NET Remoting features:

  • How application configuration files can be used to define remoting channels

  • Hosting .NET Remoting Servers in an IIS Server by using the ASP.NET runtime

  • Different ways to get the type information of the server for building the client with the utility Soapsuds

  • Calling .NET Remoting methods asynchronously

  • Implementing events to callback methods in the client

  • Using call contexts to pass some data automatically to the server behind the scenes

Configuration Files

Instead of writing the channel and object configuration in the source code, you can use configuration files. This way the channel can be reconfigured, additional channels can be added, and so on, without changing the source code. Like all the other configuration files on the .NET platform, XML is used. The same application and configuration files that you read about in Chapter 15 and in Chapter 16, ".NET Security," are used here, too. For .NET Remoting, there are some more XML elements and attributes to configure the channel and the remote objects. The difference with the remoting configuration file is that this configuration needn't be in the application configuration file itself; the file can have any name. To make the build process easier, in this chapter the Remoting configuration is written inside the application configuration files named with a .config file extension after the file name of the executable.

The code download (from www.wrox.xom) contains the following example configuration files in the root directory of the client and the server examples: clientactivated.config and wellknown.config.

With the client example, you will also find the file wellknownhttp.config that specifies an HTTP channel to a well-known remote object. To use these configurations, the files must be renamed to the name that is used with the parameter of the RemotingConfiguration.Configure() method and placed in the directory containing the executable file.

Here is just one example of how such a configuration file might look:

 <configuration> <system.runtime.remoting> <application name="Hello"> <service> <wellknown mode="SingleCall" type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" objectUri="Hi" /> </service> <channels> <channel ref="tcp" port="6791" /> <channel ref="http" port="6792" /> <channel ref="ipc" portName="myIPCPort" /> </channels> </application> </system.runtime.remoting> </configuration> 

<configuration> is the XML root element for all .NET configuration files. All the remoting configurations can be found in the subelement <system.runtime.remoting>. <application> is a subelement of <system.runtime.remoting>.

The following list describes the main elements and attributes of the parts within <system.runtime. remoting>:

  • With the <application> element you can specify the name of the application using the attribute name. On the server side, this is the name of the server, and on the client side it's the name of the client application. As an example for a server configuration, <application name="Hello"> defines the remote application name Hello, which is used as part of the URL by the client to access the remote object.

  • On the server, the element <service> is used to specify a collection of remote objects. It can have <wellknown> and <activated> subelements to specify the type of the remote object as well-known or client-activated.

  • The client part of the <service> element is <client>. Like the <service> element, it can have <wellknown> and <activated> subelements to specify the type of the remote object. Unlike the <service> counterpart, <client> has a url attribute to specify the URL to the remote object.

  • <wellknown> is an element that's used on the server and the client to specify well-known remote objects. The server part could look like this:

    <wellknown mode="SingleCall"    type="Wrox.ProCSharp.Remoting.Hello, RemoteHello"          objectURI="Hi" /> 
  • While the mode attribute SingleCall or Singleton can be specified, the type is the type of the remote class, including the namespace Wrox.ProCSharp.Remoting.Hello, followed by the assembly name RemoteHello. objectURI is the name of the remote object that's registered in the channel.

  • On the client, the type attribute is the same as it is for the server version. mode and objectURI are not needed, but the url attribute is used to define the path to the remote object instead: protocol, hostname, port number, application name, and the object URI:

    <wellknown type="Wrox.ProCSharp.Remoting.Hello, RemoteHello"                   url="tcp://localhost:6791/Hello/Hi" />

  • The <activated> element is used for client-activated objects. With the type attribute the type and the assembly must be defined for both the client and the server application:

    <activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" />

  • To specify the channel, the <channel> element is used. It's a subelement of <channels> so that a collection of channels can be configured for a single application. Its use is similar for clients and servers. With the XML attribute ref you reference a preconfigured channel name. For the server channel you have to set the port number with the XML attribute port. The XML attribute displayName is used to specify a name for the channel that is used from the .NET Framework Configuration tool, as discussed later in this chapter.

    <channels>     <channel ref="tcp" port="6791" displayName="TCP Channel" />    <channel ref="http" port="6792" displayName="HTTP Channel" />    <channel ref="ipc" portName="myIPCPort" displayName="IPC Channel" /> </channels>

Predefined channels

You can use predefined channels instead of defining the channel types with the configuration file. Prior to .NET 2.0, you can read predefined channels in the machine.config configuration file, which is in the directory <windir>\Microsoft.NET\Framework\<version>\CONFIG. With .NET 2.0 the predefined channels are defined by the RemotingConfiguration class to get a better performance.

In the following XML file extract you can see the predefined channels. The <channel> element is used as a subelement of <channels> to define channels. Here the attribute id specifies a name of a channel that can be referenced with the ref attribute. With the type attribute the class of the channel is specified followed by the assembly; for example, the channel class System.Runtime.Remoting.Channels.Http. HttpChannel can be found in the assembly System.Runtime.Remoting. Because the System. Runtime.Remoting assembly is shared, the strong name of the assembly must be specified with Version, Culture, and PublicKeyToken:

 <system.runtime.remoting> <!-- ... --> <channels> <channel  type="System.Runtime.Remoting.Channels.Http.HttpChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Http.HttpClientChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Http.HttpServerChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Tcp.TcpChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Tcp.TcpClientChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Tcp.TcpServerChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Ipc.IpcChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Ipc.IpcClientChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <channel  type="System.Runtime.Remoting.Channels.Ipc.IpcServerChannel, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> </channels> <!-- ... --> <system.runtime.remoting> 

Server configuration for well-known objects

This example file, Wellknown_Server.config, has the value Hello for the name property. In the following configuration file, the TCP channel is set to listen on port 6791 and the HTTP channel is set to listen on port 6792. The IPC channel is configured with the port name myIPCPort. The remote object class is Wrox.ProCSharp.Remoting.Hello in the assembly RemoteHello, the object is called Hi in the channel, and the object mode is SingleCall:

 <configuration> <system.runtime.remoting> <application name="Hello"> <service> <wellknown mode="SingleCall" type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" objectUri="Hi" /> </service> <channels> <channel ref="tcp" port="6791" displayName="TCP Channel (HelloServer)" /> <channel ref="http" port="6792" displayName="HTTP Channel (HelloServer)" /> <channel ref="ipc" portName="myIPCPort" displayName="IPC Channel (HelloServer)" /> </channels> </application> </system.runtime.remoting> </configuration> 

Client configuration for well-known objects

For well-known objects, you have to specify the assembly and the channel in the client configuration file Wellknown_Client.config. The types for the remote object are in the RemoteHello assembly, Hi is the name of the object in the channel, and the URI for the remote type Wrox.ProCSharp.Remoting. Hello is ipc://myIPCPort/Hello/Hi. In the client, an IPC channel is used as well, but no port is specified, so a free port is selected. The channel that is selected with the client must correspond to the URL:

 <configuration> <system.runtime.remoting> <application name="Client"> <client displayName="Hello client for well-known objects"> <wellknown type = "Wrox.ProCSharp.Remoting.Hello, RemoteHello" url="ipc://myIPCPort/Hello/Hi" /> </client> <channels> <channel ref="ipc" displayName="IPC Channel (HelloClient)" /> </channels> </application> </system.runtime.remoting> </configuration> 

After a small change in the configuration file, you're using the HTTP channel (as you can see in WellknownHttp_Client.config):

 <client> <wellknown type="Wrox.ProCSharp.Remoting.Hello, RemoteHello"  url="http://localhost:6792/Hello/Hi" /> </client> <channels> <channel ref="http" displayName="HTTP Channel (HelloClient)" /> </channels> 

Server configuration for client-activated objects

By changing only the configuration file (located in ClientActivated_Server.config), you can change the server configuration from server-activated to client-activated objects. Here the <activated> subelement of the <service> element is specified. With the <activated> element for the server configuration, just the type attribute must be specified. The name attribute of the application element defines the URI:

<configuration>    <system.runtime.remoting> <application name="HelloServer"> <service> <activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" /> </service>          <channels>             <channel ref="http" port="6788"                      displayName="HTTP Channel (HelloServer)" />             <channel ref="tcp" port="6789"                displayName="TCP Channel (HelloServer)" />             <channel ref="ipc" portName="myIPCPort"                      displayName="IPC Channel (HelloServer)" />          </channels>       </application>    </system.runtime.remoting> </configuration>

Client configuration for client-activated objects

The ClientActivated_Client.config file defines the client-activated remote object using the url attribute of the <client> element and the type attribute of the <activated> element:

<configuration>    <system.runtime.remoting>       <application> <client url="http://localhost:6788/HelloServer" displayName="Hello client for client-activated objects"> <activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" /> </client>          <channels>             <channel ref="http" displayName="HTTP Channel (HelloClient)" />             <channel ref="tcp" displayName="TCP Channel (HelloClient)" />             <channel ref="ipc" displayName="IPC Channel (HelloClient)" />          </channels>       </application>    </system.runtime.remoting> </configuration>

Server code using configuration files

In the server code, you have to configure remoting using the static method Configure() from the RemotingConfiguration class. Here all channels that are defined in the configuration file are created and configured with the .NET Remoting runtime. Maybe you also want to know about the channel configurations from the server application — that's why the static methods ShowActivatedServiceTypes() and ShowWellKnownServiceTypes()were created; they are called after loading and starting the remoting configuration:

public static void Main(string[] args) { RemotingConfiguration.Configure("HelloServer.exe.config",false); Console.WriteLine("Application: " + RemotingConfiguration.ApplicationName); ShowActivatedServiceTypes(); ShowWellKnownServiceTypes();    System.Console.WriteLine("press return to exit");    System.Console.ReadLine();    return; } 

These two functions show configuration information of well-known and client-activated types:

 public static void ShowWellKnownServiceTypes() { WellKnownServiceTypeEntry[] entries = RemotingConfiguration.GetRegisteredWellKnownServiceTypes(); foreach (WellKnownServiceTypeEntry entry in entries) { Console.WriteLine("Assembly: " + entry.AssemblyName); Console.WriteLine("Mode: " + entry.Mode); Console.WriteLine("URI: " + entry.ObjectUri); Console.WriteLine("Type: " + entry.TypeName); } } public static void ShowActivatedServiceTypes() { ActivatedServiceTypeEntry[] entries = RemotingConfiguration.GetRegisteredActivatedServiceTypes(); foreach (ActivatedServiceTypeEntry entry in entries) { Console.WriteLine("Assembly: " + entry.AssemblyName); Console.WriteLine("Type: " + entry.TypeName); } } 

Client code using configuration files

In the client code, it is only necessary to configure the remoting services using the configuration file client.exe.config. After that, you can use the new operator to create new instances of the remote class Hello, no matter whether you work with server-activated or client-activated remote objects. However, there's a small difference — with client-activated objects it's now possible to use non-default constructors with the new operator. This isn't possible for server-activated objects: single-call objects can have no state because they are destroyed with every call; singleton objects are created just once. Calling non-default constructors is only possible with client-activated objects because this is the only type where by invoking the new operator the remote object the object is instantiated.

In the Main() method of the file HelloClient.cs, you can now change the remoting code to use the configuration file with RemotingConfiguration.Configure() and create the remote object with the new operator:

 RemotingConfiguration.Configure("HelloClient.exe.config",false); Hello obj = new Hello(); if (obj == null) {    Console.WriteLine("could not locate server");    return; } for (int i=0; i < 5; i++) {    Console.WriteLine(obj.Greeting("Christian")); } 

Delayed loading of client channels

With the configuration file machine.config, three channels are configured that can be used automatically if the client doesn't configure a channel:

 <system.runtime.remoting> <application> <channels> <channel ref="http client" displayName="http client (delay loaded)" delayLoadAsClientChannel="true" /> <channel ref="tcp client" displayName="tcp client (delay loaded)" delayLoadAsClientChannel="true" /> <channel ref="ipc client" displayName="ipc client (delay loaded")" delayLoadAsClientChannel="true" /> </channels> </application> </system.runtime.remoting>  

The XML attribute delayLoadAsClientChannel with a value true defines that the channel should be used from a client that doesn't configure a channel. The runtime tries to connect to the server using the delay-loaded channels. So it is not necessary to configure a channel in the client configuration file, and a client configuration file for the well-known object you have used earlier can look as simple as this:

 <configuration> <system.runtime.remoting> <application name="Client"> <client url="tcp:/localhost:6791/Hello"> <wellknown type = "Wrox.ProCSharp.Remoting.Hello, RemoteHello" url="tcp://localhost:6791/Hello/Hi" /> </client> </application> </system.runtime.remoting> </configuration> 

Debugging Configuration

If you have a misconfigured server configuration file (for example, by specifying the wrong name of the remote assembly), the error is not detected when the server starts. Instead, the error is detected when the client instantiates a remote object and invokes a method. The client will get the exception that the remote object assembly cannot be found. By specifying the configuration <debug loadTypes="true" />, the remote object is loaded and instantiated on the server when the server starts up. This way you will get an error on the server if the configuration file is misconfigured:

<configuration>    <system.runtime.remoting>       <application name="Hello">          <service>             <wellknown mode="SingleCall"                        type="Wrox.ProCSharp.Remoting.Hello, RemoteHello"                        objectUri="Hi" />          </service>          <channels>              <channel ref="tcp" port="6791"                 displayName="TCP Channel (HelloServer)" />          </channels>       </application> <debug loadTypes="true" />    </system.runtime.remoting> </configuration>

Lifetime services in configuration files

Leasing configuration for remote servers can also be done with the application configuration files. The <lifetime> element has the attributes leaseTime, sponsorshipTimeOut, renewOnCallTime, and pollTime as shown in this example:

<configuration>    <system.runtime.remoting>       <application> <lifetime leaseTime = "15M" sponsorshipTimeOut = "4M" renewOnCallTime = "3M" pollTime = "30s"/>       </application>    </system.runtime.remoting> </configuration>

Using configuration files, it is possible to change the remoting configuration by editing files instead of working with source code. You can easily change the channel to use HTTP instead of TCP, change a port, the name of the channel, and so on. With the addition of a single line the server can listen to two channels instead of one.

Formatter providers

Earlier, this chapter discussed where properties of the formatter provider need to be changed to support marshaling all objects across the network. Instead of doing this programmatically, as was done earlier, you can configure the properties of a formatter provider in a configuration file.

The following server configuration file is changed within the <channel> element, insofar as <serverProviders> and <clientProviders> are defined as child elements. With the<serverProviders>, the built-in providers wsdl, soap, and binary are referenced, and with the soap and binary providers the property typeFilterLevel is set to Full:

<configuration>    <system.runtime.remoting>       <application name="HelloServer">          <service>             <activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" />          </service>          <channels> <channel ref="tcp" port="6789" displayName="TCP Channel (HelloServer)"> <serverProviders> <provider ref="wsdl" /> <provider ref="soap" typeFilterLevel="Full" /> <provider ref="binary" typeFilterLevel="Full" /> </serverProviders> <clientProviders> <provider ref="binary" /> </clientProviders> </channel>           </channels>          </application>    </system.runtime.remoting> </configuration>

.NET Framework Configuration tool

The System Administrator can use the .NET Framework Configuration tool (see Figure 29-11) to reconfigure existing configuration files. This tool is part of the Administrative Tools, which can be accessed by using the Control Panel.

image from book
Figure 29-11

By adding the application HelloClient.exe where you used the client configuration file to the configured applications in this tool, you can configure the URL of the remote object by selecting the hyperlink View Remoting Services Properties.

As shown in Figure 29-12, for the client application you can see the value of the displayName attribute in the combo box. This combo box allows you to select the remote application so you can change the URL of the remote object.

image from book
Figure 29-12

By adding the server application to this tool, the configuration of the remote object and the channels can be changed as shown in Figure 29-13 and Figure 29-14.

image from book
Figure 29-13

image from book
Figure 29-14

Hosting Servers in ASP.NET

Up to this point, all the sample servers were running in self-hosted .NET servers. A self-hosted server must be launched manually. A .NET Remoting server can also be started in a lot of other application types. In a Windows Service the server can be automatically started at boot-time, and in addition the process can run with the credentials of the system account. For more details on Windows Services, see Chapter 36, "Windows Services."

There's special support for .NET Remoting servers for ASP.NET. ASP.NET can be used for the automatic startup of remote servers. Contrary to EXE-hosted applications, ASP.NET-hosted Remoting uses a different file for configuration, but it has the same syntax.

To use the infrastructure from the Internet Information Server and ASP.NET, you have to create a class that derives from System.MarshalByRefObject and has a default constructor. The code used earlier for the server to create and register the channel is no longer necessary; that's done by the ASP.NET runtime. You have to create only a virtual directory on the Web server that maps a directory into which you put the configuration file web.config. The assembly of the remote class must reside in the bin subdirectory.

To configure a virtual directory on the Web server, you can use the Internet Information Services MMC. Selecting the Default Web site and opening the Action menu creates a new Virtual Directory.

The configuration file web.config on the Web server must be put in the home directory of the virtual Web site. With the default IIS configuration, the channel that will be used listens to port 80:

 <configuration> <system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" objectUri="HelloService.soap" /> </service> </application> </system.runtime.remoting> </configuration> 



Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net