I created an example that uses two approaches: 1) A Singleton SAO factory that returns an MBR object and
2) A Singleton SAO factory that returns a ObjRef to another Singleton SAO.
In order to implement a true Singleton object you must return a Singleton SAO to the client, method #2.
The only way to do so is to create an SAO on the server using the Activator class and to return an ObjRef
to the client by Marshaling the SAO reference yourself.
(See 2nd entry below for an update)
There are fundamental differences between these two types of remote objects and the context
of how you use an object alone does not determine whether it is an SAO or CAO.
How you activate an object seem to determine this classification and most importantly
any MBR object returned to a client that is created by another remote object (factory pattern)
that is created with the New statement will be classified as a CAO. The key fundamental
difference between an SAO and CAO is their lifetime management with leases. SAO lifetimes
are controlled by the server, whereas CAO lifetimes are controlled by the client. If you
attempt to use a CAO as a singleton that services all clients it's lifetime will be controlled
by the first client that creates it. Even if you give this CAO a lifetime lease, it is not the
same as a lifetime lease on an SAO. As soon as the reference from the first client goes
out of scope or is set to nothing your CAO singleton will be recycled on the server once
it's lease expires. Below are some references to an MSDN article and the .NET documentation
that discusses this in more depth and a sample output from the running of the code.
___________________________________________________________________
Here are some more observations after playing with this some more. In my
first test run below in my first message, my Singleton SAO factory object,
ObjectPublisher, did not have a lifetime lease. Therefore, it was this
object that was being reclaimed after 5 minutes, NOT the contained MBR,
MySharedObject. With a lifetime lease on ObjectPublisher, the same
MySharedObject instance was returned to all the clients and "behaved" like a
Singleton, maintaining it's state in between calls. However, the returned
MySharedObject to the client is a CAO. Lifetime management is definitely
different between a CAO and a SAO and I would think odds are high that there
are more low level differences. Another side effect of the CAO approach is
that your CAO object's lifetime will be dependent on the lifetime of the
factory. If your factory has a lifetime lease, then in theory this should
not be a problem, but generally you would not want the life of an object
created by a factory object dependent on that factory for its existence.
Therefore, it seems that both options - 1) A Singleton SAO factory that
returns an MBR object that will be a CAO and 2) A Singleton SAO factory that
returns a ObjRef to another Singleton SAO - are viable. Although the CAO
approach does behave like a Singleton my personal preference would be to
lean towards the safe side and returning a true Singleton SAO to the client.
___________________________________________________________________
Client Activation
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconclientactivation.asp Here's an excerpt: The client might even request an indefinite default lifetime, effectively preventing the remote object from ever being recycled until the server application domain is torn down. The difference between this and a server-activated indefinite lifetime is that an indefinite server-activated object will serve all client requests for that type, whereas the client-activated instances serve only the client and the reference that was responsible for their creation.
Managing the Lifetime of Remote .NET Objects with Leasing and Sponsorship by Juval Lowy
http://msdn.microsoft.com/msdnmag/issues/03/12/LeaseManager/default.aspx Here's an excerpt: The case of the client-activated object is the one affected most by the leasing mechanism. When using a client-activated model, every client that creates a new object gets a dedicated server object. That object's lifetime is governed by a lease, and the object will be disconnected from the clients once its lease has expired. The only safe way to manage client-activated objects is to use sponsors. All other options, such as global lease properties or configuring individual objects' leases, are speculative at best. Ultimately, only the client knows when it no longer needs the object. ___________________________________________________________________
Console output from running attached test. Test Run#1 (No lifetime lease on SAO Factory):
************************************************************************
Remote Client #1
Note the URL & GUID of the CAO and the returned value from GetIntData from both the CAO
and SAO MySharedObjects.
************************************************************************
Configuring Remoting
8/1/2004 8:33:22 AM
- ISAOGetter type URL: Type = SAO | http://localhost:8085/ObjectPublisher
8/1/2004 8:33:23 AM
- myTempBO type URL: Type = CAO | http://192.0.2.2:8085/83f08688_4a07_43c9
_9d65_2e74985d3d3d/zDt2ajj8J4t1pfg7TRmpHm_A_1.rem
- Guid: 2edddb26-f812-4942-bbff-e65e99c0292e
- GetIntData = 1 <-------------------
8/1/2004 8:33:23 AM
- myTempBO type URL: Type = CAO | http://192.0.2.2:8085/83f08688_4a07_43c9
_9d65_2e74985d3d3d/zDt2ajj8J4t1pfg7TRmpHm_A_1.rem
- Guid: 2edddb26-f812-4942-bbff-e65e99c0292e
- GetIntData = 2 <-------------------
8/1/2004 8:33:23 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: 1f6bf760-57ee-4379-8006-62adf6cc200c
- GetIntData = 1 <-------------------
8/1/2004 8:33:23 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: 1f6bf760-57ee-4379-8006-62adf6cc200c
- GetIntData = 2 <-------------------
CAO reference set to Nothing.
************************************************************************
Remote Client #2 (launched 7 seconds after #1)
Note the URL & GUID of the CAO are the same as for #1 and the returned value from GetIntData
has continued where #1 left off for both the CAO and SAO.
************************************************************************
Configuring Remoting
8/1/2004 8:33:30 AM
- ISAOGetter type URL: Type = SAO | http://localhost:8085/ObjectPublisher
8/1/2004 8:33:30 AM
- myTempBO type URL: Type = CAO | http://192.0.2.2:8085/83f08688_4a07_43c9
_9d65_2e74985d3d3d/zDt2ajj8J4t1pfg7TRmpHm_A_1.rem
- Guid: 2edddb26-f812-4942-bbff-e65e99c0292e
- GetIntData = 3 <-------------------
8/1/2004 8:33:30 AM
- myTempBO type URL: Type = CAO | http://192.0.2.2:8085/83f08688_4a07_43c9
_9d65_2e74985d3d3d/zDt2ajj8J4t1pfg7TRmpHm_A_1.rem
- Guid: 2edddb26-f812-4942-bbff-e65e99c0292e
- GetIntData = 4 <-------------------
8/1/2004 8:33:30 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: 1f6bf760-57ee-4379-8006-62adf6cc200c
- GetIntData = 3 <-------------------
8/1/2004 8:33:30 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: 1f6bf760-57ee-4379-8006-62adf6cc200c
- GetIntData = 4 <-------------------
CAO reference set to Nothing.
************************************************************************
Remote Client #3 (launched 7 MINUTES after #2)
Note the URL & GUID of the CAO are NOT the same as for #1 and #2. This is a
totally DIFFERENT object. This CANNOT be a Singleton by definition.
Note that the returned value from GetIntData has NOT been continued where #2 left off
for the CAO, but has restarted at 1.
Note that the returned value from the GetIntData for the SAO MySharedObject CONTINUES
to increment where #2 left off. This is THE SAME object answering client requests
and is a Singleton by definition.
*************************************************************************
Configuring Remoting
8/1/2004 8:40:00 AM
- ISAOGetter type URL: Type = SAO | http://localhost:8085/ObjectPublisher
8/1/2004 8:40:00 AM
- myTempBO type URL: Type = CAO | http://192.0.2.2:8085/83f08688_4a07_43c9
_9d65_2e74985d3d3d/tShr4Faa2r2UEPsUfu8eEuAo_2.rem
- Guid: 40f316da-9c95-4daf-b14a-1776f7e0b476
- GetIntData = 1 <-------------------
8/1/2004 8:40:00 AM
- myTempBO type URL: Type = CAO | http://192.0.2.2:8085/83f08688_4a07_43c9
_9d65_2e74985d3d3d/tShr4Faa2r2UEPsUfu8eEuAo_2.rem
- Guid: 40f316da-9c95-4daf-b14a-1776f7e0b476
- GetIntData = 2 <-------------------
8/1/2004 8:40:00 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: 1f6bf760-57ee-4379-8006-62adf6cc200c
- GetIntData = 5 <-------------------
8/1/2004 8:40:00 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: 1f6bf760-57ee-4379-8006-62adf6cc200c
- GetIntData = 6 <-------------------
CAO reference set to Nothing.
_______________________________________________________________________
Console output from running attached test. Test run#2 (Lifetime lease on SAO Factory):
************************************************************************
Remote Client #1
Note the URL & GUID of the CAO and the returned value from GetIntData from both the CAO
and SAO MySharedObjects.
************************************************************************
Configuring Remoting
8/2/2004 11:27:39 AM
- ISAOGetter type URL: Type = SAO | http://localhost:8085/ObjectPublisher
8/2/2004 11:27:40 AM
- myTempBO type URL: Type = CAO | http://127.0.0.1:8085/87861b38_5aab_4320
_8844_06e78e937d6a/VsLMsusbiRukKWYE6GjQXrQf_1.rem
- Guid: 8a33880d-4f6a-4436-84d6-b3dc96441271
- GetIntData = 1 <-------------------------------------------------
8/2/2004 11:27:40 AM
- myTempBO type URL: Type = CAO | http://127.0.0.1:8085/87861b38_5aab_4320
_8844_06e78e937d6a/VsLMsusbiRukKWYE6GjQXrQf_1.rem
- Guid: 8a33880d-4f6a-4436-84d6-b3dc96441271
- GetIntData = 2 <-------------------------------------------------
8/2/2004 11:27:40 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: f74fc69e-fa0c-4adb-9a5d-6bec1718e4a0
- GetIntData = 1 <-------------------------------------------------
8/2/2004 11:27:40 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: f74fc69e-fa0c-4adb-9a5d-6bec1718e4a0
- GetIntData = 2 <-------------------------------------------------
CAO reference set to Nothing.
************************************************************************
Remote Client #2 (launched 15 seconds after #1)
Note the URL & GUID of the CAO are the same as for #1 and the returned value from GetIntData
has continued where #1 left off for both the CAO and SAO.
************************************************************************
Configuring Remoting
8/2/2004 11:27:55 AM
- ISAOGetter type URL: Type = SAO | http://localhost:8085/ObjectPublisher
8/2/2004 11:27:55 AM
- myTempBO type URL: Type = CAO | http://127.0.0.1:8085/87861b38_5aab_4320
_8844_06e78e937d6a/VsLMsusbiRukKWYE6GjQXrQf_1.rem
- Guid: 8a33880d-4f6a-4436-84d6-b3dc96441271
- GetIntData = 3 <-------------------------------------------------
8/2/2004 11:27:55 AM
- myTempBO type URL: Type = CAO | http://127.0.0.1:8085/87861b38_5aab_4320
_8844_06e78e937d6a/VsLMsusbiRukKWYE6GjQXrQf_1.rem
- Guid: 8a33880d-4f6a-4436-84d6-b3dc96441271
- GetIntData = 4 <-------------------------------------------------
8/2/2004 11:27:55 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: f74fc69e-fa0c-4adb-9a5d-6bec1718e4a0
- GetIntData = 3 <-------------------------------------------------
8/2/2004 11:27:55 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: f74fc69e-fa0c-4adb-9a5d-6bec1718e4a0
- GetIntData = 4 <-------------------------------------------------
CAO reference set to Nothing.
************************************************************************
Remote Client #3 (launched 9 MINUTES after #2)
Note the URL & GUID of the CAO ARE the same as for #1 and #2. This is the SAME
object.
Note that the returned value from GetIntData has remembered state for both the CAO
and SAO approach.
These are THE SAME objects answering client requests and are Singletons by definition.
************************************************************************
Configuring Remoting
8/2/2004 11:36:46 AM
- ISAOGetter type URL: Type = SAO | http://localhost:8085/ObjectPublisher
8/2/2004 11:36:47 AM
- myTempBO type URL: Type = CAO | http://127.0.0.1:8085/87861b38_5aab_4320
_8844_06e78e937d6a/VsLMsusbiRukKWYE6GjQXrQf_1.rem
- Guid: 8a33880d-4f6a-4436-84d6-b3dc96441271
- GetIntData = 5 <-------------------------------------------------
8/2/2004 11:36:47 AM
- myTempBO type URL: Type = CAO | http://127.0.0.1:8085/87861b38_5aab_4320
_8844_06e78e937d6a/VsLMsusbiRukKWYE6GjQXrQf_1.rem
- Guid: 8a33880d-4f6a-4436-84d6-b3dc96441271
- GetIntData = 6 <-------------------------------------------------
8/2/2004 11:36:47 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: f74fc69e-fa0c-4adb-9a5d-6bec1718e4a0
- GetIntData = 5 <-------------------------------------------------
8/2/2004 11:36:47 AM
- myTempBO2 type URL: Type = SAO | http://localhost:8085/MySharedObject
- Guid: f74fc69e-fa0c-4adb-9a5d-6bec1718e4a0
- GetIntData = 6 <-------------------------------------------------
CAO reference set to Nothing.