Configuration

Team-Fly    

 
.NET and COM Interoperability Handbook, The
By Alan Gordon
Table of Contents
Chapter Eleven.  .NET Remoting

Configuration

In the previous example, I hard-coded the remoting configuration of both the client and server into the source code. I configured the server using the RegisterWellKnownServiceType method, and I configured the client using the RegisterChannel method and by specifying a URI in the GetObject method of the System.Activator class. If you want to change the type of channel that you are using (HTTP to TCP for instance), the port number, or the activation mode of the server object, you need to recompile the code. The .NET Framework supports a feature that allows you to configure your .NET applications using an XML configuration file. If you take advantage of this feature, you can easily change the .NET remoting configuration of both your client and server without having to change your source code.

Server

On the server, the types that you are exposing, the type of channel you are using, and the port number that you are listening on is specified in the source code by the following lines of code:

 HttpChannel chnl=new HttpChannel(8080); ChannelServices.RegisterChannel(chnl); RemotingConfiguration.RegisterWellKnownServiceType(       typeof(Company),"Company.soap",       WellKnownObjectMode.Singleton); 

The .NET Framework defines an XML schema that you can use to configure your client and server applications using XML configuration files. You can read the file and set your .NET remoting configuration to that which is specified in the configuration file by calling the RemotingConfiguration.Configure method. For instance, the following configuration file will configure your server exactly the same as the call to RegisterWellKnownServiceType in the previous example:

 <configuration> <system.runtime.remoting>           <application>             <channels>               <channel ref="http" port="8080" />             </channels>           <service>             <wellknown mode="Singleton" type="SharedLibrary.Company,SharedLibrary" objectUri="Company.soap" />           </service>           </application> </system.runtime.remoting> </configuration> 

I use the channel element to specify both the protocol of the channel that the server will listen on (http in this case) and the port that the channel will use (8080). I use the wellknown sub-element of the service element to specify that the server should use server activation in Singleton mode. The type attribute in this sub-element contains the fully qualified type name of the type that I am exposing and the assembly name for the type in the following form: "typename,assemblyname".

In order to use this file, you need to save it and give it a name CompanyServer.exe.config , for instanceand change your server code to use the configuration file as follows :

 using System; using SharedLibrary; using System.Runtime.Remoting; namespace CompanyServer { public class CompanyServer : MarshalByRefObject {       static void Main(string[] args)       {  RemotingConfiguration.Configure(   "CompanyServer.exe.config");  Console.WriteLine(             "Company server started!!!");         Console.ReadLine();       } } } 

Notice that I call the Configure method on the System.Run-time.Remoting.RemotingConfiguration class and specify the name of the file from which to read the remoting configuration settings. The advantage of using the configuration file is that you can now change the configuration of your server to use different channels, formatters, or ports just by changing the configuration file.

Client

The RemotingConfiguration.Configure method works just as well on the .NET remoting client. To use it from a client, create the following configuration file and save it in a file called CompanyClient.exe.config :

 <configuration> <system.runtime.remoting>       <application>         <client> <wellknown type="SharedLibrary.Company,SharedLibrary" url="http://localhost:8080/Company.soap" />         </client>       </application>     </system.runtime.remoting> </configuration> 

Now change the source code for your client to look as follows. Notice that, once again, you simply call the Configure method on the System.Run-time.Remoting.RemotingConfiguration class and specify the name of the configuration file.

 using System; using System.Runtime.Remoting; using SharedLibrary; namespace CompanyClient {   class Class1   {     [STAThread]     static void Main(string[] args)     {       Employee emp1, emp2;       int empID;  RemotingConfiguration.Configure(   "CompanyClient.exe.config");   Company obj=new Company();  Console.WriteLine("Enter an Employee ID");       empID=int.Parse(Console.ReadLine());       Console.WriteLine("Enter a first name");       string strFirstName=Console.ReadLine();       Console.WriteLine("Enter a last name");       string strLastName=Console.ReadLine();       emp1=obj.CreateEmployee(empID,       strFirstName,strLastName,1000);       Console.WriteLine(          "Enter the key of an Employee");        empID=int.Parse(Console.ReadLine());        emp2=obj.GetEmployee(empID);        Console.WriteLine(          "Employee first name is: " +          emp2.FirstName);        }     } } 

Notice that, in this source code, I also use the new operator instead of the Activator.GetObject method. The wellknown element in the XML configuration file specifies that any attempt to instantiate the type SharedLibrary.Company in the SharedLibrary assembly should be instantiated on the remote server identified by the objectURI property.

The XML schema for a remoting configuration file is shown in Figure 11-3. In Figure 11-3, rectangles represent XML elements, and ovals represent attributes of the XML element that points to them. The Service element is only relevant on a server configuration file, and the Client element is only relevant on a client configuration file. For instance, the following configuration file, when used on the server, will add a TCP channel to the server with a port number of 2400:

 <configuration>     <system.runtime.remoting>         <application>             <channels>             <channel ref="tcp" port="2400" />             <channel ref="http" port="8080" />         </channels>         <service>             <wellknown mode="Singleton"       type="SharedLibrary.Company,SharedLibrary"                 objectUri="Company.soap" />         </service>         </application>     </system.runtime.remoting> </configuration> 
Figure 11-3. The XML schema for a remoting configuration file.

graphics/11fig03.gif

A server application running with the previous configuration file can now be accessed from a client using a TCP channel on port 2400 or on a HTTP channel on port 8080. The following configuration file allows a client to talk to the server through the TCP channel on port 2400:

 <configuration>     <system.runtime.remoting>       <application>         <client>            <wellknown  type="SharedLibrary.Company,SharedLibrary"  url="tcp://localhost:2400/Company.soap" />         </client>       </application>     </system.runtime.remoting> </configuration> 

I'll leave it as an exercise for you to figure out how to access the server via HTTP on port 8080.

You can also configure leasing- related parameters using a configuration file. The following configuration file specifies that the initial lease time granted to the object is 10 seconds (see the leaseTime attribute on the lifetime element). The life of the object will be renewed for 100 milliseconds (one-tenth of a second) each time that you make a function call (see the renewOnCallTime attribute on the lifetime element), and the lease manager will poll every one-tenth of a second for expired leases (see the leaseManagerPollTime attribute on the lifetime element).

 <configuration>   <system.runtime.remoting>     <application>       <lifetime leaseTime="10S"         renewOnCallTime="100MS"         leaseManagerPollTime="100MS" />       <channels>         <channel ref="tcp" port="2400" />         <channel ref="http" port="8080" />       </channels>       <service>         <wellknown mode="Singleton"       type="SharedLibrary.Company,SharedLibrary"       objectUri="Company.soap" />       </service>     </application>   </system.runtime.remoting> </configuration> 

You can specify entries in this file using time units of milliseconds (MS), seconds (S), minutes (M), hours (H), and days (D). If no time unit is specified, the unit defaults to seconds. After you change the server configuration file to look as shown previously, try running the client again. If you run the server with this new configuration file and then run the client, you'll see that, if you create an employee and then immediately type in the ID of the employee to look up, everything will work correctly. The server will look up and find the employee that you just entered. However, if you enter the ID and name of an employee and then pause for more than 10 seconds, when you enter the ID of the employee to look up and press Enter, you will get an exception. Do you understand why? The list of employees that I have created using a Company object is stored in a collection within the Company object. After the Company object dies, its collection of Employees dies with it. In this case, the Company object has an initial life of 10 seconds, and it will only be renewed for one-tenth of a second after each method call. This means that the object will be destroyed approximately 10 seconds after it was created. Therefore, if you wait more than 10 seconds after you create an employee to search for the employee, the application will behave as though the employee never existed because its Company will have died. This demonstrates the precise control that .NET remoting gives you over the lifetime of your objects. You can also control the life cycle of your objects by overriding the System.MarshalByRef-Object.InitializeLifetimeService method in your remote object as shown in the following code:

 public override object InitializeLifetimeService() {     ILease myLease=         (ILease)base.InitializeLifetimeService();     if (myLease.CurrentState == LeaseState.Initial)     {       myLease.InitialLeaseTime=         TimeSpan.FromSeconds(10);       myLease.RenewOnCallTime=         TimeSpan.FromMilliseconds(50);       myLease.SponsorshipTimeout=         TimeSpan.FromMilliseconds(100);     }     return myLease; } 

Adding this code to the Company class will have the same effect as the preceding configuration file.

So far I have used the Singleton life cycle mode for the Company object. You can make the Company object a SingleCall object using the following server configuration file:

 <configuration> <system.runtime.remoting>     <application>       <channels>         <channel ref="tcp" port="2400" />         <channel ref="http" port="8080" />       </channels>       <service>         <wellknown mode  ="SingleCall"  type="SharedLibrary.Company, SharedLibrary" objectUri="Company.soap" />       </service>     </application> </system.runtime.remoting> </configuration> 

If you run the server with this configuration file and then connect with the client, the lookup will always fail. The reason, of course, is that a new object is created to service each call. Therefore, the object that you call the GetEmployee method on to look up an employee is not the same object as the one that you called CreateEmployee on to create the employee. Because the company object stores its list of employees in memory in an internal hash table, the GetEmployee method always reports that the employee could not be found.

I can configure the server to support both server activation and client activation using the following configuration file:

 <configuration>   <system.runtime.remoting>     <application name="Company" >       <channels>         <channel ref="tcp" port="2400" />         <channel ref="http" port="8080" />       </channels>       <service>         <wellknown         mode="SingleCall"       type="SharedLibrary.Company,SharedLibrary"         objectUri="Company.soap" />         <activated           type="SharedLibrary.Company,           SharedLibrary" />       </service>     </application>   </system.runtime.remoting> </configuration> 

The activated sub-element within the service element configures client activation for the Company type. Notice that we only need to specify a type attribute within the activated element that contains the fully qualified type name of the Company type and the assembly that it resides in.

A client that wants to use the object as a client-activated object should use the following configuration file:

 <configuration> <system.runtime.remoting>         <application>          <client url="http://localhost:8080/Company/" >         <activated type=           "SharedLibrary.Company, SharedLibrary"  />          </client>         </application>     </system.runtime.remoting> </configuration> 

A client that wants to use the object as a server-activated object should use the configuration file that follows:

 <configuration> <system.runtime.remoting>       <application>         <client>           <wellknown type=         "SharedLibrary.Company,SharedLibrary"         url="http://localhost:8080/Company.soap" />         </client>       </application> </system.runtime.remoting> </configuration> 

Before I leave the subject of configuration files entirely, let's take a look at how to configure a channel to use a nondefault formatter. In other words, let's look at how to configure the HTTP channel to use the binary formatter or the TCP channel to use the SOAP formatter. The following server configuration file shows how you would configure the TCP channel and the HTTP channel to use their nondefault formatter:

 <configuration>   <system.runtime.remoting>     <application name="Company" >       <channels>         <channel ref="tcp" port="2400" >  <serverProviders>   <formatter ref="soap" />   </serverProviders>   </channel>   <channel ref="http" port="8080" >  <  serverProviders>  <formatter ref="binary" />           </serverProviders>         </channel>       </channels>       <service>         <wellknown mode="Singleton"         type="SharedLibrary.Company,SharedLibrary"         objectUri="Company.soap" />         <activated type="SharedLibrary.Company,           SharedLibrary" />       </service>     </application>   </system.runtime.remoting> </configuration> 

In order to use the HTTP channel with the binary formatter, you would use the following client configuration file:

 <configuration>   <system.runtime.remoting>     <application>       <channels>         <channel ref="http" >  <clientProviders>   <formatter ref="binary" />   </clientProviders>  </channel>       </channels>       <client>       <wellknown type="SharedLibrary.Company,SharedLibrary"         url="http://localhost:8080/Company.soap" />       </client>     </application>   </system.runtime.remoting> </configuration> 

The following configuration file will configure a client to use the tcp channel with the SOAP formatter.

 <configuration>   <system.runtime.remoting>     <application>       <channels>         <channel ref="tcp" >           <clientProviders>             <formatter ref="soap" />           </clientProviders>         </channel>       </channels>       <client>       <wellknown type="SharedLibrary.Company,SharedLibrary"         url="tcp://localhost:2400/Company.soap" />       </client>     </application>   </system.runtime.remoting> </configuration> 

Team-Fly    
Top
 


. Net and COM Interoperability Handbook
The .NET and COM Interoperability Handbook (Integrated .Net)
ISBN: 013046130X
EAN: 2147483647
Year: 2002
Pages: 119
Authors: Alan Gordon

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