Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Orbis25/FoundationKit/llms.txt

Use this file to discover all available pages before exploring further.

By the end of this guide you will have a fully working ASP.NET Core Web API that stores a Person entity in a PostgreSQL database, exposes standard CRUD endpoints through FoundationKit’s base controller, and returns paginated results from a single GET request — all without writing a single line of query or routing logic yourself.
1

Install the NuGet packages

Add all four FoundationKit packages to your ASP.NET Core project. The umbrella FoundationKit package already depends on the other three, but installing them explicitly lets you control versions independently.
dotnet add package FoundationKit
dotnet add package FoundationKit.Domain
dotnet add package FoundationKit.Repository
dotnet add package Foundationkit.Extensions
If your project only needs the repository pattern without the base controllers or encryption service, you can install FoundationKit.Repository and FoundationKit.Domain alone and skip the umbrella package.
2

Define your entity model

Create a class that inherits BaseModel. You get Id (Guid), CreatedAt, UpdatedAt, IsDeleted, CreatedBy, and UpdatedBy for free. Add only the properties specific to your domain.
using FoundationKit.Domain.Models;
using System.ComponentModel.DataAnnotations.Schema;

namespace MyApp.Domain.Models;

public class Person : BaseModel
{
    public string? Name { get; set; }
}
BaseModel exposes the following members automatically:
PropertyTypeNotes
IdGuidPrimary key
CreatedAtDateTimeSet on insert
UpdatedAtDateTime?Set on update; override and add [Column] to persist
IsDeletedboolUsed by SoftRemoveAsync
CreatedBystring?Optional auditing field
UpdatedBystring?Optional auditing field
3

Create your DbContext

Inherit from FoundationKitDbContext and add a DbSet<T> for each entity. Then register the context in Program.cs using your preferred provider (the example project uses PostgreSQL via Npgsql).
using FoundationKit.Domain.Persistence;
using Microsoft.EntityFrameworkCore;
using MyApp.Domain.Models;

namespace MyApp.Domain.Persistence;

public class ApplicationDbContext : FoundationKitDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<Person> Persons { get; set; }
}
Register the context in Program.cs:
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("postgres")));
Then run the EF Core tooling to create your first migration:
dotnet ef migrations add InitialCreate
dotnet ef database update
4

Create a repository (service) class

Inherit BaseRepository<TContext, TModel> to get the full IBaseRepository<TModel> implementation — CreateAsync, UpdateAsync, GetByIdAsync, GetPaginatedListAsync, SoftRemoveAsync, and more — with transactional commit handling included.First declare the interface:
using FoundationKit.Repository.Interfaces;
using MyApp.Domain.Models;

namespace MyApp.Application.Interfaces;

public interface IPersonService : IBaseRepository<Person>
{
}
Then implement it:
using FoundationKit.Repository.Services;
using MyApp.Domain.Models;
using MyApp.Domain.Persistence;
using MyApp.Application.Interfaces;

namespace MyApp.Infrastructure.Services;

public class PersonService : BaseRepository<ApplicationDbContext, Person>, IPersonService
{
    public PersonService(ApplicationDbContext context) : base(context)
    {
    }
}
You can override any method in BaseRepository to add custom query logic. The GetAll method returns an IQueryable<TModel> that you can further compose before materialising.
5

Register services with AddFoundationKit

Wire everything up in Program.cs. AddFoundationKit scans your assembly for AutoMapper profiles and registers the mapping infrastructure. Add your scoped service registration alongside it.
using FoundationKit.Extensions;
using System.Reflection;
using MyApp.Domain.Persistence;
using MyApp.Application.Interfaces;
using MyApp.Infrastructure.Services;

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Register FoundationKit (also sets up AutoMapper from this assembly)
builder.Services.AddFoundationKit(Assembly.GetExecutingAssembly());

// Register your database context
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("postgres")));

// Register your service
builder.Services.AddScoped<IPersonService, PersonService>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.MapControllers();
app.Run();
AddFoundationKit calls services.AddAutoMapper(assembly) internally. If you are using MapRepository you must have at least one AutoMapper Profile class in the scanned assembly, otherwise AutoMapper will throw at startup.
If you also want the RSA/AES encryption service available across your application, chain AddFoundationKitEncryptor:
builder.Services.AddFoundationKitEncryptor(new()
{
    PublicKey  = builder.Configuration["Encryption:PublicKey"]!,
    PrivateKey = builder.Configuration["Encryption:PrivateKey"]!,
    HeaderAes  = "AES"
});
6

Create a controller

Inherit ApiCoreController<TModel, TService>. The base class maps the route as api/[controller] and generates five endpoints automatically: GET (paginated list), GET {id}, POST, PUT {id}, and DELETE {id} (soft delete).
using FoundationKit.Core.Controllers;
using MyApp.Domain.Models;
using MyApp.Application.Interfaces;

namespace MyApp.Controllers;

public class PeopleController : ApiCoreController<Person, IPersonService>
{
    public PeopleController(IPersonService service) : base(service)
    {
    }
}
That is the entire controller. The following endpoints are now available:
MethodRouteDescription
GET/api/people?page=1&qyt=10Paginated list
GET/api/people/{id}Single entity by GUID
POST/api/peopleCreate entity
PUT/api/people/{id}Full update
DELETE/api/people/{id}Soft delete (IsDeleted = true)
Override any virtual action method on the controller to add custom behaviour, authorization attributes, or response shaping.
7

Run and test with a paginated GET

Start your application and send a paginated request:
dotnet run
curl "https://localhost:5001/api/people?page=1&qyt=10"
A successful response looks like this:
{
  "actualPage": 1,
  "qyt": 10,
  "pageTotal": 3,
  "total": 25,
  "results": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "name": "Jane Smith",
      "createdAt": "2024-05-01T10:30:00",
      "updatedAt": null,
      "isDeleted": false,
      "createdBy": null,
      "updatedBy": null
    }
  ]
}
Pass noPaginate=true as a query parameter to return all records without pagination:
curl "https://localhost:5001/api/people?noPaginate=true"
Pass orderByDesc=false to sort ascending by CreatedAt:
curl "https://localhost:5001/api/people?page=1&qyt=10&orderByDesc=false"
The Paginate query model binds page, qyt, noPaginate, and orderByDesc automatically from the query string. You do not need to add any [FromQuery] attributes on your controller action — ApiCoreController handles the binding.

Next Steps

  • Read the Packages reference to understand what each NuGet package provides and when to install only a subset.
  • Use AddFoundationKitIdentityWithMapper<TUser, TDbContext> if your project needs ASP.NET Core Identity baked in alongside AutoMapper.
  • Explore ApiMapController when you want strict separation between input DTOs, edit DTOs, and output DTOs with AutoMapper-powered mapping at the repository layer.

Build docs developers (and LLMs) love