Access Mechanism (and Transient Storage)
You also need to think about how to access the configuration data. You can, of course, go to the persistent storage each and every time, but this is probably too costly if you need to go there often. Therefore, the following are a few techniques that I'd like to discuss for providing an access mechanism to transient storage. (Note that this list is not exhaustive.)
- Using the Shared Properties Manager (SPM)
- Using Object Construction (OC)
- Using a Shared (static) member
- Using the ThreadStatic attribute
- Using Object Pooling (OP)
Once again, let's look at each of these techniques in detail, starting with the SPM.
Using the Shared Properties Manager (SPM)
The Shared Properties Manager (SPM) is an old, faithful component service that is still around. You can use it from your serviced components as a dictionary object to store keys and values, similar to the Application object in ASP.NET. However, the SPM can group the keys in property groups.
The programming model of the SPM is a bit different from other dictionary objects, but it's still quite simple. You can see a sample in Listing 2, where a value is read from the SPM (or written, if it wasn't found in the SPM).
Listing 2: Reading a Value That Is Stored in the SPM
Imports System.EnterpriseServices Public Class SpmTest Inherits ServicedComponent Public Function Test() As String Dim theExist As Boolean Dim aManager As New SharedPropertyGroupManager() Dim aGroup As SharedPropertyGroup = _ aManager.CreatePropertyGroup("MyGroup", _ PropertyLockMode.SetGet, _ PropertyReleaseMode.Process, theExist) Dim aProperty As SharedProperty = _ aGroup.CreateProperty("MyProperty", theExist) If Not theExist Then aProperty.Value = Now.ToString() End If Return aProperty.Value.ToString() End Function End Class
Using Object Construction (OC)
In the previous section, I talked about OC as a mechanism for persistent storage, but it is also a mechanism for accessing transient storage. Refer to Listing 1 for a code sample.
Using a Shared (Static) Member
Using a Shared member variable is by no means specific to serviced components, of course. It's a simple and efficient mechanism. Its main problem is that you have only one single instance that is shared by all users and their components, which can lead to concurrency conflicts when the value isn't read-only. Because of this, you have to protect the value by writing thread-safe code. This will result in wait states in a highly stressed environment when the Shared member is to be used all the time. Most often, it won't cause you any problems, but in some situationsas I said, under extreme loadit might be a show-stopper.
To get a cheaper locking solution, you can implement a ReaderWriter lock instead. That means that there might be several readers at the same time, but only one writer. Do you get a de[as]ja[ag] vu feeling from the database area? You can find more information about how to implement a ReaderWriter lock in the .NET online help.
I must warn you against trying to write thread-safe code manually. If you do so, you might create a debugging nightmare for yourself, either now or in the future. Be careful and make sure you know what you're doing.
Using the ThreadStatic Attribute
It's possible to use TLS in .NET, too, so that each thread will have its own local data. It's easily achievable by just marking a Shared variable with the ThreadStatic attribute.
This will mean that you will have as many instances of the data as you have threads. There will be no blocking because each thread will have the data it needs. This might also mean a problem for you because you waste memory, but that is most often not the case for configuration data.
Using Object Pooling (OP)
The final technique that I'd like to discuss for providing an access mechanism to transient storage is using Object Pooling (OP) in serviced components. If you still remember the technique of thread-specific global variables from the days of VB6 (which I discussed earlier in this section about configuration data), OP is another technique that comes close to that solution. Not that pooled objects are tied to a specific thread, but you will have a pool of n number of objects with OP so that you can avoid the situation of several simultaneous requests of the same value leading to wait states. On the other hand, the larger the pool, the larger the amount of used memory, of course.
However, while it is an advantage that several instances minimize contention, it's a disadvantage if it's necessary for all instances to have the same values all the time. If it is necessary, you'd better use one single value instead (unless it's not a "fetch once, use many times" type of data).
Both Object Construction and Object Pooling can be used even when the object is located in the context of the caller because neither of these services is built with interception.