Each request in my web app can get one data access object instance (of type UnitofWork), via MVC3’s own dependency injection mechanism. So far so good.
I am creating an Idisposable UnitofWorkScope object to aggregate some store calls on this data access object, and to then call them together. Actually the UnitofWorkScope only controls the UnitofWork object, which has the facility for adding stores to a list and calling them later. I believe that the UnitofWorkScope object should have exclusive access the data access object.
Now the question: I am wondering anyone has any objections to an exclusive lock being obtained in the constructor, using Monitor.Enter(), and then released in the dispose method, using Monitor.Exit();
I have muddied the waters a buit by describing why I am asking this, but feel free to comment on anything that I have put here.
public class UnitofWorkScope : IDisposable
{
public UnitofWorkScope(UnitOfWork UnitofWork)
{
if (UnitofWork == null)
{
throw new ArgumentException("UnitofWork argument null");
}
this._unitofWork = UnitofWork;
Monitor.Enter(_unitofWork); // obtaining exclusive access to the DAO of this request
this._unitofWork.AggregateDbChanges = true; //switched back off in dispose method
}
private readonly UnitOfWork _unitofWork;
bool _disposed;
public void Dispose(bool disposing)
{
if (!_disposed)
{
_unitofWork.CallFuncList();
Monitor.Exit(_unitofWork); //releasing the lock
_disposed = true;
GC.SuppressFinalize(this);
}
}
public void Dispose()
{
Dispose(true);
}
~UnitofWorkScope()
{
if (!_disposed)
{
Dispose(false);
}
}
}
The idea is to use this UnitofWorkScope in like this:
UnitofWork _unitofWork = Resolver.GetService<UnitofWork>(); //gets the UnitofWork DAO
using (UnitofWorkScope UnitofWorkScope = new UnitofWorkScope(_unitOfWork))
{
// do a store
_unitofWork.Store<SomeClass>(_someInstance);
// do some more stores
try
{
UnitofWorkScope.Dispose(true);
}
catch (exception ex)
{
//try to undo those stores.
}
}
Yes, this is not a bad pattern for implementing locks. However: I would recommend a slightly different version of Dispose to guarantee the lock is released even if
_unitofWork.CallFuncList()throws an exception, which you are relying on to detect the need to perform some kind of rollback.However, you may want to separate out the “commit” from the lock “release” logic so that you don’t have to explicitly call
Dispose(), which the using statement will do automatically for you.You can then use it like this: