|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionWhat transactional repositories do we know at the moment? Here is a list: SQL Server, MSMQ, file systems, and the Registry (in Windows Vista/Windows Server 2008). Are these enough? Do they cover all possible needs of enterprises? The transactional repository implementation described below displays the basic principles required for the implementation of your own transactional repository that can easily participate in ambient and explicit transactions in .NET. The given implementation is based on the Enterprise Library Caching Application Block. You could ask, why the caching application block? Does anybody in the world need transactional cache? :) No, personally I don't. The goal of the article is to provide developers with a basic idea of how to design and implement a custom transactional repository, be it XML file or anything else. So, the idea is we can easily implement our own transactional resources which will easily fit into the transactional model introduced in .NET and WCF, in particular. What are the main benefits of such a transactional repository? The main benefits are:
BackgroundA new namespace Using the codeFirst of all, I would like to present a sample code on how to use this black box which I call the Transactional Caching Application Block. If you get an exception somewhere inside the Before we proceed, I'd like to note some restrictions of the solution presented below:
Let's get back to the implementation. First of all, your transactional resource should implement the public class TransactionalCacheManager : ICacheManager, IEnlistmentNotification
{
void IEnlistmentNotification.Commit(Enlistment enlistment)
{
foreach(var commandItem in CurrentTransactionalRepository.Values)
{
commandItem.Command.Invoke();
}
enlistment.Done();
}
void IEnlistmentNotification.InDoubt(Enlistment enlistment)
{
enlistment.Done();
}
void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
{
preparingEnlistment.Prepared();
}
void IEnlistmentNotification.Rollback(Enlistment enlistment)
{
enlistment.Done();
}
The main method in my implementation is [ThreadStatic]
private static ThreadSafeDictionary<string, CommandItem> transactionalRepository;
At the beginning of the transaction, I set it up, and at the end of the transaction, I do release memory. Therefore, this repository will exist only in the scope of a given transaction within a particular thread. Here is the code snippet which notifies the transaction manager that I would like to participate in a transaction: void Enlist(string key, Operation operation, object value, Action command)
{
if(Transaction.Current != null)
{
Debug.Assert(Transaction.Current.TransactionInformation.Status ==
TransactionStatus.Active);
//notify transaction manager that we want to participate in transaction
Transaction.Current.EnlistVolatile(this, EnlistmentOptions.None);
CurrentTransactionalRepository[key] =
new CommandItem(operation, value, command);
}
else
{
command.Invoke();
}
}
private class Synchronizer
{
private object lockObject = new object();
private bool canProceed = false;
public void Wait()
{
lock (lockObject)
{
while (!canProceed) Monitor.Wait(lockObject);
canProceed = true;
}
}
public void Set()
{
lock (lockObject)
{
canProceed = true;
Monitor.Pulse(lockObject);
}
}
}
That's all. You can find out more from the source code available for download. You are welcome for feedbacks. Looking forward to any suggestions.
|
||||||||||||||||||||||