DotNetAsyncSafe 1.0.0
dotnet add package DotNetAsyncSafe --version 1.0.0
NuGet\Install-Package DotNetAsyncSafe -Version 1.0.0
<PackageReference Include="DotNetAsyncSafe" Version="1.0.0" />
<PackageVersion Include="DotNetAsyncSafe" Version="1.0.0" />
<PackageReference Include="DotNetAsyncSafe" />
paket add DotNetAsyncSafe --version 1.0.0
#r "nuget: DotNetAsyncSafe, 1.0.0"
#:package DotNetAsyncSafe@1.0.0
#addin nuget:?package=DotNetAsyncSafe&version=1.0.0
#tool nuget:?package=DotNetAsyncSafe&version=1.0.0
DotNetAsyncSafe
Prevents async/await deadlocks, handles fire-and-forget tasks safely, and manages concurrency issues in .NET applications.
Problems Solved
- Deadlocks in ASP.NET:
async/awaitdeadlocks when mixing sync and async code - Thread freezing: Using
.Resultor.Wait()blocks threads and causes deadlocks - Silent failures: Fire-and-forget tasks fail without logging or handling
- Missing ConfigureAwait: Confusion about when to use
ConfigureAwait(false) - Cancellation not flowing:
CancellationTokennot properly propagated through async chains - Background tasks killed: Background tasks terminated during application shutdown
- No timeout handling: Tasks run indefinitely without timeout protection
- Thread pool starvation: Too many concurrent async operations exhaust thread pool
- Parallel.ForEach misuse: Using
Parallel.ForEachwith async operations incorrectly - Race conditions: Shared state accessed without proper synchronization
- Lost exceptions: Exceptions in
async voidmethods are lost - Incorrect async locks: Using
lock()statements in async code causes deadlocks - SemaphoreSlim misuse: Improper use of
SemaphoreSlimin async contexts - CPU-bound on async threads: Running CPU-intensive work on async threads blocks I/O
- Sync/async mixing: Mixing synchronous and asynchronous APIs incorrectly
Installation
dotnet add package DotNetAsyncSafe
Quick Start
1. Safe Fire-and-Forget Tasks
Problem: Fire-and-forget tasks fail silently, making debugging impossible.
using DotNetAsyncSafe;
// ❌ BAD: Exceptions are lost
Task.Run(async () => await ProcessDataAsync());
// ✅ GOOD: Exceptions are logged
TaskHelper.FireAndForget(
async () => await ProcessDataAsync(),
logger,
"ProcessData"
);
2. Prevent Deadlocks with Safe Synchronous Waits
Problem: Using .Result or .Wait() causes deadlocks in ASP.NET.
// ❌ BAD: Causes deadlock
var result = SomeAsyncMethod().Result;
// ✅ GOOD: Safe synchronous execution
var result = TaskHelper.RunSync(() => SomeAsyncMethod());
3. Task Timeouts
Problem: Tasks run indefinitely, blocking resources.
// ❌ BAD: No timeout protection
await LongRunningOperationAsync();
// ✅ GOOD: Automatic timeout with exception
try
{
var result = await TaskHelper.WithTimeoutAsync(
LongRunningOperationAsync(),
TimeSpan.FromSeconds(30)
);
}
catch (TimeoutException ex)
{
logger.LogError(ex, "Operation timed out");
}
4. Async Lock for Critical Sections
Problem: Using lock() in async code causes deadlocks.
// ❌ BAD: lock() doesn't work with async
lock (_lockObject)
{
await UpdateSharedResourceAsync();
}
// ✅ GOOD: Async-compatible lock
var asyncLock = new AsyncLock();
using (await asyncLock.LockAsync())
{
await UpdateSharedResourceAsync();
}
5. Background Tasks That Survive Shutdown
Problem: Background tasks are killed during application shutdown.
// ✅ GOOD: Register background task that survives shutdown
services.AddBackgroundTask<MyBackgroundService>();
public class MyBackgroundService : IBackgroundTask
{
public async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await ProcessQueueAsync();
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
// Cleanup logic
return Task.CompletedTask;
}
}
6. Prevent Thread Pool Starvation
Problem: Too many concurrent async operations exhaust the thread pool.
// ❌ BAD: All operations run concurrently
var tasks = items.Select(item => ProcessItemAsync(item));
await Task.WhenAll(tasks);
// ✅ GOOD: Limit concurrency to prevent starvation
await ParallelAsyncHelper.ForEachAsync(
items,
maxConcurrency: 10, // Process max 10 at a time
async (item, ct) => await ProcessItemAsync(item)
);
7. CPU-Bound Work on Background Threads
Problem: CPU-intensive work blocks async threads, preventing I/O operations.
// ❌ BAD: Blocks async thread
var result = await Task.Run(() => ExpensiveCalculation());
// ✅ GOOD: Explicitly run on background thread
var result = await ParallelAsyncHelper.RunCpuBoundAsync(
() => ExpensiveCalculation()
);
8. Cancellation Token Helpers
Problem: Cancellation tokens not properly linked or validated.
// ✅ GOOD: Create linked cancellation tokens
var cts = CancellationTokenHelper.CreateLinkedToken(
httpContext.RequestAborted,
timeoutCts.Token
);
await ProcessRequestAsync(cts.Token);
Real-World Example
public class OrderProcessor
{
private readonly AsyncLock _lock = new();
private readonly ILogger<OrderProcessor> _logger;
public async Task ProcessOrdersAsync(IEnumerable<Order> orders)
{
// Process orders with concurrency limit
await ParallelAsyncHelper.ForEachAsync(
orders,
maxConcurrency: 5,
async (order, ct) =>
{
// Use async lock for critical section
using (await _lock.LockAsync(ct))
{
await ValidateOrderAsync(order, ct);
await SaveOrderAsync(order, ct);
}
}
);
}
public void ProcessOrderInBackground(Order order)
{
// Fire-and-forget with proper error handling
TaskHelper.FireAndForget(
async () => await SendNotificationAsync(order),
_logger,
$"SendNotification-{order.Id}"
);
}
}
Best Practices
- Always use
TaskHelper.RunSync()instead of.Resultor.Wait() - Use
AsyncLockinstead oflock()in async code - Limit concurrency with
ParallelAsyncHelper.ForEachAsync()to prevent thread pool starvation - Always log fire-and-forget tasks using
TaskHelper.FireAndForget() - Set timeouts on long-running operations using
TaskHelper.WithTimeoutAsync() - Use background task host for tasks that must survive shutdown
API Reference
TaskHelper.FireAndForget()- Safely execute fire-and-forget tasksTaskHelper.RunSync()- Safely run async code synchronouslyTaskHelper.WithTimeoutAsync()- Add timeout to async operationsAsyncLock- Async-compatible lock for critical sectionsParallelAsyncHelper.ForEachAsync()- Parallel processing with concurrency limitsCancellationTokenHelper- Utilities for cancellation token managementBackgroundTaskHost- Host for background tasks that survive shutdown
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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. |
-
net8.0
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
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.0 | 109 | 12/29/2025 |
Initial release. Provides async/concurrency safety helpers to prevent deadlocks, handle fire-and-forget tasks, manage cancellation tokens, and provide safe async patterns.