/// <summary> /// Attempts to acquire the lock synchronously. Usage: /// <code> /// using (var handle = myLock.TryAcquire(...)) /// { /// if (handle != null) { /* we have the lock! */ } /// } /// // dispose releases the lock if we took it /// </code> /// </summary> /// <param name="lock"></param> /// <param name="timeout">How long to wait before giving up on acquiring the lock. Defaults to 0</param> /// <returns>An <see cref="IDisposable"/> "handle" which can be used to release the lock, or null if the lock was not taken</returns> public LockAcquisitionResult TryAcquire(string @lock, TimeSpan timeout = default(TimeSpan)) { // synchronous mode var timeoutMillis = timeout.ToInt32Timeout(); // calculate safe lock name var lockName = ToSafeLockName(@lock, MaxLockNameLength, s => s); DbConnection acquireConnection = null; var cleanup = true; try { acquireConnection = GetConnection(); if (_connectionString != null) { acquireConnection.Open(); } else if (acquireConnection == null) { throw new InvalidOperationException("The transaction had been disposed"); } else if (acquireConnection.State != ConnectionState.Open) { throw new InvalidOperationException("The connection is not open"); } var checkCommand = SqlHelpers.CreateCheckLockAvailabilityCommand(acquireConnection, timeoutMillis, lockName); var exists = (int)checkCommand.ExecuteScalar() > 0; if (exists) { return(LockAcquisitionResult.Fail); } var id = Guid.NewGuid(); SqlParameter insertReturnValue; using (var insertCommand = SqlHelpers.CreateInsertApplicationLockCommand(acquireConnection, id, timeoutMillis, lockName, Utc, out insertReturnValue)) { insertCommand.ExecuteNonQuery(); } var ret = (int)insertReturnValue.Value; cleanup = ret == 0; var success = ret == 0; var owner = string.Empty; if (success) { // hash owner owner = _encryptor.Encrypt(id.ToString()); // check no duplicates. var checkDuplicateCommand = SqlHelpers.CreateCheckLockAvailabilityCommand(acquireConnection, timeoutMillis, lockName); var duplicatesExist = (int)checkDuplicateCommand.ExecuteScalar() > 1; if (duplicatesExist) { // delete current lock ReleaseLock(lockName, owner); return(LockAcquisitionResult.Fail); } } return(new LockAcquisitionResult { Success = success, LockOwner = owner }); } catch { // in case we fail to create lock scope or something cleanup = true; throw; } finally { if (cleanup) { Cleanup(acquireConnection); } } }