FluentSeeding.AspNetCore 0.2.1

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

FluentSeeding

A fluent, composable data seeding library for .NET. Define how your entities are generated using a clean, chainable API, then wire them up to your database with first-class Entity Framework Core and ASP.NET Core support.

Packages

Package Description
FluentSeeding Core library with builders, rules, idempotency
FluentSeeding.EntityFrameworkCore EF Core persistence layer
FluentSeeding.AspNetCore Microsoft DI and hosted application integration

Quick Start

1. Define a seeder

public sealed class UserSeeder : EntitySeeder<User>
{
    protected override void Configure(SeedBuilder<User> builder)
    {
        builder.Count(10)
            .RuleFor(u => u.Id).UseFactory(Guid.NewGuid)
            .RuleFor(u => u.Name).UseValue("Test User")
            .RuleFor(u => u.Email).UseFactory(i => $"user{i}@example.com");
    }
}

2. Register with DI

builder.Services.AddFluentSeeding(seederConfig =>
    seederConfig
        .AddSeeder<UserSeeder>()
        .AddSeeder<ProductSeeder>()
        .AddSeeder<PurchaseSeeder>());

// Register an EF Core persistence layer
builder.Services.AddFluentSeedingEntityFrameworkCore<SampleDbContext>(options =>
    options.ConflictBehavior = ConflictBehavior.Skip);

Alternatively, register all seeders within an assembly:

builder.Services.AddFluentSeeding(seeders => { seeders.AddSeedersFromAssemblyContaining<OrderSeeder>(); })

3. Run seeders

var app = builder.Build();
await app.RunSeedersAsync();
await app.RunAsync();

Core Concepts

SeedBuilder<T>

The fluent builder that describes how to generate instances of T.

var builder = new SeedBuilder<Product>();
builder.Count(5)
    .RuleFor(p => p.Id).UseFactory(Guid.NewGuid)
    .RuleFor(p => p.Name).UseFrom("Widget", "Gadget", "Doohickey")
    .RuleFor(p => p.Price).UseFactory(() => Math.Round(Random.Shared.NextDouble() * 100, 2));

IEnumerable<Product> products = builder.Build();

Call Build() to materialize the entities. Rules execute in dependency order (see Dependencies).

RuleFor

RuleFor(selector) opens a rule for a property. Chain a terminal to set its value source:

Terminal Description
UseValue(value) Same constant value for every entity
UseFactory(Func<TProperty>) Invoked once per entity
UseFactory(Func<int, TProperty>) Index-aware factory that receives the entity's zero-based position
UseFrom(params TProperty[]) Random selection from a fixed pool
UseFrom(IEnumerable<TProperty>) Random selection from a sequence

After a terminal, you are back on SeedBuilder<T> and can continue chaining.

Modifiers

Add modifiers before the terminal to control behaviour:

builder.RuleFor(u => u.Email)
    .Unique()                               // enforce uniqueness across all generated entities
    .When(u => u.Role == "admin")           // only apply this rule when predicate is true
    .DependsOn(u => u.Role)                 // declare execution order explicitly
    .UseFactory(i => $"admin{i}@corp.com");

Rules by default are executed in the order they are declared, using DependsOn is more of a safety net or more control over it.

Dependencies

DependsOn() causes Build() to topologically sort rules so that a rule always runs after the properties it depends on have already been set. Circular dependencies are detected and throw InvalidOperationException.

builder.RuleFor(u => u.Role).UseValue("admin");

builder.RuleFor(u => u.Permissions)
    .DependsOn(u => u.Role)
    .When(u => u.Role == "admin")
    .UseValue(Permission.All);

Nested Objects

HasOne: a single nested instance per parent

builder.HasOne(u => u.Profile, profile =>
    profile.RuleFor(p => p.Bio).UseValue("Hello!"));

HasMany: a collection per parent

builder.Count(3)
    .HasMany(u => u.Purchases, purchases =>
        purchases.Count(5)
            .RuleFor(p => p.Id).UseFactory(Guid.NewGuid)
            .RuleFor(p => p.Quantity).UseFactory(() => Random.Shared.Next(1, 10)));
// Creates 3 users, each with their own list of 5 purchases

Idempotency

When you need the same data every run, no matter the occasion, use the Idempotent helpers. Values are derived deterministically from the entity type, entity index, and an optional seed string using UUID v5 (RFC 4122).

Idempotent.Guid<User>(index: 0);              // always the same GUID for User #0
Idempotent.Int<Product>(index: 1);            // deterministic int for Product #1
Idempotent.Long<Order>(index: 2);             // deterministic long for Order #2
Idempotent.Slug<Category>(index: 0, "cat");   // "cat-0"

The idempotent terminals are available directly on SeedRule<T, TProperty>:

builder.Count(5)
    .RuleFor(u => u.Id).UseIdempotentGuid()
    .RuleFor(u => u.ExternalRef).UseIdempotentSlug("user");
// Produces "user-0", "user-1", ... every single time

EntitySeeder<T>

EntitySeeder<T> is an abstract base class for reusable, injectable seeders. The generated data is cached after the first call to Data, making it safe to reference from other seeders.

public sealed class PurchaseSeeder : EntitySeeder<Purchase>
{
    private readonly UserSeeder _users;
    private readonly ProductSeeder _products;

    public PurchaseSeeder(UserSeeder users, ProductSeeder products)
    {
        _users = users;
        _products = products;
    }

    protected override void Configure(SeedBuilder<Purchase> builder)
    {
        builder.Count(50)
            .RuleFor(p => p.Id).UseFactory(Guid.NewGuid)
            .RuleFor(p => p.UserId).UseFrom(_users.Data.Select(u => u.Id))
            .RuleFor(p => p.ProductId).UseFrom(_products.Data.Select(p => p.Id))
            .RuleFor(p => p.Quantity).UseFactory(() => Random.Shared.Next(1, 100));
    }
}

Persistence

IPersistenceLayer

Implement IPersistenceLayer to back seeding with any storage:

public interface IPersistenceLayer
{
    void Persist<T>(IEnumerable<T> entities);
    Task PersistAsync<T>(IEnumerable<T> entities, CancellationToken cancellationToken = default);
    void Flush();
    Task FlushAsync(CancellationToken cancellationToken = default);
}

Entity Framework Core

EntityFrameworkCorePersistenceLayer stages entities and commits with SaveChanges(). Configure how to handle pre-existing records via ConflictBehavior:

Behavior Description
ConflictBehavior.Insert Always insert (default). Throws on key conflict
ConflictBehavior.Skip Skip entities whose primary key already exists
ConflictBehavior.Update Update existing, insert new
services.AddScoped<IPersistenceLayer>(sp =>
    new EntityFrameworkCorePersistenceLayer(
        sp.GetRequiredService<AppDbContext>(),
        ConflictBehavior.Skip));

ASP.NET Core Integration

SeederRunner

SeederRunner orchestrates multiple seeders in registration order. All entities are staged first; then a single FlushAsync() commits everything atomically.

// Manual usage (without DI)
var runner = new SeederRunner(persistenceLayer, new IEntitySeeder[] { userSeeder, productSeeder });
await runner.RunAsync();

When using AddFluentSeeding, SeederRunner is registered automatically and resolved by RunSeedersAsync().

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
0.2.1 127 3/29/2026
0.2.0 81 3/29/2026
0.1.0 133 3/28/2026