|
Sharing transient
state in a multi-user application deployed in COM+ has always
been a problem. For example, let’s say that an application component
(Component A) is called and it set the values of some of its instance
variables. If another component in the application wants to access
this “state”, there is no direct way to do it. A couple of solutions
to this exist though. One solution is to stream the state of the
object variables into a file and read this information in the
other component. Although this is quite a workable solution, it
has nothing to do with the business logic and is therefore
extra code that someone has to write and maintain. The COM+ Shared
Property Manager (SPM) provides just the solution that we
need by allowing applications to use a standard API to create
and share properties.
This article looks at how you can use the
COM+ Shared Property Manager (SPM) in .NET to implement the sharing
of state across components. I’m assuming that you are familiar
with VB.NET, Windows Forms, Serviced Components and COM+. Before
we actually get down to see the solutions, let’s get aside some
basics first.
What is the Shared Property Manager?
In COM+, shared transient state for objects
is managed by using the Shared Property Manager (SPM). The SPM
is a resource dispenser that you can use to share state among
multiple objects within a server process.
You cannot use global variables in a distributed
environment because of concurrency and name collision issues.
The Shared Property Manager eliminates name collisions by providing
shared property groups, which establish unique namespaces for
the shared properties they contain. The SPM also implements locks
and semaphores to protect shared properties from simultaneous
access, which could result in lost updates and leave properties
in an unpredictable state.
Shared properties stored in the SPM are available
only to objects running in the same process. This means that the
objects that will use the SPM for storing values and that will
need to have access to these values must be installed as part
of the same COM+ application. It is possible for system administrators
to move COM+ classes from one package to another after your COM+
application has been deployed. If you rely on several objects
sharing properties through the SPM, you should clearly document
that they must be installed in the same COM+ application.
It's also important for components sharing
properties to have the same activation attribute. If two components
in the same package have different activation attributes, they
generally won't be able to share properties. For example, if one
component is configured to run in a client process and the other
is configured to run in a server process, their objects will usually
run in different processes even though they're in the same package.
*
Shared transient state is state information kept
in memory that does not survive system failures. The information
is designed to be shared by multiple objects across transaction
(but not across process) boundaries.
Shared Property Manager API
In COM+, shared properties are organized
into groups. These groups provide a sort of “namespace” that organizes
all the properties for a process. In addition, groups help reduce
the number of possible naming conflicts among properties. For
instance, a group cannot have two properties with the same name,
but two different groups can have properties with the same name.
The API for COM+ SPM then, is organized around
three main objects as shown in the following diagram.

The following table explains each of the
above objects.
|
Object Name |
Description |
|
SharedPropertyGroupManager |
This object
allows you to create a group manager that helps you manage
all the property groups for an application. This is the
only object that can be directly instantiated. |
|
SharedPropertyGroup |
This object
allows you to create a property group which can then hold
a set of properties. To create this object you first need
to create a group manager. |
|
SharedProperty |
This object
allows you to create the properties that your application
needs to share between the various components in an application. |
The following sections explain each of these
objects in more detail and take a look at the various methods.
The SharedPropertyGroupManager Object
The SharedPropertyGroupManager is
the only object that you will directly create. This object allows
you to create property groups and has a constructor that takes
no arguments. If you were to write code for this, the code would
look like the following:
|
Imports
System
Imports
System.EnterpriseServices
Public
Class myClass : Inherits ServicedComponent
Private spmGroupManager As SharedPropertyGroupManager
Public Sub someMethod()
spmGroupManager = New SharedPropertyGroupManager
End Sub
End
Class
|
The following table shows some of the core
methods of this object.
|
Method Name |
Description |
|
CreatePropertyGroup |
This method
finds or creates a property group with the given information.
This method takes the following parameters:
1.
Group Name. This argument indicates the name
of the property group that you want to create.
2.
Lock Mode. This argument indicates how accesses
to the properties in this group are locked. The possible
values are Method and SetGet. Method
indicates that accesses to the properties in this group
are locked until the method that is using those exits. This
means that other objects that want to access the same properties
have to wait for the method to get over. SetGet indicates
that accesses to the properties are locked for the duration
of the access only.
3.
Release Mode. This argument indicates when the
properties for this group are released from memory. The
possible values are Process and Standard.
Process indicates that the memory this group occupies
is freed only when the hosting process terminates. Standard
frees the memory when the last client releases a reference
to the group.
4.
Exists Flag. This argument indicates whether
the group asked for already exists. |
|
Group |
This method
requests for a group that already exists. You should use
this method only if you know that the group already exists.
It is better to encapsulate this method inside a Try…Catch
block. |
The SharedPropertyGroup Object
Once you have created a shared property group
manager object, your next step would be to create a property group
that can be used to store properties. To create a property group,
you use the SharedPropertyGroupManager object to create
a group and store its reference into an object of type SharedPropertyGroup.
The following code snippet shows how a group can be created.
|
Imports
System
Imports
System.EnterpriseServices
Public
Class myClass : Inherits ServicedComponent
Private spmGroupManager
As SharedPropertyGroupManager
Private spmGroup As
SharedPropertyGroup
Private bExists As
Boolean
Public Sub someMethod()
spmGroupManager = New SharedPropertyGroupManager
spmGroup = spmGroupManager.CreatePropertyGroup("MyGroup",
_
PropertyLockMode.Method, PropertyReleaseMode.Process, bExists)
End Sub
End
Class
|
The following table illustrates the core
methods of the SharedPropertyGroup class.
|
Method Name |
Description |
|
CreateProperty |
This method
creates a property with the given name and takes the following
arguments.
1.
Name. This argument indicates the name of
the property to create.
2.
Exists Flag. This flag indicates whether a
property with the same name already exists.
The output
of this method call is a reference to an object of type
SharedProperty. |
|
CreatePropertyByPosition |
This method
creates a property based on position rather than by name
and takes the following arguments.
1.
Position. This argument indicates the position
where the property is to be created and replaces the name
of the property. The position can be any valid integer value,
including positive and negative numbers.
2.
Exists Flag. This flag indicates whether a
property with the same position already exists.
Note that properties
created by position cannot be retrieved by a method
that looks at name. For example, if you created a property
by using CreateProperty, you cannot access it by
using the CreatePropertyByPosition. |
|
Property |
This method
returns the property with the given name and takes as argument
the name of the property. |
|
PropertyByPosition |
This method
returns the property at the given position and takes as
argument the position for the property. |
The SharedProperty Object
Once you have created a shared property group
object, your next step would be to create the properties. To create
a property, you use the SharedProperty object to create
a property and use its methods to store and retrieve values from
it. The following code snippet shows how a property can be created.
|
Imports
System
Imports
System.EnterpriseServices
Public
Class myClass : Inherits ServicedComponent
Private spmGroupManager
As SharedPropertyGroupManager
Private spmGroup As
SharedPropertyGroup
Private spmProperty As
SharedProperty
Private bExists As
Boolean
Public Sub someMethod()
spmGroupManager = New SharedPropertyGroupManager
spmGroup = spmGroupManager.CreatePropertyGroup("MyGroup",
_
PropertyLockMode.Method, PropertyReleaseMode.Process,
bExists)
spmProperty = spmGroup.CreateProperty("ConnString",
bExists)
spmProperty.Value = "(a sample connection string)"
End Sub
End
Class
|
The only property of a shared property is
the value, which gives the current value stored in the
property.
Ok, now that we have looked at the core basics,
we have enough knowledge to construct a useful application that
demonstrates the usage of shared properties. I have written a
windows forms application and a couple of classes that can be
deployed in COM+ to illustrate all these concepts. The following
sections outline the sample application.
Sample Application
The sample application discussed here will
show you how to use the SPM in COM+ from .NET. The overall architecture
of the sample is as follows:
·
We create a class that contains the basic methods
to create the SPM and populate it with a property and its value.
·
We then create two clients that provide methods
to get the property value and to also set it to a different value.
Along the way, we will see how clients are locked between property
accesses.
*
Note that not all areas of COM+ SPM are covered.
For coverage of all the areas and the possible methods, you
can refer to the MSDN library.
Based on the above explanation, here is a
diagrammatic representation of how the application will work.

Fire-up Visual Studio .NET and follow the
steps outlined below.
1.
Create a class library project and name it ComSpm
as shown in the following figure.

2.
When you click on [Ok], VS.NET creates a solution
of the same name and a class library.
3.
Open the VS.NET command line prompt and type in the following
command.
Store the Sct.snk file into the C:\
folder. This file will be used to sign all the assemblies created.
Note that if you change this name or the folder, you need to
make the corresponding changes in the all the assembly information
files.
4.
Right-click the references node and add a reference to
System.EnterpriseServices. Also rename the class file to
MainComponent.vb.
5.
Paste the following code into the code editor.
|
Imports
System
Imports
System.EnterpriseServices
' This class is the main component that will
create the shared property
' groups and the associated properties
<EventTrackingEnabled(True)>
_
Public
Class MainComponent : Inherits
ServicedComponent
Private
spmGroupManager As SharedPropertyGroupManager
Private
spmGroup As SharedPropertyGroup
Private
spmProperty As SharedProperty
Private
bExists As Boolean
Public
Sub New()
' Create
the shared property group manager. It is by this object
' that
we can access all the other objects
spmGroupManager = New SharedPropertyGroupManager
' Create
a property group and give it a name. The property group
will
' lock
at the method level and will be released when the process
ends
spmGroup = spmGroupManager.CreatePropertyGroup("MyGroup",
_
PropertyLockMode.Method, PropertyReleaseMode.Process, bExists)
' Create
a property and assign a value to it
spmProperty = spmGroup.CreateProperty("ConnString",
bExists)
spmProperty.Value = "(a sample connection string)"
End
Sub
End
Class
|
6.
Open the AssemblyInfo.vb file and paste the following
code.
|
Imports
System
Imports
System.Reflection
Imports
System.Runtime.InteropServices
Imports
System.EnterpriseServices
' General Information about an assembly is
controlled through the following
' set of attributes. Change these attribute
values to modify the information
' associated with an assembly.
' Review the values of the assembly attributes
<Assembly: AssemblyTitle("")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("")>
<Assembly: AssemblyCopyright("")>
<Assembly: AssemblyTrademark("")>
<Assembly: CLSCompliant(True)>
<Assembly: ApplicationName("SriSamp")>
<Assembly: ApplicationActivation(ActivationOption.Server)>
<Assembly: AssemblyKeyFile("C:\Sct.snk")>
'The following GUID is for the ID of the
typelib if this project is exposed to COM
<Assembly: Guid("F3C200B5-341D-4A56-AF46-1945E01F985D")>
' Version information for an assembly consists
of the following four values:
'
' Major Version
' Minor Version
' Build Number
' Revision
'
' You can specify all the values or you can
default the Build and Revision Numbers
' by using the '*' as shown below:
<Assembly: AssemblyVersion("1.0.0.1")>
|
Note that I have specified the COM+ application
name to be SriSamp and the application type to be Server.
The assembly will be signed using the key generated in the earlier
step.
7.
Right click on the solution and add a new class library
project and name it ClientA. You can instruct VS.NET to
place this project within the ComSpm project.
8.
Add a reference to System.EnterpriseServices and
also rename the class file to ClientA.vb.
9.
Paste the following code into the code editor.
|
Imports
System
Imports
System.EnterpriseServices
Imports
System.Threading
' This class is a client component that will
query the property and
' get its value
<EventTrackingEnabled(True)>
_
Public
Class ClientA : Inherits
ServicedComponent
Private
spmGroupManager As SharedPropertyGroupManager
Public
Function GetPropertyValue()
As String
Dim strValue As
String
' Create
a property manager object and access the property
spmGroupManager = New SharedPropertyGroupManager
Try
strValue = spmGroupManager.Group("MyGroup").Property("ConnString").Value
Catch ex As
Exception
strValue = "(property does not exist)"
End Try
Return (strValue)
End
Function
Public
Sub SetPropertyValue(ByVal
strValue As String)
' Create
a property manager and access the property
spmGroupManager = New SharedPropertyGroupManager
Try
spmGroupManager.Group("MyGroup").Property("ConnString").Value
= "(property value set from ClientA) = " + strValue
Catch ex As
Exception
strValue = "(could not set property value from ClientA)"
End Try
Thread.Sleep(3000)
End
Sub
End
Class
|
Note that we have specified a Thread.Sleep(3000)
in the SetPropertyValue method. This is to force the method
to wait so that we can demonstrate the act of locking of shared
properties. Also, note that we try to access the ConnString
property directly in the method and catch exceptions if any.
10.
Open the AssemblyInfo.vb file and paste the following
code.
|
Imports
System
Imports
System.Reflection
Imports
System.Runtime.InteropServices
Imports
System.EnterpriseServices
' General Information about an assembly is
controlled through the following
' set of attributes. Change these attribute
values to modify the information
' associated with an assembly.
' Review the values of the assembly attributes
<Assembly: AssemblyTitle("")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("")>
<Assembly: AssemblyCopyright("")>
<Assembly: AssemblyTrademark("")>
<Assembly: CLSCompliant(True)>
<Assembly: ApplicationName("SriSamp")>
<Assembly: ApplicationActivation(ActivationOption.Server)>
<Assembly: AssemblyKeyFile("C:\Sct.snk")>
'The following GUID is for the ID of the
typelib if this project is exposed to COM
<Assembly: Guid("3E17D6A5-F98F-4FD4-8B61-B276EFE05B8E")>
' Version information for an assembly consists
of the following four values:
'
' Major Version
' Minor Version
' Build Number
' Revision
'
' You can specify all the values or you can
default the Build and Revision Numbers
' by using the '*' as shown below:
<Assembly: AssemblyVersion("1.0.0.1")>
|
This file is very similar to the one that
we placed for the MainComponent class.
11.
Right click on the solution and add a new class library
project and name it ClientB. You can instruct VS.NET to
place this project within the ComSpm project.
12.
Add a reference to System.EnterpriseServices and
also rename the class file to ClientB.vb.
13.
Paste the following code into the code editor.
|
Imports
System
Imports
System.EnterpriseServices
' This class is a client component that will
query the property and
' get its value
<EventTrackingEnabled(True)>
_
Public
Class ClientB : Inherits
ServicedComponent
Private
spmGroupManager As SharedPropertyGroupManager
Public
Function GetPropertyValue()
As String
Dim strValue As
String
' Create
a property manager object and access the property
spmGroupManager = New SharedPropertyGroupManager
Try
strValue = spmGroupManager.Group("MyGroup").Property("ConnString").Value
Catch ex As
Exception
strValue = "(property does not exist)"
End Try
Return (strValue)
End
Function
Public
Sub SetPropertyValue(ByVal
strValue As String)
' Create
a property manager and access the property
spmGroupManager = New SharedPropertyGroupManager
Try
spmGroupManager.Group("MyGroup").Property("ConnString").Value
= "(property value set from ClientB) = " + strValue
Catch ex As
Exception
strValue = "(could not set property value from ClientB)"
End Try
End
Sub
End
Class
|
14.
Open the AssemblyInfo.vb file and paste the following
code.
|
Imports
System
Imports
System.Reflection
Imports
System.Runtime.InteropServices
Imports
System.EnterpriseServices
' General Information about an assembly is
controlled through the following
' set of attributes. Change these attribute
values to modify the information
' associated with an assembly.
' Review the values of the assembly attributes
<Assembly: AssemblyTitle("")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("")>
<Assembly: AssemblyCopyright("")>
<Assembly: AssemblyTrademark("")>
<Assembly: CLSCompliant(True)>
<Assembly: ApplicationName("SriSamp")>
<Assembly: ApplicationActivation(ActivationOption.Server)>
<Assembly: AssemblyKeyFile("C:\Sct.snk")>
'The following GUID is for the ID of the
typelib if this project is exposed to COM
<Assembly: Guid("0E02595E-4A0F-4879-B5C0-0438DB11CA1B")>
' Version information for an assembly consists
of the following four values:
'
' Major Version
' Minor Version
' Build Number
' Revision
'
' You can specify all the values or you can
default the Build and Revision Numbers
' by using the '*' as shown below:
<Assembly: AssemblyVersion("1.0.0.1")>
|
15.
You will now need to build all these three class libraries.
You can do this by right-clicking each project and selecting Build
from the context menu that appears.
16.
After you have built the projects successfully, you need
to register these with COM+ so that they appear in the COM+ explorer.
To do this, I wrote a simple batch file that has the following
contents.
|
regsvcs
.\bin\ComSpm.dll
regsvcs
.\ClientA\bin\ClientA.dll
regsvcs
.\ClientB\bin\ClientB.dll
|
You need to then save this batch file (let’s
call it register.bat) in the same directory as of the application.
When you run this batch file, all the three components are registered
with COM+ and appear in the MMC snap-in as shown.

Note that I’m running COM+ 1.5 in Windows
XP, thus you might not see all the nodes displayed here (like
legacy components) if you are using an earlier version of COM+.
17.
Now right-click the COM+ application, select Properties.
In the dialog box that opens, choose the Security tab and
clear the Enforce Access Checks For This Application checkbox
as shown.

18.
Right click on the solution and add a new windows forms
project and call it TestApp. I designed the following form
(called frmTestSpm) with the following naming conventions
(all other values were left as their defaults).

19.
Add a reference to System.EnterpriseServices, ClientA,
ClientB for this form.
20.
Open the code editor for this form and paste the following
code in it. Note that the forms designer would have created
some code. Do not overwrite it.
|
Public
Class frmTestSpm
Inherits System.Windows.Forms.Form
Private
Sub cmdCreateSpm_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
cmdCreateSpm.Click
' Create
the SPM main component so that the SPM is initialized
' with
some property and value
Dim oComSpm As
ComSpm.MainComponent
oComSpm = New ComSpm.MainComponent
oComSpm.Dispose()
MsgBox("COM+ SPM has been initialized.", MsgBoxStyle.OKOnly,
"COM+ SPM Test")
End
Sub
Private
Sub cmdClientAGet_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
cmdClientAGet.Click
' Create
and call the ClientA object's methods. This component assumes
' that
the SPM has some property based on which a result is returned
Dim oClientA As
ClientA.ClientA
Dim strValue As
String
Try
oClientA = New ClientA.ClientA
txtClientAOutput.Text = "Client A has been initialized..."
+ vbCrLf
strValue
= oClientA.GetPropertyValue()
txtClientAOutput.Text = txtClientAOutput.Text + "Property
Value = " + strValue + vbCrLf
Catch ex As
Exception
txtClientAOutput.Text = ex.Message
End Try
oClientA.Dispose()
End
Sub
Private
Sub cmdClientBGet_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
cmdClientBGet.Click
' Create
and call the ClientB object's methods. This component assumes
' that
the SPM has some property based on which a result is returned
Dim oClientB As
ClientB.ClientB
Dim strValue As
String
Try
oClientB = New ClientB.ClientB
txtClientBOutput.Text = "Client B has been initialized..."
+ vbCrLf
strValue
= oClientB.GetPropertyValue()
txtClientBOutput.Text = txtClientBOutput.Text + "Property
Value = " + strValue + vbCrLf
Catch ex As
Exception
txtClientBOutput.Text = ex.Message
End Try
oClientB.Dispose()
End
Sub
Private
Sub cmdClientASet_Click(ByVal
sender As System.Object,
ByVal e As
System.EventArgs) Handles
cmdClientASet.Click
' Create the ClientA object and call the
method that sets a value. After setting the
' value sleep for 3 seconds
Dim
oClientA As ClientA.ClientA
Try
oClientA = New ClientA.ClientA
oClientA.SetPropertyValue("CLIENTA")
txtClientAOutput.Text = txtClientAOutput.Text + oClientA.GetPropertyValue()
+ vbCrLf
Catch
ex As Exception
txtClientBOutput.Text = ex.Message
End
Try
oClientA.Dispose()
End
Sub
End
Class
|
What this code essentially does is to instantiate
the various objects in COM+ and then calls the appropriate methods
in them. The output from each method is then aggregated and displayed
in the appropriate text boxes.
21.
Now you are all done! Your solution explorer should now
look like this.

22.
Make TestApp as the startup project and press F5
to run the application and the following screen appears.
|
 |
You can play around with this application and click the
various buttons to see how the SPM works and the properties
are retrieved.
If you run
two instances of this application and press [Client
A (Set)] in one instance and the [Client A (Get)]
in the other instance parallely, you will see that the
second instance will wait for 3 seconds and then get the
property. Remember the sleep that we put? That’s causing
this client to wait…
Make sure
that you click the [Create SPM] button first; otherwise
you will see exception messages displayed in the text
boxes. |
That brings us to the end of this article.
We have seen COM+ SPM working for us and how it can be used to
share properties between components running in the same COM+ application.
You can experiment with the code given and try out various other
possibilities like using positional properties etc. Hopefully,
I have shown you the power that the SPM can give to your applications
and I leave it to you readers to experiment.
Conclusion
In this article, we have seen how COM+ SPM
works. In future articles we will see some more interesting features
of COM+. You can also look at the MSDN India site for a set of
articles on the various COM+ features.
For comments and suggestions on this article
and on articles that you might want me to explore, mail me at:
mailto:srisamp@hotmail.com
|