MDLSoft.DistributedLock 1.0.3

dotnet add package MDLSoft.DistributedLock --version 1.0.3
                    
NuGet\Install-Package MDLSoft.DistributedLock -Version 1.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MDLSoft.DistributedLock" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MDLSoft.DistributedLock" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="MDLSoft.DistributedLock" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MDLSoft.DistributedLock --version 1.0.3
                    
#r "nuget: MDLSoft.DistributedLock, 1.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MDLSoft.DistributedLock@1.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MDLSoft.DistributedLock&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=MDLSoft.DistributedLock&version=1.0.3
                    
Install as a Cake Tool

MDLSoft.DistributedLock

A high-performance, lightweight distributed lock library for SQL Server with zero external dependencies.

Features

  • 🔒 Distributed Locking: Acquire and release locks across multiple processes/applications
  • 🗄️ SQL Server Backend: Uses SQL Server as the lock storage mechanism
  • Zero Dependencies: Built with raw ADO.NET for maximum performance and minimal footprint
  • 🔄 Sync & Async: Full support for both synchronous and asynchronous operations
  • 🎯 Universal Compatibility: Single package supports .NET Framework 4.0 through .NET 8+
  • 🚀 High Performance: Optimized lock acquisition with READ COMMITTED isolation
  • 🔧 Simple API: Clean, intuitive interface with manual lock release
  • 📦 Lightweight: Only 49KB package size

Installation

Install the package via NuGet:

# Single package for ALL .NET versions (4.0 through 8+)
dotnet add package MDLSoft.DistributedLock

Or via Package Manager Console:

# Works with any .NET version
Install-Package MDLSoft.DistributedLock

Quick Start

1. Setup the Database Table

var connectionString = "Server=.;Database=MyApp;Integrated Security=true;";
var provider = new SqlServerDistributedLockProvider(connectionString);

// Ensure the locks table exists
await provider.EnsureTableExistsAsync();

2. Basic Usage

// Synchronous usage
using (var lockProvider = new SqlServerDistributedLockProvider(connectionString))
{
    using (var distributedLock = lockProvider.TryAcquireLock("my-resource"))
    {
        if (distributedLock != null)
        {
            // Critical section - only one process can execute this
            Console.WriteLine("Lock acquired successfully!");
            // Do your work here...
        }
        else
        {
            Console.WriteLine("Could not acquire lock");
        }
    } // Lock is automatically released here
}

// Asynchronous usage
using (var lockProvider = new SqlServerDistributedLockProvider(connectionString))
{
    using (var distributedLock = await lockProvider.TryAcquireLockAsync("my-resource"))
    {
        if (distributedLock != null)
        {
            // Critical section
            await DoImportantWorkAsync();
        }
    }
}

3. Advanced Usage

var lockProvider = new SqlServerDistributedLockProvider(connectionString);

try
{
    // Acquire lock with timeout
    using (var distributedLock = await lockProvider.AcquireLockAsync(
        lockId: "critical-operation", 
        timeout: TimeSpan.FromSeconds(30)))
    {
        // Your critical work here
        await ProcessLongRunningOperationAsync();
        
        // Manual release (optional - automatic on dispose)
        await distributedLock.ReleaseAsync();
    }
}
catch (DistributedLockTimeoutException ex)
{
    Console.WriteLine($"Could not acquire lock '{ex.LockId}' within the specified timeout");
}

Examples

Complete Example Applications

This repository includes comprehensive example applications demonstrating various usage patterns:

1. Modern .NET Example (MDLSoft.DistributedLock.Example)
  • Target: .NET 8 (modern applications)
  • Features: Async/await, cancellation tokens, modern C# patterns
  • Use Case: Web applications, services, modern desktop apps
2. .NET Framework 4.0 Example (MDLSoft.DistributedLock.Example.Net40)
  • Target: .NET Framework 4.0 (legacy compatibility)
  • Features: Synchronous operations, classic .NET patterns, Thread-based concurrency
  • Use Case: Legacy applications, Windows services, older codebases

What the examples demonstrate:

  • ✅ Basic lock acquisition and release patterns
  • ✅ Lock timeout handling and conflict resolution
  • ✅ Concurrent access simulation (multiple threads/processes)
  • ✅ Proper error handling and exception management
  • ✅ IDisposable pattern for automatic cleanup
  • ✅ Configuration management (app.config/appsettings.json)
  • ✅ Database table initialization
  • ✅ Thread safety and synchronization patterns

Running the examples:

# Modern .NET example
cd MDLSoft.DistributedLock.Example
dotnet run

# .NET Framework 4.0 example (requires Visual Studio or MSBuild)
cd MDLSoft.DistributedLock.Example.Net40
# Build with Visual Studio or MSBuild, then run the .exe

API Reference

IDistributedLockProvider

The main interface for acquiring distributed locks.

Methods
  • TryAcquireLock(string lockId, TimeSpan? timeout = null) - Attempts to acquire a lock synchronously
  • TryAcquireLockAsync(string lockId, TimeSpan? timeout = null, CancellationToken cancellationToken = default) - Attempts to acquire a lock asynchronously
  • AcquireLock(string lockId, TimeSpan? timeout = null) - Acquires a lock synchronously (throws on failure)
  • AcquireLockAsync(string lockId, TimeSpan? timeout = null, CancellationToken cancellationToken = default) - Acquires a lock asynchronously (throws on failure)

IDistributedLock

Represents an acquired distributed lock.

Properties
  • string LockId - The unique identifier for the lock
  • bool IsAcquired - Whether the lock is currently acquired
Methods
  • Release() - Releases the lock synchronously
  • ReleaseAsync(CancellationToken cancellationToken = default) - Releases the lock asynchronously

SqlServerDistributedLockProvider

SQL Server implementation of the distributed lock provider.

Constructor
public SqlServerDistributedLockProvider(string connectionString, string tableName = "DistributedLocks")
Additional Methods
  • EnsureTableExists() - Creates the locks table if it doesn't exist (sync)
  • EnsureTableExistsAsync(CancellationToken cancellationToken = default) - Creates the locks table if it doesn't exist (async)

Database Schema

The library automatically creates the following table structure:

CREATE TABLE [DistributedLocks] (
    [LockId] NVARCHAR(255) NOT NULL PRIMARY KEY,
    [LockToken] NVARCHAR(255) NOT NULL,
    [CreatedAt] DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);

Configuration

Connection Strings

The library supports:

  • System.Data.SqlClient (for .NET Framework 4.0-4.8)
  • Microsoft.Data.SqlClient (for .NET Standard 2.0/.NET Core/.NET 5+)

Custom Table Name

You can specify a custom table name for the locks:

var provider = new SqlServerDistributedLockProvider(connectionString, "MyCustomLocksTable");

Error Handling

The library includes specific exception types:

  • DistributedLockException - Base exception for all lock operations
  • DistributedLockTimeoutException - Thrown when a lock cannot be acquired within the timeout period
  • DistributedLockOperationException - Thrown when a lock operation fails

Best Practices

  1. Always use using statements to ensure locks are properly released
  2. Use timeouts when acquiring locks to avoid indefinite waiting
  3. Handle timeout exceptions gracefully in your application
  4. Monitor lock duration - Keep critical sections as short as possible
  5. Use meaningful lock IDs that clearly identify the resource being protected

Performance Considerations

  • Lightweight: Zero external dependencies (except minimal framework backports)
  • Fast: Raw ADO.NET operations with optimized SQL
  • Efficient: Lock acquisition uses READ COMMITTED isolation with primary key constraints
  • Scalable: Consider the database load when using many concurrent locks

Thread Safety

The library is thread-safe and can be used from multiple threads simultaneously. Each lock acquisition creates a unique lock token to prevent conflicts.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

If you encounter any issues or have questions, please open an issue on GitHub.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net40 is compatible.  net403 was computed.  net45 was computed.  net451 is compatible.  net452 was computed.  net46 was computed.  net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.3 78 10/12/2025
1.0.2 71 10/12/2025
1.0.1 71 10/12/2025