GerstITS Framework Examples
This solution demonstrates all features of the GerstITS framework packages in a small, coherent customer management domain.
Solution layout
| Project | Purpose |
|---|---|
GerstITS.Examples.Api |
ASP.NET Core Web API host: fluent controllers, minimal API endpoints, versioning, exception handling, Swagger, authentication, session cache, jobs and auto migration. |
GerstITS.Examples.Logic |
Business logic: providers, search engine integration, validation rules, customizations and AutoMapper profiles. |
GerstITS.Examples.Data |
Data access: entities with framework aspects, EF Core DbContext, entity mappings, database configurator and migrations. |
GerstITS.Examples.Jobs.SayHelloWorld |
Scheduled Quartz jobs with cron configuration. |
GerstITS.WebClients.Example.Api |
Typed REST client contract for the example API (ICustomer). |
GerstITS.Examples.WebClient.Console |
Console client consuming the API via IWebClient plus demos of the common/system utilities. |
GerstITS.Examples.Tests |
xUnit tests using the GerstITS test framework categories. |
Feature matrix
GerstITS.Common
| Feature | Example |
|---|---|
| String/object/enum/enumerable extensions | WebClient.Console/Tests/CommonFeaturesRunner.cs |
Fluent exception handling (Is(...).ThenThrows<...>().WithMessage(...)) |
CommonFeaturesRunner.cs, Logic/Customers/CustomerProvider.cs (Import) |
Range<T> + Intersects |
CommonFeaturesRunner.cs |
AES cryptography extensions (Encrypt/Decrypt) |
CommonFeaturesRunner.cs |
ApplicationEnvironment detection |
Api/Program.cs (IsEfCoreActionStarted) |
GerstITS.System
| Feature | Example |
|---|---|
ISystemClock |
MaintenanceController.Ping, SayHelloWorldJob |
IJsonConvert |
Api/Common/StartupTasks/ExampleStartupTask.cs, CommonFeaturesRunner.cs |
IActivator |
CommonFeaturesRunner.cs |
ICache (encrypted, session backed) |
Api/Controllers/1.1/CacheController.cs |
Customizations (CustomizationBase<T>, ApplyCustomizations()) |
Logic/Customers/Customizations/CustomerDisplayNameCustomization.cs |
Configuration prefix pattern (ToConfigurationPrefix) |
Api/Common/Configurations/WebApiConfiguration.*.cs |
GerstITS.IoC / GerstITS.IoC.DotNetCore
| Feature | Example |
|---|---|
IIoCModule<IServiceCollection> modules (partial pattern) |
Module.cs in every project |
DotNetCoreApplicationBootstrapper + IApplicationStart |
WebClient.Console/Program.cs, Tests/TestRunner.cs, Tests/CommonFeaturesRunner.cs |
IStartupTask with priorities |
Api/Common/StartupTasks/ExampleStartupTask.cs |
Namespace based assembly scanning (Register...Of<T>()) |
Logic/Module.Customers.cs |
GerstITS.Data / GerstITS.Data.EntityFramework / GerstITS.Data.EntityFramework.PostgreSql
| Feature | Example |
|---|---|
EntityBase<TKey> + aspects (IActivatable, ICreatable, IModifiable, IVersionable) |
Data/Entities/CustomerEntity.cs |
Historization (IHistoricizable) |
Data/Entities/CustomerNoteEntity.cs |
EntityMappingBase<TEntity> |
Data/Mappings/*.cs |
EntityFrameworkDbContextBase + IDbContext |
Data/CustomerDbContext.cs |
PostgreSqlDatabaseConfiguratorBase<TDbContext> |
Data/Migrations/CustomerDatabaseConfigurator.cs |
| Design time factory + migrations | Data/Migrations/DesignTime/CustomerDbContextDesignTimeFactory.cs, Data/Migrations/20260703*_InitialCreate.cs |
Registration (AddMigration, AddEntityFrameworkSession) |
Data/Module.cs |
Repository queries (active only by default, includeInactive opt-in) |
Logic/Customers/CustomerProvider.cs (GetById) |
Soft delete by default, forceDelete opt-in |
CustomerProvider.Delete |
Bulk operations (BulkSave) |
CustomerProvider.Import |
Query projection (Project) |
Logic/Customers/Search/CustomerSearchQueryBuilderRule.cs |
ThrowsAnExceptionIfNotExisting / EntityNotFoundException |
CustomerProvider.cs, Api/.../EntityNotFoundExceptionTransformation.cs |
Auto migration on startup (WebApi:EntityFrameworkMigration:AutoMigrate) |
Api/appsettings.json |
GerstITS.Data.EntityFramework.SqlServerworks exactly like the PostgreSql package: derive fromSqlServerDatabaseConfiguratorBase<TDbContext>instead. Note that only oneIDatabaseConfiguratorimplementation is allowed per assembly.
GerstITS.Search
| Feature | Example |
|---|---|
ISearchEngine + SearchResult<T> |
Logic/Customers/CustomerProvider.cs (Search) |
SearchFilterBase (paging + sorting) |
Logic/Customers/Contracts/CustomerSearchFilter.cs |
SearchQueryBuilderRuleBase<TItem, TFilter> |
Logic/Customers/Search/CustomerSearchQueryBuilderRule.cs |
InitializationRuleBase<T> (filter defaults) |
Logic/Customers/Search/CustomerSearchFilterInitializationRule.cs |
PagingValidationRuleBase<T> |
Logic/Customers/Validation/CustomerSearchFilterValidationRule.cs |
Custom ISortingProvider |
Logic/Shared/Search/Sorting/SortingProvider.cs |
GerstITS.Validation
| Feature | Example |
|---|---|
ValidationRuleBase<T> (FluentValidation) |
Logic/Customers/Validation/CustomerValidationRule.cs, Logic/Shared/Validation/IdValidationRule.cs |
IsEMail() rule builder extension |
CustomerValidationRule.cs |
Automatic validation in fluent controllers (IValidator) |
All controllers via FluentApiControllerBase |
Explicit validation in minimal API endpoints (IValidator + ToErrorMessage) |
Api/Endpoints/Endpoints.Validator.cs |
GerstITS.Mapping.AutoMapper
| Feature | Example |
|---|---|
Profiles + RegisterMappingsOf<T>() |
Logic/Customers/Mappings/CustomerMapping.cs, Logic/Example/Mappings/IntegerMapping.cs |
GerstITS.Web / GerstITS.Web.Api / GerstITS.Web.Api.Swagger / GerstITS.Web.Rest
| Feature | Example |
|---|---|
HostingStartup fluent pipeline |
Api/Program.cs |
FluentApiControllerBase (Api().Use(...).Get/Create/Update/Delete) |
Api/Controllers/1.1/*.cs |
| API versioning (side by side controllers) | Api/Controllers/1.0 vs Api/Controllers/1.1 |
Minimal API endpoints (partial Endpoints class per feature, nested static endpoint classes) |
Api/Endpoints/Endpoints.cs, Endpoints.Customers.cs, Endpoints.CustomerNotes.cs |
Endpoint grouping + Swagger tags (MapGroup, WithTags) |
Api/Endpoints/Endpoints.Customers.cs |
Query parameter binding to search filters ([AsParameters]) |
Endpoints.Customers.MapSearch |
| Global exception transformations | Api/Common/ExceptionHandling/Transformations/*.cs |
Global exception handling middleware for minimal APIs (UseGlobalExceptionHandling) |
Api/Common/ExceptionHandling/Extensions/WebApplicationExtensions.cs, Api/Program.cs |
| Automatic response compression (zstd, brotli, gzip — also for HTTPS) | built in, no app code required — see "Response compression" below |
| Server configuration (CORS, HSTS, forwarded headers) | Api/Common/Configurations/WebApiConfiguration.Server.*.cs |
| Swagger configuration incl. security schemes | Api/Common/Configurations/WebApiConfiguration.Swagger*.cs, WebApiConfiguration.OpenApiSecurityScheme.cs |
Session based cache storage (AddHttpSession) |
Api/Module.Session.cs, CacheController.cs |
Typed REST clients (IWebService, WebMethod, ResourceUrl, HttpHeader) |
GerstITS.WebClients.Example.Api/Contracts/ICustomer.cs |
RestWebServiceConfigurationBase + creation rules |
GerstITS.WebClients.Example.Api/Configurations, CreationRules |
IWebClient.Request<T>().Execute(...) |
WebClient.Console/Tests/TestRunner.cs |
GerstITS.Authentication.ApiKey / GerstITS.Authentication.OpenId
| Feature | Example |
|---|---|
[ApiKey] attribute + IApiKeyConfiguration |
Api/Controllers/1.1/MaintenanceController.cs, WebApiConfiguration.ApiKey.cs |
JWT bearer via IOpenIdConfiguration + [Authorize] |
Api/Controllers/1.1/SecuredController.cs, WebApiConfiguration.OpenId*.cs |
GerstITS.Mail
| Feature | Example |
|---|---|
IMailProvider, MailNotification, ContactRequest |
Api/Controllers/1.1/ContactController.cs |
SMTP configuration (Mail section) |
Api/appsettings.json |
GerstITS.Job / GerstITS.Job.Scheduling
| Feature | Example |
|---|---|
JobBase + cron scheduling |
Jobs.SayHelloWorld/Jobs/*.cs |
JobSchedulingConfigurationBase (named + convention based) |
Jobs.SayHelloWorld/Configurations/*.cs, Api/appsettings.json (Jobs section) |
RegisterJob<TJob, TConfig>() + IgnoreConditions |
Jobs.SayHelloWorld/Module.cs |
GerstITS.TestFramework
| Feature | Example |
|---|---|
[TestCategory(TestCategories.Unit/Integration)] traits |
GerstITS.Examples.Tests/**/*Test.cs |
Filtering: dotnet test --filter "Category=Unit" |
see below |
Running
- Database: the API auto-migrates on startup (
AutoMigrate: true). Adjust theCustomerDbContextconnection string inGerstITS.Examples.Api/appsettings.json(PostgreSQL). - API: start
GerstITS.Examples.Api. Swagger UI is available in development at/api/swagger. - Console client: start
GerstITS.Examples.WebClient.Consolewhile the API is running. - Tests:
dotnet test(optionally--filter "Category=Unit"). - Migrations:
dotnet ef migrations add <Name>insideGerstITS.Examples.Data(uses the design time factory andappsettings.jsonof that project).
Fluent controllers vs. minimal API endpoints
The customer domain is exposed twice to compare both styles:
POST/GET/PUT/DELETE /api/Customer— fluent controllers (FluentApiControllerBase, validation and exception transformations applied by the fluent pipeline).GET/POST/PUT/DELETE /api/v2.0/customers— minimal API endpoints (partialEndpointsclass, explicitEndpoints.Validator, exception transformations applied byUseGlobalExceptionHandling).
Search differs on purpose: the controller uses POST /api/Customer/Search with a body filter, the minimal API uses
GET /api/v2.0/customers binding the same CustomerSearchFilter from query parameters via [AsParameters].
Response compression
GerstITS.Web.Api enables response compression automatically — there is nothing to register or configure in the
application: the framework module registers the zstd (ZstdSharp), brotli and gzip providers with
EnableForHttps = true and HostingStartup...Build() adds the UseResponseCompression() middleware. The provider is
picked by the client's Accept-Encoding header (zstd preferred, then brotli, then gzip):
curl -s -D - -o NUL -H "Accept-Encoding: zstd, br, gzip" https://localhost:<port>/api/v2.0/customers
The response then carries the matching Content-Encoding header (e.g. Content-Encoding: zstd).
Requires the first
GerstITS.Web.Apirelease after 2026.7.7 — older packages do not contain the compression feature yet, requests are then answered uncompressed.
Api key protected endpoints
GET /api/Maintenance/Ping requires the header configured under WebApi:ApiKey (default: X-Api-Key: example-api-key).