AdoNet.Async.DataSet 0.2.0

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

Installation

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

# Async DataTable, DataSet, DataAdapter
dotnet add package AdoNet.Async.DataSet

# Newtonsoft.Json converters (Json.Net.DataSetConverters wire format)
dotnet add package AdoNet.Async.Serialization.NewtonsoftJson

# System.Text.Json converters (same wire format)
dotnet add package AdoNet.Async.Serialization.SystemTextJson

# 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);

JSON serialization with System.Text.Json

AsyncDataTable and AsyncDataSet also work with System.Text.Json, producing the same wire format:

using System.Data.Async.Converters.SystemTextJson;
using System.Text.Json;

var options = new JsonSerializerOptions();
options.Converters.Add(new AsyncDataTableJsonConverter());
options.Converters.Add(new AsyncDataSetJsonConverter());

// Serialize
string json = JsonSerializer.Serialize(table, options);

// Deserialize
var restored = JsonSerializer.Deserialize<AsyncDataTable>(json, options);

Both serializers produce identical JSON — you can serialize with one and deserialize with the other.

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, and AsyncDataAdapter None
AdoNet.Async.Serialization.NewtonsoftJson AsyncDataTableConverter, AsyncDataSetConverter for Newtonsoft.Json. Wire-compatible with Json.Net.DataSetConverters. AdoNet.Async.DataSet, Newtonsoft.Json
AdoNet.Async.Serialization.SystemTextJson AsyncDataTableJsonConverter, AsyncDataSetJsonConverter for System.Text.Json. Same wire format. AdoNet.Async.DataSet
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, an integration test suite (35 tests) covering interop and cross-serialization compatibility, and a benchmark suite measuring async wrapper and serialization 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
Serialization (AsyncDataTable, 10 / 100 rows)
Method RowCount Mean Ratio Allocated Alloc Ratio
Newtonsoft_Serialize 10 1.00 1.00
STJ_Serialize 10
Newtonsoft_Deserialize 10
STJ_Deserialize 10
Newtonsoft_Serialize 100 1.00 1.00
STJ_Serialize 100
Newtonsoft_Deserialize 100
STJ_Deserialize 100

Run dotnet run --project tests/System.Data.Async.Benchmarks -c Release -- --filter *Serialization* to populate this table.

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
DataTableInteropTests 7 DataTableAsyncDataTable wrapping is lossless (all row states, constraints, extended properties)
DataSetInteropTests 6 DataSetAsyncDataSet wrapping is lossless (relations, constraints, row states across tables)
NewtonsoftJsonCrossCompatibilityTests 12 Wire-compatibility with Json.Net.DataSetConverters in both directions; all row states, types, AutoIncrement
SystemTextJsonCrossCompatibilityTests 10 STJ produces identical JSON as Newtonsoft; cross-deserializer round-trips; AsyncDataSet round-trip
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.

NuGet packages (3)

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

Package Downloads
AdoNet.Async.Adapters

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

AdoNet.Async.Serialization.NewtonsoftJson

Newtonsoft.Json converters for AsyncDataTable and AsyncDataSet, wire-compatible with Json.Net.DataSetConverters.

AdoNet.Async.Serialization.SystemTextJson

System.Text.Json converters for AsyncDataTable and AsyncDataSet, wire-compatible with Json.Net.DataSetConverters.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.1 0 3/28/2026
0.4.0 16 3/27/2026
0.3.2 19 3/27/2026
0.3.1 20 3/27/2026
0.3.0 33 3/27/2026
0.2.0 24 3/27/2026
0.1.5 36 3/26/2026
0.1.4 84 3/22/2026
0.1.3 79 3/22/2026
0.1.2 83 3/22/2026
0.1.1 80 3/22/2026