RepoKit.Core 1.0.0

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

RepoKit 🎯

One attribute. Zero boilerplate. Full repository pattern.

A lightweight, production-ready .NET library that eliminates repository boilerplate through smart dependency injection. Add [AutoRepository] to your entity and instantly get a fully wired IRepository<T> with support for Entity Framework Core, Dapper, pagination, specifications, and Unit of Work.

NuGet version License: MIT .NET 8+ Build Status Quality Gate


✨ Features

  • 🎯 Zero Configuration - Single [AutoRepository] attribute to register repositories
  • 🔄 ORM Agnostic - Entity Framework Core, Dapper, or both in the same project
  • 📖 Specification Pattern - Type-safe, reusable query building
  • 📄 Built-in Pagination - PagedResult<T> with metadata
  • 🔗 Unit of Work - Atomic multi-repository operations with transactions
  • ⚡ High Performance - Minimal overhead; Dapper for raw SQL workloads
  • 📚 Full XML Docs - 100% documented with complete IntelliSense support
  • 🛡️ Null-Safe - Nullable reference types; comprehensive validation
  • 🎓 Clean Architecture Ready - SOLID principles and DDD compatible
  • 💾 Multi-Targeting - .NET 8, 9, and 10

📦 Installation

Option 1: Entity Framework Core Only

dotnet add package RepoKit.Core
dotnet add package RepoKit.EfCore

Option 2: Dapper Only

dotnet add package RepoKit.Core
dotnet add package RepoKit.Dapper

Option 3: Both EF Core and Dapper

dotnet add package RepoKit.Core
dotnet add package RepoKit.EfCore
dotnet add package RepoKit.Dapper

🚀 Quick Start

Step 1: Define Entity

using RepoKit.Core;

[AutoRepository]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public bool IsActive { get; set; }
}

Step 2: Configure Services

Entity Framework Core Only:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddDbContext<AppDbContext>()
    .AddAutoRepositoryEfCore<AppDbContext>()
    .AddAutoRepositories(typeof(Program).Assembly);

Dapper Only:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAutoRepositoryDapper(sp => 
        new SqlConnection("Server=localhost;Database=MyDb;Trusted_Connection=true;"))
    .AddAutoRepositories(typeof(Program).Assembly);

Both EF Core and Dapper:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddDbContext<AppDbContext>()
    .AddAutoRepositoryEfCore<AppDbContext>()
    .AddAutoRepositoryDapper(sp => 
        new SqlConnection("Server=localhost;Database=MyDb;Trusted_Connection=true;"))
    .AddAutoRepositories(typeof(Program).Assembly);

Step 3: Inject & Use

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IRepository<Product> _repo;

    public ProductsController(IRepository<Product> repo) => _repo = repo;

    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> Get(int id)
    {
        var product = await _repo.GetByIdAsync(id);
        return product != null ? Ok(product) : NotFound();
    }

    [HttpPost]
    public async Task<ActionResult> Create(Product product)
    {
        await _repo.AddAsync(product);
        return Created($"products/{product.Id}", product);
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> Update(int id, Product product)
    {
        var existing = await _repo.GetByIdAsync(id);
        if (existing == null) return NotFound();
        
        product.Id = id;
        await _repo.UpdateAsync(product);
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        await _repo.DeleteByIdAsync(id);
        return NoContent();
    }

    [HttpGet]
    public async Task<ActionResult<PagedResult<Product>>> GetAll(
        [FromQuery] int pageNumber = 1,
        [FromQuery] int pageSize = 10)
    {
        var result = await _repo.GetPagedAsync(
            new AllProductsSpec(), pageNumber, pageSize);
        return Ok(result);
    }
}

🔍 Advanced Usage

Specification Pattern

public class ActiveProductsSpec : BaseSpecification<Product>
{
    public ActiveProductsSpec(string? search = null)
    {
        AddCriteria(p => p.IsActive);
        
        if (search != null)
            AddCriteria(p => p.Name.Contains(search));
        
        ApplyOrderBy(p => p.Name);
        AddInclude(p => p.Category);
        AddInclude(p => p.Supplier);
        ApplyPaging(skip: 0, take: 10);
    }
}

var spec = new ActiveProductsSpec("laptop");
var products = await _repo.GetAsync(spec);
var paged = await _repo.GetPagedAsync(spec, pageNumber: 1, pageSize: 10);

Dapper with Raw SQL

public class TopSellingProductsSpec : BaseSpecification<Product>
{
    public TopSellingProductsSpec(int limit = 5)
    {
        UseRawSql(
            @"SELECT TOP @Limit p.* 
              FROM Products p
              INNER JOIN OrderItems oi ON p.Id = oi.ProductId
              GROUP BY p.Id, p.Name, p.Price
              ORDER BY COUNT(*) DESC",
            new { Limit = limit });
    }
}

var spec = new TopSellingProductsSpec(5);
var topProducts = await _repo.GetAsync(spec);

Unit of Work Pattern

public class ProductTransferService
{
    private readonly IRepository<Product> _productRepo;
    private readonly IRepository<Category> _categoryRepo;
    private readonly IUnitOfWork _unitOfWork;

    public async Task MoveProductsAsync(int fromCategoryId, int toCategoryId)
    {
        await _unitOfWork.BeginTransactionAsync();
        try
        {
            var spec = new ProductsByCategorySpec(fromCategoryId);
            var products = await _productRepo.GetAsync(spec);
            
            foreach (var product in products)
            {
                product.CategoryId = toCategoryId;
                await _productRepo.UpdateAsync(product);
            }
            
            await _unitOfWork.SaveChangesAsync();
            await _unitOfWork.CommitTransactionAsync();
        }
        catch
        {
            await _unitOfWork.RollbackTransactionAsync();
            throw;
        }
    }
}

Read-Only Repositories

[AutoRepository(ReadOnly = true)]
public class AuditLog
{
    public int Id { get; set; }
    public string Action { get; set; } = string.Empty;
    public DateTime Timestamp { get; set; }
}

private readonly IReadRepository<AuditLog> _auditRepo;
public async Task<IActionResult> History()
{
    var logs = await _auditRepo.GetAllAsync();
    return Ok(logs);
}

Custom Implementations

public class CustomProductRepository : DapperRepository<Product>
{
    public CustomProductRepository(IDbConnection connection) 
        : base(connection) { }
    
    protected override string GetTableName() => "tbl_Product";
    protected override string GetIdColumnName() => "ProductID";
}

[AutoRepository(CustomImplementation = typeof(CustomProductRepository))]
public class SpecialProduct { }

📊 Architecture

Project Structure

RepoKit.Core (Required)
├── IRepository<T>          - Full CRUD operations
├── IReadRepository<T>      - Read-only operations
├── IUnitOfWork             - Transaction management
├── ISpecification<T>       - Query specification
├── PagedResult<T>          - Paged result container
├── BaseSpecification<T>    - Base class for specifications
└── [AutoRepository]        - Entity registration attribute

RepoKit.EfCore (Optional)
├── EfRepository<T>         - Entity Framework implementation
├── EfUnitOfWork            - DbContext-based transactions
├── SpecificationEvaluator  - Converts specs to LINQ
└── ServiceCollectionExtensions

RepoKit.Dapper (Optional)
├── DapperRepository<T>     - Dapper implementation
├── DapperUnitOfWork        - SQL transaction management
└── ServiceCollectionExtensions

🎯 Best Practices

DO:

  • Use IReadRepository<T> for queries only
  • Create specifications for complex queries
  • Use Unit of Work for multi-repository operations
  • Always paginate large datasets
  • Use [AutoRepository(ReadOnly = true)] for audit entities

DON'T:

  • Use IRepository<T> where IReadRepository<T> suffices
  • Retrieve all rows without pagination
  • Pass raw SQL without parameters (SQL injection risk)

📋 API Reference

Method Returns Purpose
GetByIdAsync<TKey>(key) T? Get entity by primary key
GetAllAsync() IReadOnlyList<T> Get all entities
GetAsync(spec) IReadOnlyList<T> Get by specification
GetPagedAsync(spec, page, size) PagedResult<T> Get paginated results
CountAsync(spec) int Count matching entities
AnyAsync(spec) bool Check if any exists
AddAsync(entity) Task Add single entity
UpdateAsync(entity) Task Update entity
DeleteAsync(entity) Task Delete entity

⚙️ Requirements

  • .NET 8.0+ - Supports 8.0, 9.0, 10.0
  • C# 12+ - Using nullable reference types
  • Entity Framework Core 8.0+ - For RepoKit.EfCore
  • Dapper 2.1+ - For RepoKit.Dapper

📝 License

MIT License - See LICENSE for details.


🤝 Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.


📚 Documentation


💬 Support


Made with ❤️ by Sourav Das

Product 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 is compatible.  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.  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 (2)

Showing the top 2 NuGet packages that depend on RepoKit.Core:

Package Downloads
RepoKit.EfCore

Entity Framework Core implementation for RepoKit. Provides generic repository pattern, Unit of Work, and specification evaluator with automatic registration via [AutoRepository] attribute. Includes EfRepository<T>, EfUnitOfWork, and LINQ specification support.

RepoKit.Dapper

Dapper implementation for RepoKit. Provides high-performance raw SQL repository with automatic registration via [AutoRepository] attribute. Includes DapperRepository<T> and DapperUnitOfWork for transaction management.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 57 3/25/2026