Dot.Conductor 5.0.0

dotnet add package Dot.Conductor --version 5.0.0
                    
NuGet\Install-Package Dot.Conductor -Version 5.0.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="Dot.Conductor" Version="5.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dot.Conductor" Version="5.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Dot.Conductor" />
                    
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 Dot.Conductor --version 5.0.0
                    
#r "nuget: Dot.Conductor, 5.0.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 Dot.Conductor@5.0.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=Dot.Conductor&version=5.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Dot.Conductor&version=5.0.0
                    
Install as a Cake Tool

Dot.Conductor - Unit of Work & Repository Pattern for .NET 10

NuGet .NET License

A robust, production-ready implementation of the Unit of Work and Repository patterns for Entity Framework Core, with advanced data patterns, resilience, and caching.

✨ Features

Category Features
Core Patterns Unit of Work, Generic Repository, Multi-tenancy
Database Providers SQL Server, PostgreSQL, MySQL, SQLite
Data Patterns 🎯 Specification Pattern, 🗑️ Soft Delete, 📝 Audit Logging
Performance 💾 Caching, ⚡ Bulk Operations, 🔄 Retry Policies
Advanced 📊 Temporal Tables, 🔌 Query Interceptors, 📄 Paging

📦 Installation

dotnet add package Dot.Conductor

🚀 Quick Start

Basic Setup (SQL Server)

// Program.cs
services.AddUnitOfWorkAndRepositories<MyDbContext>(
    Configuration.GetConnectionString("DefaultConnection"),
    isDevelopment: builder.Environment.IsDevelopment()
);

Using Repository

public class UserService
{
    private readonly IUnitOfWork<MyDbContext> _unitOfWork;

    public UserService(IUnitOfWork<MyDbContext> unitOfWork) => _unitOfWork = unitOfWork;

    public async Task<User?> GetUserAsync(int id)
    {
        var repo = _unitOfWork.GetRepository<User>();
        return await repo.GetByIdAsync(id);
    }

    public async Task CreateUserAsync(User user)
    {
        var repo = _unitOfWork.GetRepository<User>();
        await repo.AddAsync(user);
        await _unitOfWork.CommitAsync();
    }
}

🗄️ Multi-Database Provider Support

// PostgreSQL
services.AddPostgreSqlUnitOfWork<MyDbContext>(
    "Host=localhost;Database=mydb;Username=user;Password=pass"
);

// MySQL
services.AddMySqlUnitOfWork<MyDbContext>(
    "Server=localhost;Database=mydb;User=user;Password=pass",
    serverVersion: new MySqlServerVersion(new Version(8, 0, 36))
);

// SQLite
services.AddSqliteUnitOfWork<MyDbContext>("Data Source=mydb.sqlite");

// Generic configuration
services.AddUnitOfWorkWithProvider<MyDbContext>(options =>
{
    options.Provider = DatabaseProvider.PostgreSql;
    options.ConnectionString = "your-connection-string";
});

🎯 Specification Pattern

Define reusable query specifications:

public class ActiveUsersSpec : Specification<User>
{
    public ActiveUsersSpec()
    {
        AddCriteria(u => u.IsActive);
        AddCriteria(u => !u.IsDeleted);
        AddInclude(u => u.Orders);
        ApplyOrderBy(u => u.LastName);
    }
}

public class UsersByAgeSpec : Specification<User>
{
    public UsersByAgeSpec(int minAge, int maxAge)
    {
        AddCriteria(u => u.Age >= minAge && u.Age <= maxAge);
        ApplyPaging(skip: 0, take: 10);
        ApplyAsNoTracking();
    }
}

// Usage
var repo = _unitOfWork.GetRepository<User>();
var activeUsers = await repo.FindAsync(new ActiveUsersSpec());
var user = await repo.FirstOrDefaultAsync(new UsersByAgeSpec(18, 30));
var count = await repo.CountAsync(new ActiveUsersSpec());

🗑️ Soft Delete

Implement soft delete for entities:

// Entity
public class Order : ISoftDeletable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsDeleted { get; set; }
    public DateTime? DeletedAt { get; set; }
    public string? DeletedBy { get; set; }
}

// Configure in DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplySoftDeleteFilters(); // Auto-filters all ISoftDeletable
}

// Usage
repo.SoftDelete(order);    // Sets IsDeleted = true
repo.Restore(order);       // Restores the entity

// Query including deleted
var allOrders = context.Orders.IncludeDeleted().ToList();

📝 Audit Logging

Automatically track who created/modified entities:

// Entity
public class Product : IAuditable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? ModifiedAt { get; set; }
    public string? CreatedBy { get; set; }
    public string? ModifiedBy { get; set; }
}

// Setup
services.AddDotConductorAuditing<MyUserContext>();

// Implement IUserContext
public class MyUserContext : IUserContext
{
    private readonly IHttpContextAccessor _httpContext;
    
    public string? GetCurrentUserId() => 
        _httpContext.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    
    public string? GetCurrentUserName() =>
        _httpContext.HttpContext?.User.Identity?.Name;
}

// Register interceptor in DbContext
services.AddDbContext<MyDbContext>((sp, options) =>
{
    options.AddInterceptors(sp.GetRequiredService<AuditSaveChangesInterceptor>());
});

⚡ Bulk Operations

High-performance bulk operations using EF Core 8+ ExecuteUpdate/ExecuteDelete:

var repo = _unitOfWork.GetRepository<Product>();

// Bulk insert
await repo.BulkInsertAsync(products);

// Bulk update - deactivate products
var updated = await repo.BulkUpdateAsync(
    p => p.Category == "Discontinued",
    setter => setter
        .SetProperty(p => p.IsActive, false)
        .SetProperty(p => p.ModifiedAt, DateTime.UtcNow)
);

// Bulk delete
var deleted = await repo.BulkDeleteAsync(p => p.ExpiryDate < DateTime.Today);

🔄 Resilience (Retry & Circuit Breaker)

Built-in resilience for transient failures:

services.AddDotConductorResilience(options =>
{
    options.EnableRetry = true;
    options.MaxRetryAttempts = 3;
    options.RetryBaseDelay = TimeSpan.FromMilliseconds(200);
    options.EnableCircuitBreaker = true;
    options.CircuitBreakerFailureThreshold = 5;
    options.CircuitBreakerDuration = TimeSpan.FromSeconds(30);
    options.Timeout = TimeSpan.FromSeconds(10);
});

// Use in your code
var pipeline = serviceProvider.GetRequiredService<ResiliencePipeline>();
var result = await pipeline.ExecuteAsync(async ct =>
{
    return await repo.GetByIdAsync(id, ct);
});

💾 Caching

Repository caching decorator:

services.AddDotConductorCaching(options =>
{
    options.DefaultExpiration = TimeSpan.FromMinutes(5);
    options.UseSlidingExpiration = true;
    options.CacheGetById = true;
});

// Use CachedRepository decorator
var cachedRepo = new CachedRepository<Product>(
    innerRepository, memoryCache, cachingOptions);

// First call hits database, subsequent calls hit cache
var product = await cachedRepo.GetByIdAsync(1);

🔌 Query Interceptors

Log and monitor queries:

// Add logging interceptor
services.AddQueryLogging(logParameters: true);

// Add slow query detection
services.AddSlowQueryDetection(slowQueryThreshold: TimeSpan.FromSeconds(1));

// Register in DbContext
services.AddDbContext<MyDbContext>((sp, options) =>
{
    options.AddInterceptors(
        sp.GetRequiredService<LoggingInterceptor>(),
        sp.GetRequiredService<PerformanceInterceptor>()
    );
});

📊 Temporal Tables (SQL Server)

Query historical data:

// Configure in DbContext
modelBuilder.Entity<Order>(entity =>
{
    entity.ToTable("Orders", b => b.IsTemporal());
});

// Query historical data
var repo = _unitOfWork.GetRepository<Order>();
var history = repo.TemporalAll().Where(o => o.Id == orderId).ToList();
var orderAtTime = repo.TemporalAsOf(DateTime.UtcNow.AddDays(-7)).FirstOrDefault(o => o.Id == orderId);

💼 Transaction Management

await _unitOfWork.BeginTransactionAsync();
try
{
    var accountRepo = _unitOfWork.GetRepository<Account>();
    // ... perform operations ...
    await _unitOfWork.CommitTransactionAsync();
}
catch
{
    await _unitOfWork.RollbackTransactionAsync();
    throw;
}

📄 Paged Results

var pagedResult = await repo.GetPagedDataAsync(
    pageNumber: 1,
    pageSize: 20,
    orderBy: p => p.CreatedAt,
    ascending: false
);

// PagedResult<T> contains:
// - Results: IEnumerable<T>
// - TotalCount: int
// - PageSize: int
// - CurrentPage: int
// - TotalPages: int (computed)

📚 API Reference

IRepository<TEntity>

Method Description
GetAll(asNoTracking) Get all entities
GetByIdAsync(id) Get by ID (int or Guid)
FindAsync(predicate) Find matching entities
FindAsync(specification) Find using specification
FirstOrDefaultAsync(...) Get first match
CountAsync(...) Count entities
AnyAsync(...) Check existence
AddAsync(entity) Add entity
Update(entity) Update entity
Delete(entity) Delete entity
BulkInsertAsync(...) Bulk insert
BulkUpdateAsync(...) Bulk update
BulkDeleteAsync(...) Bulk delete
SoftDelete(entity) Soft delete
Restore(entity) Restore soft-deleted

IUnitOfWork<TContext>

Method Description
GetRepository<T>() Get repository instance
CommitAsync() Save all changes
BeginTransactionAsync() Start transaction
CommitTransactionAsync() Commit transaction
RollbackTransactionAsync() Rollback transaction
ExecuteSqlRawAsync(sql) Execute raw SQL

🔄 Migration from v5.0 to v5.1

New Features

  • Specification Pattern (ISpecification<T>, Specification<T>)
  • Soft Delete (ISoftDeletable, SoftDeleteExtensions)
  • Audit Logging (IAuditable, AuditSaveChangesInterceptor)
  • Bulk Operations (BulkInsertAsync, BulkUpdateAsync, BulkDeleteAsync)
  • Resilience (ResiliencePipeline, ResilienceOptions)
  • Caching (CachedRepository<T>, CachingOptions)
  • Query Interceptors (LoggingInterceptor, PerformanceInterceptor)

Breaking Changes

  • BulkUpdateAsync uses EF Core 10's Action<UpdateSettersBuilder<T>> signature

📄 License

MIT License - Copyright (c) 2024-2026 Nathan WILCKÉ

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.

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

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
5.0.0 98 1/28/2026
3.0.1 434 12/8/2025
3.0.0 198 11/26/2025
2.0.1 181 8/15/2025
1.5.0 370 11/21/2024
1.4.0 1,470 10/17/2024
1.3.0 1,307 6/23/2024
1.2.23 461 3/11/2024
1.2.22 465 12/29/2023
1.2.21 237 12/29/2023
1.2.20 243 12/28/2023
1.2.19 252 12/19/2023
1.2.18 214 12/19/2023
1.2.17 201 12/19/2023
1.2.16 329 11/15/2023
1.2.15 238 11/5/2023
1.2.14 216 11/4/2023
1.2.13 194 11/4/2023
1.2.12 190 11/4/2023
1.2.11 199 11/4/2023
Loading failed