|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionMemoryMappedCache is a small project can be used to host a proactive loaded cache using a Windows Service. This cache uses Memory Mapped Files internally. Other applications on the same computer can then also use MemoryMappedCache to access information stored in this cache. This is done much quicker than using .NET Remoting. A significant amount of time was spent to ensure that this cache can be accessed from within ASP.NET if the cache is hosted by a Windows Service. BackgroundBefore I describe how, let’s explain why: people often develop a three-tiered application containing a data-layer, a business-layer and one or more interfaces in the interface-layer:
Microsoft typically recommends to develop your Business Logic Components stateless to prevent any scalability-issues. This means that every time a request comes in, an instance of the Business Logic Component is created and the request is executed. The disadvantage of this way of working is that it makes caching in the Business Layer more difficult:
A possible solution to this caching-problem is to develop a Windows Service that manages the cache. This service sits as an additional layer between the Database and the Business Logic Components. Every time the Business Logic Components need something, they could first check the cache managed by the Windows Service and, if the information is there, use it without accessing the database. So we now need a fast way of accessing information hosted by a Windows Service using a Class Library and that's a problem because that involves interprocess-communication. The .NET Framework gives you a couple of solutions if you want to have two processes on the same computer to talk to each other in .NET: Web Services and .NET Remoting. The problem with both of these technologies is that they are very slow (at least compared to in-process communication)! Some tests that I did showed that accessing a Singleton-object hosted by a Windows Service using .NET Remoting isn't much faster than accessing the database directly (MSDN). A much faster way of sharing information between two processes involves the usage of Memory Mapped Files. This is a feature provided by Windows and it can be easiest explained as an in-memory representation of a file's content that can be shared by several processes. The problem is that the .NET Framework 1.1 does not provide any native support for Memory Mapped Files. To my knowledge, this feature is not planned for the Visual Studio .NET 2005 either. Memory Mapped Files is the fastest way on Windows to share data between two processes on the same computer. So, if you want to develop a .NET solution using Memory Mapped Files you have to use native Windows API-functions using P/Invoke. But since my C++ knowledge is rusty, I wanted to develop this using VB.NET or C# only. If you search the Internet, you'll notice that you won't find too many resources or sample applications showing you how to use Memory Mapped Files from within VB.NET or C#. I found two interesting resources however:
I actually started developing MemoryMappedCache based on the Microsoft.ApplicationBlocks.MemoryMappedFile-project and the Microsoft.ApplicationBlocks.Cache-project of the Caching Application Block. I stripped and changed these projects until they finally worked the way I wanted them to work and until they didn't contain any code anymore that I was never going to use. Significant pieces of the code had to be redesigned though to work in ASP.NET as described further down. I've mentioned earlier that both of these solutions don't work if you want to access a cache created by a Windows Service from within ASP.NET. The problem is that both solutions create their Mutexes and the Memory Mapped Files using default security. More information about the meaning of default security and this problem can be found in the Mutex Madness-paragraph of Ask Dr. GUI #49: MSDN. Please read MSDN for detailed information about default security, but I'll try to give you a simple explanation here. If you create a Mutex or a Memory Mapped File using Windows API, than you have three different options when it comes to security:
For those of you who don't know what a mutex is, there's a good description in MSDN: "When two or more threads need to access a shared resource at the same time, the system needs a synchronization mechanism to ensure that only one thread at a time uses the resource. Mutex is a synchronization primitive that grants exclusive access to the shared resource to only one thread. If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex." As you may have learned so far, there are three obstacles to overcome if you want to use Memory Mapped Files in an architecture described above:
The MemoryMappedCache-project is currently designed with proactive content loading in mind. This means that the service is supposed to read all the information to be cached in memory when it starts and all the other applications (the clients so to speak) have read-only access to the cached information. If you want to, it should not be too difficult to change this project to a more reactive loading approach. Using the codeWhen you open the MemoryMappedCache-solution you'll notice that it contains 4 small projects:
Once you've been able to get the Client-application to work, you'll notice that it is very easy to develop an ASP.NET-solution that does the same thing. Here's some sample code that shows you what happens when the server starts (I've replaced the Windows Service with a Console Application to make the code more readable): Sub Main()
Dim myCache As MemoryMappedCache.Cache
myCache = New MemoryMappedCache.Cache("MyCompany.MyApplication.Cache_")
myCache.Assign("test", "value2")
myCache.Assign("test", "value2")
Console.WriteLine("Server is ready. You may start" & _
" your client now. Press enter to stop the server.")
Console.ReadLine()
myCache.Dispose()
End Sub
The first thing that happens is that an instance is made of the After the server has created an instance of the
The MemoryMappedCache-project will create a separate Memory Mapped File for every item stored in the cache. Because of this, it's better to store a few large objects than a large number of small objects in the cache. If you have a lot of small values to store in the cache, create a separate class that contains all this information and then store this single class in the cache. This will work much faster than having dozens of small items. Every time an item is retrieved from the cache, the data has to be deserialized. This is also a rather costly operation which makes it another reason why it's best to have only a few large objects. Once all the data has been loaded in the cache, the server is running. If you want to stop the server, make sure that you call the We can now start our client-application and see if we can retrieve any of the information stored in the cache using the server. The sample Client Console-application is written in C# (it could be any other .NET compliant language): static void Main(string[] args)
{
MemoryMappedCache.Cache myCache =
new MemoryMappedCache.Cache("MyCompany.MyApplication.Cache_");
Console.WriteLine(myCache.Contents("test").ToString());
myCache.Dispose();
}
You can see that the cache can be used very easily. Simply create an instance of the
I've documented all important areas in the code. Please read the documentation in the source for more information on the inner-workings. The entire MemoryMappedCache-library has only 3 classes and contains less than 700 lines of code so it should be easy to read. Points of InterestAll mutexes and Memory Mapped Files are created using a NULL DACL. Make sure to use a more secure design before using in a production environment. History
| ||||||||||||||||||||