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.

FoundationKit ships three abstract controller base classes that eliminate boilerplate CRUD code. ApiCoreController targets REST APIs that work directly with domain models, ApiMapController adds AutoMapper support for APIs that expose separate input/output DTOs, and MvcCoreController handles server-side Razor MVC applications with built-in SweetAlert2 notification support. All three expose virtual methods so you can override any endpoint with custom logic.
ApiCoreController and ApiMapController are decorated with [Route("api/[controller]")] and [ApiController]. The controller name is derived from the class name with the Controller suffix removed. MvcCoreController extends Controller and has no route attribute — routes are resolved by the standard MVC {controller}/{action} convention.

ApiCoreController<TModel, TService>

ApiCoreController<TModel, TService> is an abstract ControllerBase decorated with [Route("api/[controller]")] and [ApiController]. It exposes five virtual endpoints backed by an IBaseRepository<TModel> service. Generic constraints:
  • TModel : BaseModel — your entity class that inherits BaseModel
  • TService : IBaseRepository<TModel> — a service/repository implementing IBaseRepository<TModel>
Endpoints provided out of the box:
MethodRouteAction
GET/api/[controller]Paginated list via [FromQuery] Paginate
GET/api/[controller]/{id:guid}Fetch single entity by GUID
POST/api/[controller]Create entity, returns 201 Created
PUT/api/[controller]/{id}Update entity, returns 200 OK
DELETE/api/[controller]/{id:guid}Soft-delete entity, returns 200 OK
Create a controller by inheriting the base class and injecting your service:
// Controllers/PersonController.cs
[Route("api/[controller]")]
public class PersonController : ApiCoreController<Person, IPersonService>
{
    public PersonController(IPersonService service) : base(service)
    {
    }
}
That single class provides all five endpoints with no additional code. To customise an endpoint, override the virtual method:
// Override Create to stamp the current user before saving
[HttpPost]
public override async Task<IActionResult> AddAsync(
    Person model,
    CancellationToken cancellationToken = default)
{
    model.CreatedBy = GetCurrentUserId(); // your helper
    return await base.AddAsync(model, cancellationToken);
}

ApiMapController<TService, TDtoModel, TInputModel, TEditModel>

ApiMapController is the DTO-aware counterpart. It implements IApiMapController<TInputModel, TEditModel> and delegates work to an IMapRepository, which uses AutoMapper under the hood to translate between domain models and DTOs. Generic constraints:
  • TService : IMapRepository<TInputModel, TEditModel, TDtoModel>
  • TInputModel : BaseInput — DTO used for POST
  • TEditModel : BaseEdit — DTO used for PUT
  • TDtoModel : BaseOutput — DTO returned from GET endpoints
Same five endpoints, now DTO-driven:
MethodRouteAction
GET/api/[controller]Paginated list returning TDtoModel
GET/api/[controller]/{id:guid}Single TDtoModel
POST/api/[controller]Accepts TInputModel, returns 201 Created
PUT/api/[controller]/{id}Accepts TEditModel, returns 200 OK
DELETE/api/[controller]/{id:guid}Soft-delete, returns 200 OK
// Controllers/PeopleController.cs
public class PeopleController : ApiMapController<IPersonMapService, PersonDto, PersonInput, PersonEdit>
{
    public PeopleController(IPersonMapService service) : base(service)
    {
    }
}
You can inject additional services and override any endpoint:
public class PeopleController : ApiMapController<IPersonMapService, PersonDto, PersonInput, PersonEdit>
{
    private readonly IPersonMapService _service;

    public PeopleController(IPersonMapService service) : base(service)
    {
        _service = service;
    }

    // Override Create to attach the caller's identity
    [HttpPost]
    public override async Task<IActionResult> Create(
        PersonInput inputModel,
        CancellationToken cancellationToken = default)
    {
        inputModel.CreatedBy = User.FindFirstValue(ClaimTypes.NameIdentifier);
        return await base.Create(inputModel, cancellationToken);
    }
}
Use ApiMapController for any API that needs to decouple the request/response shape from the database model — for example, hiding internal IDs, combining fields, or applying validation annotations that shouldn’t live on domain entities.

MvcCoreController<TModel, TService>

MvcCoreController<TModel, TService> extends Controller (Razor/MVC) and implements IMvcCoreController<TModel>. It provides server-rendered views for the classic create/read/update/delete flow, plus built-in notification support via SweetAlert2. Generic constraints:
  • TModel : BaseModel
  • TService : IBaseRepository<TModel>
Actions provided:
MethodHTTPAction
IndexGETPaginated list view
CreateGETRender empty create form
CreatePOSTValidate, save, redirect to Index
UpdateGETLoad entity into edit form
UpdatePOSTValidate, save, redirect to Index
DeletePOSTSoft-delete entity
Notification helpers: ShowAlert(title, type, message, config) stores a SweetAlert2 call in TempData["Notification"], which your Razor partial view reads and renders. It wraps the SendNotification extension method from ControllerExtensions.
// Available MvcCoreNotification values
MvcCoreNotification.Success  // green check
MvcCoreNotification.Error    // red X
MvcCoreNotification.Warning  // orange triangle
MvcCoreNotification.Question // question mark
MvcCoreNotification.Info     // blue info
GetUserId helper: GetUserId(claimType) reads the current user’s claim from the HttpContext. By default it reads ClaimTypes.NameIdentifier:
var userId = GetUserId(); // returns the user's ID string, or null if unauthenticated
Example — MVC controller for products:
// Controllers/ProductController.cs
public class ProductController : MvcCoreController<Product, IProductService>
{
    public ProductController(IProductService service) : base(service)
    {
    }

    // Override Create POST to stamp the current user
    [HttpPost]
    public override async Task<IActionResult> Create(
        Product inputModel,
        CancellationToken cancellationToken = default)
    {
        inputModel.CreatedBy = GetUserId();
        return await base.Create(inputModel, cancellationToken);
    }
}
The base class has customisable success/error message properties you can override per controller:
protected override string CreateSuccess { get; set; } = "Product created!";
protected override string CreateError   { get; set; } = "Could not create product.";
protected override string UpdateSuccess { get; set; } = "Product updated!";
protected override string UpdateError   { get; set; } = "Could not update product.";

Comparing the three controller types

FeatureApiCoreControllerApiMapControllerMvcCoreController
Base classControllerBaseControllerBaseController
Response formatJSON (TModel)JSON (TDtoModel)Razor views
Input typeTModel directlyTInputModel / TEditModelTModel directly
AutoMapper
Notifications✓ SweetAlert2
GetUserId helper
Typical use caseSimple internal APIsPublic REST APIs with DTOsAdmin dashboards / MVC apps

Build docs developers (and LLMs) love