Promethix.Framework.Ado
1.1.1
dotnet add package Promethix.Framework.Ado --version 1.1.1
NuGet\Install-Package Promethix.Framework.Ado -Version 1.1.1
<PackageReference Include="Promethix.Framework.Ado" Version="1.1.1" />
<PackageVersion Include="Promethix.Framework.Ado" Version="1.1.1" />
<PackageReference Include="Promethix.Framework.Ado" />
paket add Promethix.Framework.Ado --version 1.1.1
#r "nuget: Promethix.Framework.Ado, 1.1.1"
#addin nuget:?package=Promethix.Framework.Ado&version=1.1.1
#tool nuget:?package=Promethix.Framework.Ado&version=1.1.1
AdoScope
π What is AdoScope?
AdoScope is a lightweight and flexible library for Dapper and ADO.NET that manages DbConnection and DbTransaction lifecycles, while providing clean, scoped transactions through an ambient context pattern.
It provides a minimal-effort Unit of Work pattern, inspired by DbContextScope for Entity Framework β but tailored for Dapper and raw ADO.NET.
It has been used in enterprise-scale applications and production systems, giving it a thorough shake-down in complex, high-volume scenarios.
No need to manually manage transactions, connection lifetimes, or implement repetitive unit of work classes. AdoScope wraps all of this with clean Dependency Injection (DI) support and allows:
- Transparent ambient scoping (no passing around context)
- Cross-database transaction coordination
- Distributed transactions (via MSDTC on supported platforms)
- Fine-grained control per scope or per context
β¨ Features
- β Lightweight ambient scope for ADO.NET
- β Provider-agnostic (works with MSSQL, SQLite, PostgreSQL, etc.)
- β Minimal effort Unit of Work via scoped transactions
- β Nested scope support
- β Support for multiple databases in the same transaction
- β Distributed transaction support across databases
- β Asynchronous-safe usage
- β Configurable per context and per scope (transactional / non-transactional)
- β Isolation level configuration per context or scope
π¦ Installation
Install-Package Promethix.Framework.Ado
π§ Configuration (Dependency Injection)
.NET with SQLite (Appsettings Example)
DbProviderFactories.RegisterFactory("Microsoft.Data.Sqlite", SqliteFactory.Instance);
services.AddSingleton<IAmbientAdoContextLocator, AmbientAdoContextLocator>();
services.AddSingleton<IAdoScopeFactory, AdoScopeFactory>();
services.AddSingleton<IAdoContextGroupFactory, AdoContextGroupFactory>();
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var adoScopeConfig = new AdoScopeConfigurationBuilder()
.ConfigureScope(options => options.WithScopeConfiguration(configuration))
.Build();
var adoContextConfig = new AdoContextConfigurationBuilder()
.AddAdoContext<SqliteDbContext>(options =>
options.WithNamedContext("SqliteDbContext", configuration))
.Build();
services.AddScoped(_ => adoScopeConfig);
services.AddScoped(_ => adoContextConfig);
.NET with MSSQL (Appsettings Example)
DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", SqlClientFactory.Instance);
services.AddSingleton<IAmbientAdoContextLocator, AmbientAdoContextLocator>();
services.AddSingleton<IAdoScopeFactory, AdoScopeFactory>();
services.AddSingleton<IAdoContextGroupFactory, AdoContextGroupFactory>();
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var adoScopeConfig = new AdoScopeConfigurationBuilder()
.ConfigureScope(options => options.WithScopeConfiguration(configuration))
.Build();
var adoContextConfig = new AdoContextConfigurationBuilder()
.AddAdoContext<MyDbContext>(options =>
options.WithNamedContext("MyDbContext", configuration))
.Build();
services.AddScoped(_ => adoScopeConfig);
services.AddScoped(_ => adoContextConfig);
appsettings.json Example
{
"AdoScopeOptions": {
"ScopeExecutionOption": "Standard"
},
"AdoContextOptions": {
"SqliteDbContext": {
"ProviderName": "Microsoft.Data.Sqlite",
"ConnectionString": "Data Source=mydatabase.db",
"ExecutionOption": "Transactional"
},
"MyDbContext": {
"ProviderName": "Microsoft.Data.SqlClient",
"ConnectionString": "Server=localhost;Database=MyDb;Trusted_Connection=True;",
"ExecutionOption": "Transactional"
}
}
}
.NET Framework Example (Ninject + Fluent Configuration)
// Register AdoScope services
kernel.Bind<IAmbientAdoContextLocator>().To<AmbientAdoContextLocator>().InSingletonScope();
kernel.Bind<IAdoScopeFactory>().To<AdoScopeFactory>().InSingletonScope();
kernel.Bind<IAdoContextGroupFactory>().To<AdoContextGroupFactory>().InSingletonScope();
// Register the ADO.NET provider for MSSQL
DbProviderFactory sqlFactory = DbProviderFactories.GetFactory("Microsoft.Data.SqlClient");
kernel.Bind<DbProviderFactory>().ToConstant(sqlFactory);
// Configure AdoScope globally (application-wide scope behavior)
var adoScopeConfig = new AdoScopeConfigurationBuilder()
.ConfigureScope(options =>
{
options.WithScopeExecutionOption(AdoContextGroupExecutionOption.Standard);
})
.Build();
// Configure multiple AdoContexts using fluent API
var adoContextConfig = new AdoContextConfigurationBuilder()
.AddAdoContext<PrimaryDbContext>(options =>
{
options.WithNamedContext("PrimaryDbContext")
.WithConnectionString(ConfigurationManager.ConnectionStrings["PrimaryDb"].ConnectionString)
.WithProviderName("Microsoft.Data.SqlClient")
.WithExecutionOption(AdoContextExecutionOption.Transactional)
.WithDefaultIsolationLevel(IsolationLevel.ReadCommitted);
})
.AddAdoContext<AuditDbContext>(options =>
{
options.WithNamedContext("AuditDbContext")
.WithConnectionString(ConfigurationManager.ConnectionStrings["AuditDb"].ConnectionString)
.WithProviderName("Microsoft.Data.SqlClient")
.WithExecutionOption(AdoContextExecutionOption.Transactional)
.WithDefaultIsolationLevel(IsolationLevel.ReadCommitted);
})
.Build();
// Register configurations into DI container
kernel.Bind<AdoScopeOptionsBuilder>().ToConstant(adoScopeConfig).InRequestScope();
kernel.Bind<IAdoContextOptionsRegistry>().ToConstant(adoContextConfig).InRequestScope();
π§ͺ Usage
1. Define Your Context
public class MyDbContext : AdoContext { }
public class SqliteDbContext : AdoContext { }
2. Create a Repository
public class MyRepository : IMyRepository
{
private readonly IAmbientAdoContextLocator locator;
public MyRepository(IAmbientAdoContextLocator locator)
{
this.locator = locator;
}
private IDbConnection Connection => locator.GetContext<MyDbContext>().Connection;
private IDbTransaction Transaction => locator.GetContext<MyDbContext>().Transaction;
public int UpdateSomething(string code)
{
const string sql = "UPDATE MyTable SET Processed = 1 WHERE Code = @Code";
return Connection.Execute(sql, new { Code = code }, Transaction);
}
}
3. Use AdoScope in a Service
public class MyService(IAdoScopeFactory adoScopeFactory, IMyRepository repository) : IMyService
{
public int ProcessItem(string code)
{
using IAdoScope adoScope = adoScopeFactory.Create();
int affected = repository.UpdateSomething(code);
adoScope.Complete();
return affected;
}
}
4. Unit of Work Style Usage with Multiple Repositories
using IAdoScope scope = adoScopeFactory.Create();
repository1.DoSomething();
repository2.DoSomethingElse();
repository3.BulkInsert(records);
repository4.MarkAsProcessed(ids);
scope.Complete();
β οΈ Notes and Gotchas
- β
You must call
.Complete()
to commit a transactional scope. If not called, the transaction will automatically roll back on dispose. - β
If you forget to declare an ambient scope (i.e. no
adoScopeFactory.Create()
), an explicit and helpful exception will be thrown. - β
CreateWithTransaction()
andCreateWithDistributedTransaction()
allow full per-scope control of transaction behavior. - β
When using Distributed Transactions, ensure:
- .NET 7+ is used
- Windows OS with MSDTC service is enabled and running
- ADO.NET provider supports distributed transactions
π Release Notes
Stable Releases
- Support for nested scopes, async operations, multiple DBs, and distributed transactions
- Latest release supports .NET 8
π£οΈ Roadmap / Future Features
- Support for read-only transactions
- Improved exception messages for missing ambient scopes
β€οΈ Credits
Inspired by Mehdime El Gueddariβs DbContextScope project.
π Contributing
Pull requests and suggestions welcome! Feel free to open an issue for bugs, ideas, or questions.
π License
MIT
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. |
.NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- Microsoft.Data.SqlClient (>= 5.2.2)
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- System.Collections.Immutable (>= 9.0.0)
-
net8.0
- Microsoft.Data.SqlClient (>= 5.2.2)
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- System.Collections.Immutable (>= 9.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.1.1 | 147 | 4/7/2025 |
1.1.0 | 144 | 12/3/2024 |
1.1.0-alpha | 79 | 12/2/2024 |
1.0.0 | 145 | 5/2/2024 |
1.0.0-rc4 | 224 | 1/17/2024 |
1.0.0-rc3 | 123 | 1/15/2024 |
1.0.0-rc2 | 193 | 11/19/2023 |
1.0.0-rc1 | 125 | 11/9/2023 |
0.1.42-alpha | 130 | 11/6/2023 |
0.1.39-alpha | 123 | 10/17/2023 |
0.1.32-alpha | 129 | 10/14/2023 |
0.1.30-alpha | 115 | 9/30/2023 |
0.1.29-alpha | 119 | 9/28/2023 |
0.1.28-alpha | 111 | 9/28/2023 |
0.1.24-alpha | 117 | 9/25/2023 |
0.1.20-alpha | 116 | 9/24/2023 |
0.1.7-alpha | 116 | 9/23/2023 |
Support added for implicit/explicit distributed transactions and ambient supression for async workloads.