AdoNet.Async 0.1.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package AdoNet.Async --version 0.1.3
                    
NuGet\Install-Package AdoNet.Async -Version 0.1.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="AdoNet.Async" Version="0.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="AdoNet.Async" Version="0.1.3" />
                    
Directory.Packages.props
<PackageReference Include="AdoNet.Async" />
                    
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 AdoNet.Async --version 0.1.3
                    
#r "nuget: AdoNet.Async, 0.1.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 AdoNet.Async@0.1.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=AdoNet.Async&version=0.1.3
                    
Install as a Cake Addin
#tool nuget:?package=AdoNet.Async&version=0.1.3
                    
Install as a Cake Tool

<p align="center"> <img src="assets/logo.svg" alt="AdoNet.Async" width="128" /> </p>

<h1 align="center">AdoNet.Async</h1>

<p align="center">Async-first interfaces and base classes for ADO.NET. A drop-in replacement that brings modern <code>async/await</code>, <code>IAsyncEnumerable</code>, and <code>ValueTask</code> support to <code>System.Data</code>.</p>

NuGet NuGet NuGet

Installation

# Core interfaces and abstract base classes (zero dependencies)
dotnet add package AdoNet.Async

# Async DataTable, DataSet, DataAdapter + JSON converters
dotnet add package AdoNet.Async.DataSet

# Adapter wrappers for existing ADO.NET providers + DI extensions
dotnet add package AdoNet.Async.Adapters

Quick Start

Migrate existing code with .AsAsync()

Wrap any DbConnection to get a fully async interface:

using System.Data.Async.Adapters;

DbConnection sqlConnection = new SqlConnection(connectionString);
IAsyncDbConnection connection = sqlConnection.AsAsync();

await connection.OpenAsync();
await using var transaction = await connection.BeginTransactionAsync();

IAsyncDbCommand cmd = connection.CreateCommand();
cmd.CommandText = "SELECT Id, Name FROM Users";
IAsyncDataReader reader = await cmd.ExecuteReaderAsync();

Iterate results with await foreach

IAsyncDataReader implements IAsyncEnumerable<IAsyncDataRecord>, so you can stream rows naturally:

IAsyncDataReader reader = await cmd.ExecuteReaderAsync();
await using (reader)
{
    await foreach (IAsyncDataRecord record in reader)
    {
        Console.WriteLine($"{record.GetInt32(0)}: {record.GetString(1)}");
    }
}

Fill an AsyncDataTable

Use FillAsync with the AdapterDbDataAdapter to populate tables asynchronously:

using System.Data.Async.DataSet;
using System.Data.Async.Adapters;

var table = new AsyncDataTable("Users");
var adapter = new AdapterDbDataAdapter(cmd);
int rowCount = await adapter.FillAsync(table);

foreach (DataRow row in table.Rows)
{
    Console.WriteLine(row["Name"]);
}

JSON serialization with Newtonsoft.Json

AsyncDataTable and AsyncDataSet include converters compatible with the Json.Net.DataSetConverters format:

using System.Data.Async.Converters;
using Newtonsoft.Json;

var settings = new JsonSerializerSettings();
settings.Converters.Add(new AsyncDataTableConverter());
settings.Converters.Add(new AsyncDataSetConverter());

// Serialize
string json = JsonConvert.SerializeObject(table, settings);

// Deserialize
var restored = JsonConvert.DeserializeObject<AsyncDataTable>(json, settings);

Dependency Injection

Register an async provider factory from any existing DbProviderFactory:

using System.Data.Async.Adapters;

services.AddAsyncData(SqlClientFactory.Instance);

// Then inject IAsyncDbProviderFactory anywhere:
public class MyRepository(IAsyncDbProviderFactory factory)
{
    public async Task<string> GetNameAsync(int id)
    {
        await using var conn = factory.CreateConnection();
        conn.ConnectionString = "...";
        await conn.OpenAsync();
        // ...
    }
}

Packages

Package Description Dependencies
AdoNet.Async Core async interfaces (IAsyncDbConnection, IAsyncDbCommand, IAsyncDataReader, etc.) and abstract base classes None
AdoNet.Async.DataSet AsyncDataTable, AsyncDataSet, AsyncDataAdapter + Newtonsoft.Json converters Newtonsoft.Json
AdoNet.Async.Adapters Adapter wrappers (AdapterDbConnection, etc.), .AsAsync() extension, DI registration Microsoft.Extensions.DependencyInjection.Abstractions

Validation & Benchmarks

The library includes a comprehensive validation test suite (40 tests) that proves behavioral parity with raw ADO.NET, and a benchmark suite measuring async wrapper overhead.

Running

# Run all validation tests
dotnet test tests/System.Data.Async.Validation.Tests

# Run benchmarks (Release mode required)
dotnet run --project tests/System.Data.Async.Benchmarks -c Release

Benchmark Results

Measured on Intel Core i9-12900HK, .NET 10.0.4, BenchmarkDotNet v0.15.8 (ShortRun).

Command Execution
Method Mean Ratio Allocated Alloc Ratio
Raw_ExecuteScalar 6.581 us 1.00 720 B 1.00
Async_ExecuteScalar 12.069 us 1.83 912 B 1.27
Raw_ExecuteNonQuery 9.355 us 1.42 480 B 0.67
Async_ExecuteNonQuery 16.063 us 2.44 528 B 0.73
Raw_ExecuteReader_Iterate 10.087 us 1.53 704 B 0.98
Async_ExecuteReader_Iterate 16.023 us 2.44 992 B 1.38
Connection Open/Close
Method Mean Ratio Allocated Alloc Ratio
Raw_OpenClose 15.54 us 1.00 384 B 1.00
Async_OpenClose 14.35 us 0.92 408 B 1.06
Data Reader Iteration (50 rows)
Method Mean Ratio Allocated Alloc Ratio
Raw_ReadAll_Fields 20.99 us 1.00 3.7 KB 1.00
Async_ReadAll_ManualLoop 33.13 us 1.58 3.98 KB 1.08
Async_ReadAll_AwaitForeach 30.74 us 1.46 4.09 KB 1.11
DataAdapter Fill
Method RowLimit Mean Ratio Allocated Alloc Ratio
Raw_Fill 10 595.5 us 1.00 94.42 KB 1.00
Async_Fill 10 872.3 us 1.46 78.88 KB 0.84
Raw_Fill 100 1,293.8 us 1.00 160.21 KB 1.00
Async_Fill 100 1,173.8 us 0.92 117.40 KB 0.73
Transactions
Method Mean Ratio Allocated Alloc Ratio
Raw_BeginCommit 5.948 us 1.00 1.64 KB 1.00
Async_BeginCommit 240.697 us 40.47 1.79 KB 1.09
Raw_BeginRollback 6.040 us 1.00 1.65 KB 1.00
Async_BeginRollback 233.939 us 39.33 1.73 KB 1.06

Note: Transaction overhead is high in this microbenchmark because SQLite serializes write transactions. In real-world usage with network-bound databases (SQL Server, PostgreSQL), the async overhead is negligible compared to I/O latency. Memory allocation overhead is consistently minimal (< 200 bytes per operation).

Validation Coverage

Test Class Tests What it validates
ConnectionParityTests 3 State transitions, repeated open/close, timeout
CommandExecutionParityTests 7 ExecuteScalar, ExecuteNonQuery, ExecuteReader, parameters, Prepare, CommandBehavior
ReaderParityTests 11 Field access, schema, IsDBNull, await foreach, HasRows, NextResult, GetFieldValueAsync, Close/IsClosed, Depth, typed accessors
TransactionParityTests 3 Commit, Rollback, IsolationLevel
DataAdapterParityTests 3 Fill DataTable/DataSet, Update roundtrip
SerializationParityTests 4 XML data/schema roundtrip, JSON roundtrip
EventParityTests 5 Row/Column/Table events fire in same order
EdgeCaseParityTests 4 Empty/large results, cancellation, empty fill

Design Decisions

  • ValueTask everywhere -- All async methods return ValueTask or ValueTask<T> for zero-allocation on synchronous completion paths.
  • Dual sync/async -- Every interface exposes both synchronous and asynchronous members, enabling gradual migration without breaking existing code.
  • IAsyncEnumerable<IAsyncDataRecord> -- IAsyncDataReader implements IAsyncEnumerable, enabling await foreach iteration over result sets.
  • Adapter pattern -- Existing DbConnection/DbCommand/DbDataReader instances are wrapped, not replaced. No provider-specific code needed.
  • Zero core dependencies -- The System.Data.Async package has no external dependencies; adapters and DataSet packages only reference what they need.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on AdoNet.Async:

Package Downloads
AdoNet.Async.DataSet

Async DataSet and DataTable for ADO.NET (System.Data). Includes AsyncDataTable, AsyncDataSet, AsyncDataAdapter, and Newtonsoft.Json converters.

AdoNet.Async.Adapters

Adapters wrapping existing ADO.NET providers (DbConnection, DbCommand, DbDataReader) into async interfaces. Includes .AsAsync() extension and DI support.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 0 3/27/2026
0.2.0 0 3/27/2026
0.1.5 37 3/26/2026
0.1.4 60 3/22/2026
0.1.3 57 3/22/2026
0.1.2 57 3/22/2026
0.1.1 59 3/22/2026