# 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` + `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`, `ApplyCustomizations()`) | `Logic/Customers/Customizations/CustomerDisplayNameCustomization.cs` | | Configuration prefix pattern (`ToConfigurationPrefix`) | `Api/Common/Configurations/WebApiConfiguration.*.cs` | ### GerstITS.IoC / GerstITS.IoC.DotNetCore | Feature | Example | |---------|---------| | `IIoCModule` 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()`) | `Logic/Module.Customers.cs` | ### GerstITS.Data / GerstITS.Data.EntityFramework / GerstITS.Data.EntityFramework.PostgreSql | Feature | Example | |---------|---------| | `EntityBase` + aspects (`IActivatable`, `ICreatable`, `IModifiable`, `IVersionable`) | `Data/Entities/CustomerEntity.cs` | | Historization (`IHistoricizable`) | `Data/Entities/CustomerNoteEntity.cs` | | `EntityMappingBase` | `Data/Mappings/*.cs` | | `EntityFrameworkDbContextBase` + `IDbContext` | `Data/CustomerDbContext.cs` | | `PostgreSqlDatabaseConfiguratorBase` | `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.SqlServer` works exactly like the PostgreSql package: derive from > `SqlServerDatabaseConfiguratorBase` instead. Note that only one `IDatabaseConfigurator` > implementation is allowed per assembly. ### GerstITS.Search | Feature | Example | |---------|---------| | `ISearchEngine` + `SearchResult` | `Logic/Customers/CustomerProvider.cs` (`Search`) | | `SearchFilterBase` (paging + sorting) | `Logic/Customers/Contracts/CustomerSearchFilter.cs` | | `SearchQueryBuilderRuleBase` | `Logic/Customers/Search/CustomerSearchQueryBuilderRule.cs` | | `InitializationRuleBase` (filter defaults) | `Logic/Customers/Search/CustomerSearchFilterInitializationRule.cs` | | `PagingValidationRuleBase` | `Logic/Customers/Validation/CustomerSearchFilterValidationRule.cs` | | Custom `ISortingProvider` | `Logic/Shared/Search/Sorting/SortingProvider.cs` | ### GerstITS.Validation | Feature | Example | |---------|---------| | `ValidationRuleBase` (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()` | `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().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()` + `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 1. **Database**: the API auto-migrates on startup (`AutoMigrate: true`). Adjust the `CustomerDbContext` connection string in `GerstITS.Examples.Api/appsettings.json` (PostgreSQL). 2. **API**: start `GerstITS.Examples.Api`. Swagger UI is available in development at `/api/swagger`. 3. **Console client**: start `GerstITS.Examples.WebClient.Console` while the API is running. 4. **Tests**: `dotnet test` (optionally `--filter "Category=Unit"`). 5. **Migrations**: `dotnet ef migrations add ` inside `GerstITS.Examples.Data` (uses the design time factory and `appsettings.json` of 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 (partial `Endpoints` class, explicit `Endpoints.Validator`, exception transformations applied by `UseGlobalExceptionHandling`). 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:/api/v2.0/customers ``` The response then carries the matching `Content-Encoding` header (e.g. `Content-Encoding: zstd`). > Requires the first `GerstITS.Web.Api` release 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`).