DapprWire simplifies the integration of Dapper into Microsoft's Dependency Injection (DI) container, making database connectivity effortless and efficient. It provides an abstraction layer for connection and transaction management, that can be easily injected into your services or repositories, while exposing all Dapper operations so you can use it as your micro-ORM the same way you use Dapper.
If you're tired of manually wiring IDbConnection
into Microsoft DI, reminding yourself to pass IDbTransaction
as an argument, or simply have some logs to help analyzing production problems, DapprWire provides a clean and simple solution for that.
Package | NuGet | Downloads |
---|---|---|
DapprWire.Contracts | ||
DapprWire | ||
DapprWire.MicrosoftExtensions |
Package Purposes:
- DapprWire.Contracts - library that only contains contracts like
IDatabase
,IDatabaseSession
,IDatabaseTransaction
orSqlOptions
, usefull if you want to decouple from implementation details; - DapprWire - library with core implementations like
Database
,DatabaseSession
orDatabaseTransaction
; - DapprWire.MicrosoftExtensions - extension library for
Microsoft.Extension.*
packages that helps with container registration or logging SQL statements intoILogger
instances;
All packages directly target the following frameworks:
- .NET Framework 4.6.1;
- .NET Standard 2.0;
- .NET Standard 2.1;
- .NET 5.0
This means you should be able to use it almost everywhere that needs to access a SQL database, from an ASP.NET Core 8 application to a Windows Service, command line terminal and even on older ASP.NET Core 2 applications.
By managing database connections and transactions for you, DapprWire simplifies how you use Dapper. Here are some of the top features that you can read in more detail on the Wiki documentation:
If your application uses Microsoft.Extensions.DependencyInjection
, simply install the DapprWire.MicrosoftExtensions
package:
dotnet add package DapprWire.MicrosoftExtensions
Then use the extension method AddDatabase
to register the required services into the container - you only need to provide a function that creates the DbConnection
using any database driver you may prefer:
var connectionString = builder.Configuration.GetConnectionString("ProductsDatabase");
builder.Services.AddDatabase(_ => new Microsoft.Data.SqlClient.SqlConnection(connectionString));
Instead of using DbConnection
directly, you can now inject instances of IDatabaseSession
, which offer the same methods as Dapper but behave like a unit of work, with a scoped lifetime.
If you need to manage directly the lifetime of a IDatabaseSession
, you can instead inject the IDatabase
singleton and create as many database sessions as you need.
[Route("products")]
public class ProductsController(IDatabaseSession databaseSession) : ControllerBase
{
[HttpGet]
public async Task<IEnumerable<ProductModel> GetAllAsync(CancellationToken ct)
{
return await databaseSession.QueryAsync<ProductModel>(
"select Id, Code, Name from Products",
ct
);
}
}
If your application needs to connect to multiple databases, like a service that synchronizes data between multiple systems, you can easily define multiple IDatabaseName
, one for each database you need to connect.
public sealed class ProductsDatabase : IDatabaseName;
public sealed class ClientsDatabase : IDatabaseName;
Then use the AddDatabase<TName>
or, if you want one of the databases to be the fallback when no name is specified, AddDatabaseAsDefault<TName>
methods to register the required services, while providing a DbConnection
factory for each:
var productsDatabaseConnectionString = builder.Configuration.GetConnectionString("ProductsDatabase");
builder.Services.AddDatabaseAsDefault<ProductsDatabase>(
_ => new Microsoft.Data.SqlClient.SqlConnection(productsDatabaseConnectionString)
);
var clientsDatabaseConnectionString = builder.Configuration.GetConnectionString("ClientsDatabase");
builder.Services.AddDatabase<ClientsDatabase>(
_ => new Oracle.ManagedDataAccess.Client.OracleConnection(clientsDatabaseConnectionString)
);
You can now inject generic instances of IDatabaseSession<TName>
or IDatabase<TName>
into your services or repositories and use them like you would with a single database.
[Route("products")]
public class ProductsController(
IDatabaseSession<ProductsDatabase> productsDatabaseSession,
IDatabaseSession<ClientsDatabase> clientsDatabaseSession,
IDatabaseSession databaseSession // 'ProductsDatabase' was defined as default, so this is the same instance as 'productsDatabaseSession'
) : ControllerBase
{
// ...
}
When you need to manage database transactions, after starting a new transaction DapprWire will automatically pass it to Dapper when executing any database operation until it is disposed, preventing transactional problems:
await using var tx = await databaseSession.BeginTransactionAsync(ct);
var productId = await databaseSession.ExecuteScalarAsync<long>(
"insert into Products(Code, Name) values (@Code, @Name);select cast(SCOPE_IDENTITY() as bigint);",
new
{
Code = "12345",
Name = "Product 12345"
},
ct
);
await databaseSession.ExecuteAsync(
"insert into Events(Description) values (@Description)",
new
{
Description = $"Product {productId} was created!"
},
ct
);
await tx.CommitAsync(ct);
Keep in mind that, when using multiple databases, DapprWire only manages the transaction for each session individually so you need so solve distributed transaction problems on your own.
DapprWire has native support for logging, which means that everytime you open a new database session, transaction or execute an SQL command it will be logged, if enabled.
By default, logging is disabled except when using the DapprWire.MicrosoftExtensions
package since it will use Microsoft ILogger
faΓ§ade so you can manage logging configurations via application settings.
2025-06-09T14:40:41.3136668+00:00 [Debug] DapprWire.Database | Starting a new database session...
2025-06-09T14:40:41.3137026+00:00 [Debug] DapprWire.DatabaseSession | Creating a new database connection...
2025-06-09T14:40:41.3138825+00:00 [Debug] DapprWire.DatabaseSession | Opening the database connection...
2025-06-09T14:40:41.3139286+00:00 [Info] DapprWire.DatabaseSession | Database connection opened successfully.
2025-06-09T14:40:41.3139347+00:00 [Info] DapprWire.Database | Database session started successfully.
2025-06-09T14:40:41.3140091+00:00 [Debug] DapprWire.DatabaseSession | Starting a new database transaction [IsolationLevel:ReadCommitted]
2025-06-09T14:40:41.3157917+00:00 [Info] DapprWire.DatabaseSession | Database transaction started successfully
2025-06-09T14:40:41.3158548+00:00 [Debug] DapprWire.DatabaseSession | Executing SQL command
[HasParameters:True IsTransactional:True Timeout:<null> Type:<null>]
insert into Products(Code, Name) values (@Code, @Name);select cast(SCOPE_IDENTITY() as bigint);
2025-06-09T14:40:41.3168732+00:00 [Debug] DapprWire.DatabaseSession | Executing SQL command
[HasParameters:True IsTransactional:True Timeout:<null> Type:<null>]
insert into Events(Description) values (@Description)
2025-06-09T14:40:41.3180452+00:00 [Debug] DapprWire.DatabaseTransaction | Committing the database transaction...
2025-06-09T14:40:41.3239587+00:00 [Info] DapprWire.DatabaseTransaction | Database transaction committed successfully.
You can assign your own DatabaseLogger
and other options, like default command timeout, transaction isolation level and even a callback when a new DbConnection
is open by configuring the available DatabaseOptions
.
When using DapprWire.MicrosoftExtensions
package you can either configure just like any other IOptions
using Configure<DatabaseOptions>(...)
method or pass a configuration callback to the AddDatabase
methods:
var connectionString = builder.Configuration.GetConnectionString("ProductsDatabase");
builder.Services.AddDatabase(_ => new SqlConnection(connectionString), options =>
{
options.Logger = DatabaseLogger.Null;
options.DefaultTimeout = 5;
options.DefaultIsolationLevel = IsolationLevel.ReadCommitted;
});
You should be able to easily build this solution as long you have installed both SDKs for .NET 8.0 and .NET Framework 4.8, but more recent versions should also work.
git clone https://github.com/gravity00/DapprWire.git DapprWire
cd .\DapprWire
dotnet build
This library is focused on interacting with SQL databases and unit tests currently require a running SQL Server instance. To make the setup easier, the library Testcontainers is used so you only need Docker running on your local machine and everything should run as expected.
git clone https://github.com/gravity00/DapprWire.git DapprWire
cd .\DapprWire
dotnet test
Keep in mind the first execution may take some time because images may need to be automatically downloaded first.
If you prefer to use another database, either using Testcontainers or not, simply open the DatabaseFixture.cs file and change to your needs.