Programming Remote Objects


You can use RemoteObjects in two ways. You can create a new instance of a remote object. You can also obtain a proxy to an existing remote object so that you can invoke its methods . RemoteObjects provide communications functionality to programs running in separate application domains in the same Win32 process, running in different processes on the same machine, or even running across machines over the Internet.

From the server s point of view, there are two aspects to serving a remote object. You can publish the ability to create a new instance of a remote object class, or you can publish the ability to connect to an existing instance of a remote object class. Either way, you need a remote object class, so let s start there.

Creating a TimeZone RemoteObject

It s actually easier to define a class that supports Indigo RemoteObjects than it is to define a Web service class. A RemoteObject must derive directly or indirectly from System.MarshalByRefObject . Note that .NET remoting had the same base class requirement, so a class written to be used by .NET remoting can generally be used as an Indigo RemoteObject.

The following code example creates a TimeZoneObject RemoteObject that has public methods that return time and date information. I ll be using this class in the rest of the examples in this section. A client creates a TimeZoneObject instance for a specific time zone. The GetCurrentTimeAndDate method for that instance then returns the current time in the specified time zone.

 using System; 
using System.Globalization;

public class TimeZoneObject : MarshalByRefObject {
private Guid myID = Guid.NewGuid ();
private TimeSpan myOffset;

public TimeZoneObject (string tz) {
myOffset = ConvertZoneToUtcOffset (tz);
Console.WriteLine("Creating object {0} for zone {1}", myID, tz);
}

public string GetCurrentTimeAndDate (CultureInfo ci) {
if (ci == null) ci = new CultureInfo ("");
Console.WriteLine("{0} returning current time/date for culture {1}",
myID, ci.ToString());
return (DateTime.UtcNow + myOffset).ToString ("F", ci);
}

public string GetUtcTimeAndDate (CultureInfo ci) {
return DateTime.UtcNow.ToString ("F", ci);
}

private TimeSpan ConvertZoneToUtcOffset (string tz) {
string upperTZ = tz.ToUpper();
switch (upperTZ) {
case "ADT": // Atlantic Daylight -3 hours
return new TimeSpan (-3, 0, 0);
case "AST": // Atlantic Standard
case "EDT": // Eastern Daylight -4 hours
return new TimeSpan (-4, 0, 0);
case "EST": // Eastern Standard
case "CDT": // Central Daylight -5 hours
return new TimeSpan (-5, 0, 0);
case "CST": // Central Standard
case "MDT": // Mountain Daylight -6 hours
return new TimeSpan (-6, 0, 0);
case "MST": // Mountain Standard
case "PDT": // Pacific Daylight -7 hours
return new TimeSpan (-7, 0, 0);
case "PST": // Pacific Standard
//case "ADT": // Alaskan Daylight -8 hours
return new TimeSpan (-8, 0, 0);
case "ALA": // Alaskan Standard -9 hours
return new TimeSpan (-9, 0, 0);
case "HAW": // Hawaiian Standard -10 hours
return new TimeSpan (-10, 0, 0);
case "UTC":
case "GMT":
case "ZULU": // So its not a real zone name
return new TimeSpan (0, 0, 0);
case "CET": // Central European
case "FWT": // French Winter
case "MET": // Middle European
case "MEWT": // Middle European Winter
case "SWT": // Swedish Winter +1 hour
return new TimeSpan (+1, 0, 0);
case "EET": // Eastern European, USSR Zone 1 +2
return new TimeSpan (+2, 0, 0);
case "BT": // Baghdad, USSR Zone 2 +3 hours
return new TimeSpan (+3, 0, 0);
case "ZP4": // USSR Zone 3 +4 hours
return new TimeSpan (+4, 0, 0);
case "ZP5": // USSR Zone 4 +5 hours
return new TimeSpan (+5, 0, 0);
case "ZP6": // USSR Zone 5 +6 hours
return new TimeSpan (+6, 0, 0);
case "WAST": // West Australian Standard +7 hours
return new TimeSpan (+7, 0, 0);
case "CCT": // China Coast, USSR Zone 7 +8
return new TimeSpan (+8, 0, 0);
case "JST": // Japan Standard, USSR Zone 8 +9
return new TimeSpan (+9, 0, 0);
case "EAST": // East Australian Standard GST
case "Guam": // Standard, USSR Zone 9 +10 hours
return new TimeSpan (+10, 0, 0);
case "IDLE": // International Date Line
case "NZST": // New Zealand Standard
case "NZT": // New Zealand
return new TimeSpan (+12, 0, 0);
default:
throw new Exception ("Unrecognized time zone");
}
}
}

Hosting a RemoteObject Class

In your RemoteObject hosting application, just like the Web service, you create a ServiceEnvironment object by loading an application configuration file and passing the name of the service environment configuration settings that you want to use. As before, I ll default to loading the main service environment from the configuration file.

 using System; 
using System.MessageBus;
using System.MessageBus.Remoting;

class Host {
static void Main () {
ServiceEnvironment se = null;

try {
se = ServiceEnvironment.Load ();
RemotingManager rm = se[typeof(RemotingManager)] as RemotingManager;
if (rm == null)
throw new Exception("No RemotingManager in ServiceEnvironment.");

// Start the ServiceEnvironment.
se.Open ();

// Register an instance of a TimeZoneObject for
// remote connection hosted in this service environment.
TimeZoneObject tzoPST = new TimeZoneObject ("PST");
TimeZoneObject tzoHAW = new TimeZoneObject ("HAW");
TimeZoneObject tzoCET = new TimeZoneObject ("CET");
TimeZoneObject tzoGMT = new TimeZoneObject ("GMT");

// A client can create a proxy to a published object using
// RemotingManager.GetObject
PublishedServerObject psoPST =
new PublishedServerObject (tzoPST, new Uri("urn:PST"));
rm.PublishedServerObjects.Add (psoPST);

PublishedServerObject psoHAW =
new PublishedServerObject (tzoHAW, new Uri("urn:HAW"));
rm.PublishedServerObjects.Add (psoHAW);

PublishedServerObject psoCET =
new PublishedServerObject (tzoCET, new Uri("urn:CET"));
rm.PublishedServerObjects.Add (psoCET);

PublishedServerObject psoGMT =
new PublishedServerObject (tzoGMT, new Uri("urn:GMT"));
rm.PublishedServerObjects.Add (psoGMT);

Console.WriteLine("Listening for requests. Press Enter to exit...");
Console.ReadLine();

// Cancel the publication of the objects.
rm.PublishedServerObjects.Remove(psoPST);
rm.PublishedServerObjects.Remove(psoHAW);
rm.PublishedServerObjects.Remove(psoCET);
rm.PublishedServerObjects.Remove(psoGMT);
}
finally {
if (se != null) se.Close();
}
}
}

Note that in a RemoteObject hosting application, I use the RemotingManager class instead of the ServiceManager , as I did in my Web service. The unique part of this example is my use of the RemotingManager to publish objects the hosting application has created and initialized . I create a few TimeZoneObject instances as usual:

 TimeZoneObject tzoPST = new TimeZoneObject ("PST"); 
. . .
TimeZoneObject tzoGMT = new TimeZoneObject ("GMT");

However, I then publish the objects by creating a set of PublishedServerObject instances, each one of which associates a particular TimeZoneObject object with a unique name. When I add the PublishedServerObject instances to the RemotingManager PublishedServerObjects collection, the RemotingManager allows clients to access each published object by its unique name.

 PublishedServerObject psoPST = 
new PublishedServerObject (tzoPST, new Uri("urn:PST"));
rm.PublishedServerObjects.Add (psoPST);

I also have, by now, the expected configuration file for the server. The only difference between this RemoteObject configuration file and the earlier Web service configuration file is that I ve specified a different port identity.

 <configuration> 
<system.messagebus>
<serviceEnvironments>
<serviceEnvironment name="main">
<port>
<identityRole>
soap.tcp://localhost:46010/TimeZoneObjects
</identityRole>
</port>
<!-- CAUTION: Security disabled for demonstration purposes only. -->
<remove name="securityManager" />
<policyManager>
<!-- CAUTION: Security disabled for demonstration purposes only. -->
<!-- Permits unsigned policy statements. Default requires signed policy statements -->
<areUntrustedPolicyAttachmentsAccepted>
true
</areUntrustedPolicyAttachmentsAccepted>
<isPolicyReturned>true</isPolicyReturned>
</policyManager>
<remotingManager>
</remotingManager>
</serviceEnvironment>
</serviceEnvironments>
</system.messagebus>
</configuration>

Connecting to a Remote Instance of a RemoteObject

A client application can connect to a published RemoteObject by

  • Creating the ServiceEnvironment by calling the Load method as usual

  • Obtaining a RemotingManager from the ServiceEnvironment

  • Opening the ServiceEnvironment

  • Creating a URI that addresses the desired RemotingObject server

  • Calling the RemotingManager GetObject method and specifying the server s URI and the unique name of the specific object to which you want to connect

  • Calling methods, access fields, and properties on the remote object

The following RemotingObject client application connects to a published TimeZoneObject and retrieves and displays the current time in that time zone.

 using System; 
using System.Globalization;
using System.MessageBus;
using System.MessageBus.Remoting;

class Client {
static void Main (string[] args) {
string zone = "PST";
if (args.Length > 0 && args[0].Length > 0) zone = args[0];

CultureInfo ci = new CultureInfo ("");
if (args.Length > 1 && args[1].Length > 0) ci = new CultureInfo (args[1]);

ServiceEnvironment se = null;

try {
se = ServiceEnvironment.Load ();
RemotingManager rm = se[typeof(RemotingManager)] as RemotingManager;
if (rm == null)
throw new Exception("No RemotingManager in ServiceEnvironment.");

// Start the ServiceEnvironment.
se.Open();

Uri serverPortUri =
new Uri("soap.tcp://localhost:46010/TimeZoneObjects");

// Build a proxy to an existing object
string urn = "urn:" + zone;
TimeZoneObject tzo =
rm.GetObject (serverPortUri, new Uri(urn)) as TimeZoneObject;

if (tzo != null) {
Console.WriteLine ("It is currently {0} in the {1} time zone.",
tzo.GetCurrentTimeAndDate (ci), zone);
}
else {
Console.WriteLine ("Could not connect to the remote object.");
}
}
finally {
if (se != null) se.Close();
}
}
}

Allowing Clients to Create a New Instance of a RemoteObject

A RemoteObject host application can also allow client applications to create their very own personal, private instances of a hosted class. In this case, the hosting application is typically extremely simple. It simply loads the configuration file in which all the real information resides.

 using System; 
using System.MessageBus;
using System.MessageBus.Remoting;

class Host {
static void Main() {
ServiceEnvironment se = null;

try {
se = ServiceEnvironment.Load ();
se.Open ();

Console.WriteLine ("Listening for requests. Press Enter to exit...");
Console.ReadLine ();
}
finally {
if (se != null) se.Close ();
}
}
}

A configuration file that allows clients to create new instances of types contains a publishedServerTypes element. Each publishedServerTypes element s child add element lists a fully qualified type that client applications can request the server to create.

 <configuration> 
<system.messagebus>
<serviceEnvironments>
<serviceEnvironment name="main">
<port>
<identityRole>
soap.tcp://localhost:46010/TimeZoneObjects
</identityRole>
</port>
<!-- CAUTION: Security disabled for demonstration purposes only. -->
<remove name="securityManager" />
<policyManager>
<!-- CAUTION: Security disabled for demonstration purposes only. -->
<!-- Permits unsigned policy statements. Default requires signed policy statements -->
<areUntrustedPolicyAttachmentsAccepted>
true
</areUntrustedPolicyAttachmentsAccepted>
<isPolicyReturned>true</isPolicyReturned>
</policyManager>
<remotingManager>
<publishedServerTypes>
<add type="TimeZoneObject, TimeZoneObject"/>
</publishedServerTypes>
</remotingManager>
</serviceEnvironment>
</serviceEnvironments>
</system.messagebus>
</configuration>

Creating a New Instance of a RemoteObject

A client application can also create its very own personal, private instance of a remote class using the RemotingManager . The host application in this case is extremely simple:

  • Creating the ServiceEnvironment by calling the Load method as usual

  • Obtaining a RemotingManager from the ServiceEnvironment

  • Opening the ServiceEnvironment

  • Creating a URI that addresses the desired RemotingObject server

  • Calling the RemotingManager GetObject method and specifying the server s URI and the unique name of the specific object to which you want to connect

  • Calling methods, access fields, and properties on the remote object

The following RemotingObject client application connects to a published TimeZoneObject and retrieves and displays the current time in that time zone.

 using System; 
using System.Globalization;
using System.MessageBus;
using System.MessageBus.Remoting;

class Client {
static void Main (string[] args) {
string zone = "PST";
if (args.Length > 0 && args[0].Length > 0) zone = args[0];

CultureInfo ci = new CultureInfo ("");
if (args.Length > 1 && args[1].Length > 0) ci = new CultureInfo (args[1]);

ServiceEnvironment se = null;

try {
se = ServiceEnvironment.Load ();
RemotingManager rm = se[typeof(RemotingManager)] as RemotingManager;
if (rm == null)
throw new Exception("No RemotingManager in ServiceEnvironment.");

// Start the ServiceEnvironment.
se.Open();

Uri serverPortUri =
new Uri("soap.tcp://localhost:46010/TimeZoneObjects");

// Build a proxy to an existing object
string urn = "urn:" + zone;
TimeZoneObject tzo =
rm.GetObject (serverPortUri, new Uri(urn)) as TimeZoneObject;

if (tzo != null) {
Console.WriteLine ("It is currently {0} in the {1} time zone.",
tzo.GetCurrentTimeAndDate (ci), zone);
}
else {
Console.WriteLine ("Could not connect to the remote object.");
}
}
finally {
if (se != null) se.Close();
}
}
}



Introducing Microsoft WinFX
Introducing WinFX(TM) The Application Programming Interface for the Next Generation of Microsoft Windows Code Name Longhorn (Pro Developer)
ISBN: 0735620857
EAN: 2147483647
Year: 2004
Pages: 83
Authors: Brent Rector

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