Pragmatic.Abstractions -- Complete Interface Catalog
This document lists every public type in Pragmatic.Abstractions with its full member signatures, organized by domain. For a higher-level overview, see the README.
1. Result
Section titled “1. Result”IError (Pragmatic.Result)
Section titled “IError (Pragmatic.Result)”Base contract for all error types in the Result pattern. Supports HTTP status code mapping and RFC 7807 Problem Details.
public interface IError{ string Code { get; } // Semantic error code, UPPER_SNAKE_CASE (e.g., "NOT_FOUND") int StatusCode { get; } // HTTP status code string Title => string.Empty; // Problem Details title (default: empty) string? Description => null; // Additional context (default: null)}Usage: Extend the Error abstract record in Pragmatic.Result for class-based errors. Implement IError directly only for struct-based errors (e.g., ValidationError). For localized errors, implement ILocalizedError which adds LocalizationKey.
2. Persistence — Entities
Section titled “2. Persistence — Entities”IEntity (Pragmatic.Persistence.Entity)
Section titled “IEntity (Pragmatic.Persistence.Entity)”Marker interface for all entities. No members.
public interface IEntity;IEntity<TId> (Pragmatic.Persistence.Entity)
Section titled “IEntity<TId> (Pragmatic.Persistence.Entity)”Entity with a typed identifier.
public interface IEntity<TId> : IEntity where TId : notnull{ TId PersistenceId { get; } // Unique persistence identifier}IAuditable (Pragmatic.Persistence.Entity)
Section titled “IAuditable (Pragmatic.Persistence.Entity)”Audit tracking for creation and last update.
public interface IAuditable{ DateTimeOffset CreatedAt { get; set; } string? CreatedBy { get; set; } DateTimeOffset? UpdatedAt { get; set; } string? UpdatedBy { get; set; }}The CreatedBy/UpdatedBy fields are populated automatically by the persistence layer using ICurrentUser.IdOrNull().
ISoftDelete (Pragmatic.Persistence.Entity)
Section titled “ISoftDelete (Pragmatic.Persistence.Entity)”Soft-delete support. Entities are not physically removed; instead IsDeleted is set to true.
public interface ISoftDelete{ bool IsDeleted { get; set; } DateTimeOffset? DeletedAt { get; set; } string? DeletedBy { get; set; }}The SG generates a SoftDeleteFilter query filter that automatically excludes soft-deleted entities from queries.
IChangeTracking (Pragmatic.Persistence.Entity)
Section titled “IChangeTracking (Pragmatic.Persistence.Entity)”Property-level change tracking, implemented automatically by the source generator on entities with generated Set{Property} methods.
public interface IChangeTracking{ IReadOnlySet<string> ModifiedProperties { get; } // Modified scalar properties IReadOnlySet<string> CollectionsModified { get; } // Modified collection navigations void ResetModifiedProperties(); // Clear tracking state bool IsNew { get; set; } // True for unsaved entities (all props "modified")}Enables: selective validation (only modified properties), audit trail, optimized persistence (only changed columns).
ITemporalRelation (Pragmatic.Persistence.Entity)
Section titled “ITemporalRelation (Pragmatic.Persistence.Entity)”Time-bounded relationship (e.g., user-role assignment valid from Jan 1 to Jun 30).
public interface ITemporalRelation{ DateTimeOffset ValidFrom { get; set; } DateTimeOffset? ValidTo { get; set; } // Null means currently active (no end date)}Entities implementing this interface get automatic Active() and ActiveAt(date) query extensions.
IEntityFactory<TEntity> (Pragmatic.Persistence.Entity)
Section titled “IEntityFactory<TEntity> (Pragmatic.Persistence.Entity)”Factory for creating entity instances during mutations.
public interface IEntityFactory<out TEntity> where TEntity : class{ TEntity Create();}When registered in DI, the MutationInvoker uses this factory for MutationMode.Create operations. If no factory is registered, it falls back to new TEntity().
3. Persistence — Repositories
Section titled “3. Persistence — Repositories”IReadRepository<TEntity, TId> (Pragmatic.Persistence.Repository)
Section titled “IReadRepository<TEntity, TId> (Pragmatic.Persistence.Repository)”Read-only repository. Uses Specification<T> from Pragmatic.Specification for composable query predicates.
public interface IReadRepository<TEntity, TId> where TEntity : class, IEntity<TId> where TId : notnull{ Task<TEntity?> GetByIdAsync(TId id, CancellationToken ct = default); Task<List<TEntity>> FindAsync(Specification<TEntity> spec, CancellationToken ct = default); Task<int> CountAsync(Specification<TEntity> spec, CancellationToken ct = default); Task<bool> ExistsAsync(Specification<TEntity> spec, CancellationToken ct = default); Task<TEntity?> FirstOrDefaultAsync(Specification<TEntity> spec, CancellationToken ct = default); IQueryable<TEntity> Query();}IRepository<TEntity, TId> (Pragmatic.Persistence.Repository)
Section titled “IRepository<TEntity, TId> (Pragmatic.Persistence.Repository)”Full CRUD repository, extending IReadRepository.
public interface IRepository<TEntity, TId> : IReadRepository<TEntity, TId> where TEntity : class, IEntity<TId> where TId : notnull{ void Add(TEntity entity); void AddRange(IEnumerable<TEntity> entities); void Remove(TEntity entity); void RemoveRange(IEnumerable<TEntity> entities); void Update(TEntity entity);}IUnitOfWork (Pragmatic.Persistence.Repository)
Section titled “IUnitOfWork (Pragmatic.Persistence.Repository)”Unit of Work pattern for transactional persistence.
public interface IUnitOfWork : IDisposable, IAsyncDisposable{ Task<int> SaveChangesAsync(CancellationToken ct = default); void Add(object entity) { } // Default no-op; used by preset providers Task<ITransaction> BeginTransactionAsync(CancellationToken ct = default);}ITransaction (Pragmatic.Persistence.Repository)
Section titled “ITransaction (Pragmatic.Persistence.Repository)”Database transaction handle.
public interface ITransaction : IDisposable, IAsyncDisposable{ Guid TransactionId { get; } Task CommitAsync(CancellationToken ct = default); Task RollbackAsync(CancellationToken ct = default);}4. Identity
Section titled “4. Identity”ICurrentUser (Pragmatic.Identity)
Section titled “ICurrentUser (Pragmatic.Identity)”The currently authenticated user in the request scope. Core contract consumed by persistence (auditing), actions (authorization), and endpoints (permission enforcement).
public interface ICurrentUser{ string Id { get; } // Empty for anonymous users string? DisplayName { get; } // Null for anonymous bool IsAuthenticated { get; } PrincipalKind Kind { get; } // Anonymous, User, Service, System string? TenantId { get; } // Null when not applicable IReadOnlyDictionary<string, IReadOnlyList<string>> Claims { get; } // Multi-valued claims string? ImpersonatedBy { get; } // Impersonator user ID, if any IUserAuthorization Authorization { get; } // Roles, permissions, groups, scopes IAuthenticationContext Authentication { get; } // Scheme, issuer, MFA, expiry}IAuthenticationContext (Pragmatic.Identity)
Section titled “IAuthenticationContext (Pragmatic.Identity)”Authentication metadata. Accessed via ICurrentUser.Authentication.
public interface IAuthenticationContext{ string? Scheme { get; } // e.g., "Bearer", "Cookie" string? Protocol { get; } // e.g., "oidc", "saml2", "apikey" string? Issuer { get; } // e.g., "https://login.example.com" string? Subject { get; } // Subject identifier from IdP bool IsMfaAuthenticated { get; } DateTimeOffset? AuthenticatedAt { get; } DateTimeOffset? ExpiresAt { get; } string? ExternalIdentityKey { get; } // "{issuer}|{subject}" format}IUserProfile (Pragmatic.Identity)
Section titled “IUserProfile (Pragmatic.Identity)”User profile data, generated from [PragmaticUser] entity properties.
public interface IUserProfile{ string? PreferredCulture { get; } // e.g., "it-IT", "en-US" string? TimeZone { get; } // IANA, e.g., "Europe/Rome" IReadOnlyDictionary<string, string?> Properties { get; } // Additional profile properties}PrincipalKind (Pragmatic.Identity)
Section titled “PrincipalKind (Pragmatic.Identity)”public enum PrincipalKind{ Anonymous, // No authenticated identity User, // Human user via identity provider Service, // Service-to-service (API key, client credentials) System // Background jobs, seed, migrations}AnonymousUser (Pragmatic.Identity)
Section titled “AnonymousUser (Pragmatic.Identity)”Singleton ICurrentUser for unauthenticated requests. Id is empty string, IsAuthenticated is false, Authorization returns NullUserAuthorization.Instance, Authentication returns NullAuthenticationContext.Instance.
public static readonly AnonymousUser Instance;NullAuthenticationContext (Pragmatic.Identity)
Section titled “NullAuthenticationContext (Pragmatic.Identity)”Singleton IAuthenticationContext for anonymous/system contexts. All properties return null or false.
public static readonly NullAuthenticationContext Instance;CurrentUserExtensions (Pragmatic.Identity)
Section titled “CurrentUserExtensions (Pragmatic.Identity)”public static class CurrentUserExtensions{ static string? IdOrNull(this ICurrentUser user); static string DisplayNameOrId(this ICurrentUser user); static string? GetClaim(this ICurrentUser user, string type); static IReadOnlyList<string> GetClaims(this ICurrentUser user, string type); static string? GetClaimValue(this ICurrentUser user, string claimType); // Alias for GetClaim static IReadOnlyList<string> GetClaimValues(this ICurrentUser user, string claimType); // Alias for GetClaims}[PragmaticUser] (Pragmatic.Identity)
Section titled “[PragmaticUser] (Pragmatic.Identity)”Marks the application’s user entity. The SG generates a profile adapter (IUserProfile) and a user resolver service.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]public sealed class PragmaticUserAttribute : Attribute{ public string MatchClaim { get; set; } = "sub"; // Claim type for user matching public string? MatchProperty { get; set; } // Entity property for matching (default: ExternalIdentityKey)}[ProfileProperty] (Pragmatic.Identity)
Section titled “[ProfileProperty] (Pragmatic.Identity)”Marks a property on a [PragmaticUser] entity for IUserProfile generation. Well-known names (PreferredCulture, TimeZone) map to dedicated accessors; others go into Properties dictionary.
[AttributeUsage(AttributeTargets.Property)]public sealed class ProfilePropertyAttribute : Attribute;5. Authorization
Section titled “5. Authorization”IUserAuthorization (Pragmatic.Authorization)
Section titled “IUserAuthorization (Pragmatic.Authorization)”Authorization context for the current user. Accessed via ICurrentUser.Authorization.
public interface IUserAuthorization{ IReadOnlyCollection<string> Roles { get; } IReadOnlySet<string> Permissions { get; } // Expanded, cached per request IReadOnlyCollection<string> Groups { get; } IReadOnlyCollection<string> Scopes { get; } // OAuth/OIDC scopes
bool HasPermission(string permission); bool HasAnyPermission(IEnumerable<string> permissions); // OR logic bool HasAllPermissions(IEnumerable<string> permissions); // AND logic bool IsInRole(string role); bool IsInGroup(string group); bool HasScope(string scope);}IPermission (Pragmatic.Authorization)
Section titled “IPermission (Pragmatic.Authorization)”Strongly-typed permission. Each permission is a type with static abstract members.
public interface IPermission{ static abstract string Name { get; } // e.g., "booking.guests.create" static abstract string? Description { get; } static abstract string? Category { get; } // e.g., "Booking"}IRole (Pragmatic.Authorization)
Section titled “IRole (Pragmatic.Authorization)”Strongly-typed role with default permission assignments.
public interface IRole{ static abstract string Name { get; } static abstract string? Description { get; } static abstract IReadOnlyList<string> DefaultPermissions { get; } // Supports wildcards ("booking.*")}IGroup (Pragmatic.Authorization)
Section titled “IGroup (Pragmatic.Authorization)”Strongly-typed group with default role assignments.
public interface IGroup{ static abstract string Name { get; } static abstract string? Description { get; } static abstract IReadOnlyList<string> DefaultRoles { get; }}IRoleDefinition (Pragmatic.Authorization)
Section titled “IRoleDefinition (Pragmatic.Authorization)”Permission template defined by a module. Not an application role. Used as a building block for composing real roles at the host level.
public interface IRoleDefinition{ static abstract string Name { get; } static abstract string? Description { get; } static abstract IReadOnlyList<string> Permissions { get; }}Example composition:
authz.MapRole("operations-manager", r => r .IncludeDefinition<BookingOperator>() .IncludeDefinition<CatalogReader>() .WithoutPermissions(BookingPermissions.Reservation.Delete));IPermissionProvider (Pragmatic.Authorization)
Section titled “IPermissionProvider (Pragmatic.Authorization)”Resolves permissions from external sources. Multiple providers are composed and merged (union).
public interface IPermissionProvider{ int Order { get; } // Convention: 0 = claims, 100 = role expansion, 200 = external ValueTask<IReadOnlySet<string>> ResolvePermissionsAsync(ICurrentUser user, CancellationToken ct = default);}IPermissionChecker (Pragmatic.Authorization)
Section titled “IPermissionChecker (Pragmatic.Authorization)”Async permission checker for scenarios requiring I/O (policy servers, database RBAC).
public interface IPermissionChecker{ ValueTask<bool> HasPermissionAsync(string permission, CancellationToken cancellationToken = default); ValueTask<bool> HasAnyPermissionAsync(IEnumerable<string> permissions, CancellationToken cancellationToken = default); ValueTask<bool> HasAllPermissionsAsync(IEnumerable<string> permissions, CancellationToken cancellationToken = default);}When to use: Use IUserAuthorization (synchronous, in-memory) for simple checks. Use IPermissionChecker when authorization needs API calls or database queries.
IResourceAuthorizer<TResource> (Pragmatic.Authorization)
Section titled “IResourceAuthorizer<TResource> (Pragmatic.Authorization)”Resource-level (ABAC) authorization. Contravariant on TResource.
public interface IResourceAuthorizer<in TResource>{ ValueTask<bool> CanAccessAsync( ICurrentUser user, TResource resource, string action, CancellationToken ct = default);}NullUserAuthorization (Pragmatic.Authorization)
Section titled “NullUserAuthorization (Pragmatic.Authorization)”Singleton. All checks return false, all collections empty.
public static readonly NullUserAuthorization Instance;FullAccessUserAuthorization (Pragmatic.Authorization)
Section titled “FullAccessUserAuthorization (Pragmatic.Authorization)”Singleton. All checks return true. Used for system-level contexts (background jobs, migrations).
public static readonly FullAccessUserAuthorization Instance;PermissionInfo (Pragmatic.Authorization)
Section titled “PermissionInfo (Pragmatic.Authorization)”public sealed record PermissionInfo(string Name, string? Description, string? Category);RoleInfo (Pragmatic.Authorization)
Section titled “RoleInfo (Pragmatic.Authorization)”public sealed record RoleInfo(string Name, string? Description, IReadOnlyList<string> DefaultPermissions);[RequirePermission] (Pragmatic.Authorization)
Section titled “[RequirePermission] (Pragmatic.Authorization)”AND-logic permission enforcement. Applied to endpoints, actions, and mutations.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]public sealed class RequirePermissionAttribute(params string[] permissions) : Attribute{ public string[] Permissions { get; } public string? Description { get; set; } // For SG-generated constants (Mode 2) public string? Category { get; set; } // Category override for generated permission}Mode 1 (enforcement only): [RequirePermission("booking.reservation.create")]
Mode 2 (enforcement + definition): [RequirePermission("refund", Description = "Issue a refund")] — SG derives full name from context.
[RequireAnyPermission] (Pragmatic.Authorization)
Section titled “[RequireAnyPermission] (Pragmatic.Authorization)”OR-logic permission enforcement.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]public sealed class RequireAnyPermissionAttribute(params string[] permissions) : Attribute{ public string[] Permissions { get; }}[ExplicitPermission] / [ExplicitPermission<TPermission>] (Pragmatic.Authorization)
Section titled “[ExplicitPermission] / [ExplicitPermission<TPermission>] (Pragmatic.Authorization)”Overrides the auto-derived permission name.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]public sealed class ExplicitPermissionAttribute(string permission) : Attribute{ public string Permission { get; }}
[AttributeUsage(AttributeTargets.Class, Inherited = false)]public sealed class ExplicitPermissionAttribute<TPermission> : Attribute where TPermission : IPermission;6. Events
Section titled “6. Events”IDomainEvent (Pragmatic.Events)
Section titled “IDomainEvent (Pragmatic.Events)”Marker for domain events.
public interface IDomainEvent{ DateTimeOffset OccurredAt { get; }}Events should be immutable records capturing what happened.
IDomainEventDispatcher (Pragmatic.Events)
Section titled “IDomainEventDispatcher (Pragmatic.Events)”Dispatches events to registered handlers.
public interface IDomainEventDispatcher{ Task DispatchAsync<TEvent>(TEvent @event, CancellationToken ct = default) where TEvent : IDomainEvent; Task DispatchAsync(IEnumerable<IDomainEvent> events, CancellationToken ct = default);}IDomainEventHandler<TEvent> (Pragmatic.Events)
Section titled “IDomainEventHandler<TEvent> (Pragmatic.Events)”Handles a specific event type. Multiple handlers per event type are supported, executed in ascending Order.
public interface IDomainEventHandler<in TEvent> where TEvent : IDomainEvent{ int Order => 0; // Lower = earlier Task HandleAsync(TEvent @event, CancellationToken ct = default);}IHasDomainEvents (Pragmatic.Events)
Section titled “IHasDomainEvents (Pragmatic.Events)”Entity that accumulates domain events for post-persistence dispatch.
public interface IHasDomainEvents{ IReadOnlyList<IDomainEvent> DomainEvents { get; } void ClearDomainEvents();}EntityPropertyChanged<TEntity> (Pragmatic.Events)
Section titled “EntityPropertyChanged<TEntity> (Pragmatic.Events)”Built-in event for property change propagation (cascade handlers).
public sealed record EntityPropertyChanged<TEntity> : IDomainEvent where TEntity : class{ public required object EntityId { get; init; } public required string PropertyName { get; init; } public object? NewValue { get; init; } public object? OldValue { get; init; } public DateTimeOffset OccurredAt { get; init; } = DateTimeOffset.UtcNow;}7. Temporal
Section titled “7. Temporal”IClock (Pragmatic.Temporal.Clock)
Section titled “IClock (Pragmatic.Temporal.Clock)”Testable time abstraction wrapping TimeProvider for .NET 8+ interop.
public interface IClock{ DateTimeOffset UtcNow { get; } DateTimeOffset Now { get; } DateOnly UtcToday { get; } DateOnly Today { get; } TimeOnly UtcTimeOfDay { get; } TimeOnly TimeOfDay { get; } TimeProvider GetTimeProvider();}8. Multi-Tenancy
Section titled “8. Multi-Tenancy”ITenantContext (Pragmatic.MultiTenancy)
Section titled “ITenantContext (Pragmatic.MultiTenancy)”Current tenant identity, scoped per request.
public interface ITenantContext{ string? TenantId { get; } string? TenantName { get; } bool IsResolved { get; }}ITenantResolver (Pragmatic.MultiTenancy)
Section titled “ITenantResolver (Pragmatic.MultiTenancy)”Transport-agnostic tenant resolution.
public interface ITenantResolver{ ValueTask<string?> ResolveAsync(CancellationToken cancellationToken = default);}Resolution strategies: HTTP header, subdomain, JWT claim, API key, route parameter.
ITenantEntity (Pragmatic.MultiTenancy)
Section titled “ITenantEntity (Pragmatic.MultiTenancy)”Marker for row-level tenant isolation.
public interface ITenantEntity{ string TenantId { get; set; } // Set automatically on creation, filtered on read}UnresolvedTenantContext (Pragmatic.MultiTenancy)
Section titled “UnresolvedTenantContext (Pragmatic.MultiTenancy)”Singleton fallback. All properties null, IsResolved is false.
public static readonly UnresolvedTenantContext Instance;9. Caching
Section titled “9. Caching”ICacheStack (Pragmatic.Caching)
Section titled “ICacheStack (Pragmatic.Caching)”Unified caching abstraction with stampede protection and tag-based invalidation. Default implementation: HybridCacheStack in Pragmatic.Caching (L1 memory + L2 distributed via Microsoft.Extensions.Caching.Hybrid).
public interface ICacheStack{ ValueTask<T> GetOrSetAsync<T>(string key, Func<CancellationToken, ValueTask<T>> factory, CacheEntryOptions? options = null, CancellationToken ct = default);
ValueTask<T?> GetAsync<T>(string key, CancellationToken ct = default);
ValueTask<(bool Found, T? Value)> TryGetAsync<T>(string key, CancellationToken ct = default);
ValueTask SetAsync<T>(string key, T value, CacheEntryOptions? options = null, CancellationToken ct = default);
ValueTask RemoveAsync(string key, CancellationToken ct = default);
ValueTask InvalidateByTagAsync(string tag, CancellationToken ct = default); ValueTask InvalidateByTagsAsync(IEnumerable<string> tags, CancellationToken ct = default);}CacheEntryOptions (Pragmatic.Caching)
Section titled “CacheEntryOptions (Pragmatic.Caching)”Options for a cache entry including duration, tags, and eviction priority.
public sealed class CacheEntryOptions{ public TimeSpan? Duration { get; init; } public TimeSpan? SlidingDuration { get; init; } public ImmutableArray<string> Tags { get; init; } = []; public CachePriority Priority { get; init; } = CachePriority.Normal;
public static CacheEntryOptions Default { get; } // 5 min duration public static CacheEntryOptions WithDuration(TimeSpan duration); public static CacheEntryOptions WithSliding(TimeSpan slidingDuration);}CachePriority (Pragmatic.Caching)
Section titled “CachePriority (Pragmatic.Caching)”Eviction priority under memory pressure.
public enum CachePriority{ Low = 0, // First to be evicted Normal = 1, // Default High = 2, // Less likely to be evicted NeverRemove = 3 // Never auto-evicted (use sparingly)}CacheCategories (Pragmatic.Caching)
Section titled “CacheCategories (Pragmatic.Caching)”Predefined category marker types for routing cache operations to different backends or configurations. Each nested sealed class is used as a generic type parameter with CachingBuilder.ForCategory<T>() and CacheStackProvider.ForCategory<T>().
public static class CacheCategories{ public sealed class Default; // General-purpose business cache public sealed class OutputCache; // ASP.NET Core HTTP response caching public sealed class RateLimiting; // Cross-instance rate limit counters public sealed class Permissions; // Authorization permission set caching public sealed class Configuration; // Remote configuration value caching}Custom categories are defined as additional sealed marker classes.
10. Configuration
Section titled “10. Configuration”IConfigurationStore (Pragmatic.Configuration)
Section titled “IConfigurationStore (Pragmatic.Configuration)”Backend-agnostic configuration store with tenant-scoped overrides and change watching.
public interface IConfigurationStore{ Task<string?> GetAsync(string key, CancellationToken ct = default); Task<string?> GetAsync(string key, string tenantId, CancellationToken ct = default); Task<IReadOnlyDictionary<string, string>> GetSectionAsync(string prefix, CancellationToken ct = default); Task<IReadOnlyDictionary<string, string>> GetSectionAsync(string prefix, string tenantId, CancellationToken ct = default); Task SetAsync(string key, string value, string? tenantId = null, CancellationToken ct = default); Task DeleteAsync(string key, string? tenantId = null, CancellationToken ct = default); IAsyncEnumerable<ConfigurationChange> WatchAsync(string keyPattern, CancellationToken ct = default);}ISecretStore (Pragmatic.Configuration)
Section titled “ISecretStore (Pragmatic.Configuration)”Read-only store for secrets (vault, CI/CD, user-secrets).
public interface ISecretStore{ Task<string?> GetSecretAsync(string key, CancellationToken ct = default); Task<string?> GetSecretAsync(string key, string tenantId, CancellationToken ct = default);}ConfigurationChange (Pragmatic.Configuration)
Section titled “ConfigurationChange (Pragmatic.Configuration)”public sealed record ConfigurationChange( string Key, string? OldValue, string? NewValue, string? TenantId, DateTimeOffset Timestamp);EnvironmentProfile (Pragmatic.Configuration)
Section titled “EnvironmentProfile (Pragmatic.Configuration)”Wraps IHostEnvironment with Pragmatic conventions.
public sealed class EnvironmentProfile{ public required string Name { get; init; } // e.g., "Development", "Production" public string? Tag { get; init; } // e.g., "eu-west", "canary" public IReadOnlyList<string> ResolutionChain { get; init; } // e.g., ["base", "staging", "staging-eu-west"]
public bool IsDevelopment { get; } public bool IsStaging { get; } public bool IsProduction { get; } public bool IsTesting { get; } public bool IsEnvironment(string environmentName);
public static EnvironmentProfile From(string environmentName, string? tag = null);}11. Feature Flags
Section titled “11. Feature Flags”IFeatureFlag (Pragmatic.FeatureFlags)
Section titled “IFeatureFlag (Pragmatic.FeatureFlags)”Strongly-typed feature flag marker.
public interface IFeatureFlag{ static abstract string Name { get; } static abstract string? Description { get; }}IFeatureFlagStore (Pragmatic.FeatureFlags)
Section titled “IFeatureFlagStore (Pragmatic.FeatureFlags)”Evaluation-aware flag store with context-based targeting.
public interface IFeatureFlagStore{ Task<bool> IsEnabledAsync(string flagName, CancellationToken ct = default); Task<bool> IsEnabledAsync(string flagName, FeatureFlagContext context, CancellationToken ct = default); Task<FeatureFlagDefinition?> GetDefinitionAsync(string flagName, CancellationToken ct = default); Task<IReadOnlyList<FeatureFlagDefinition>> GetAllAsync(CancellationToken ct = default); IAsyncEnumerable<FeatureFlagChange> WatchAsync(CancellationToken ct = default);}IFeatureFlagContextProvider (Pragmatic.FeatureFlags)
Section titled “IFeatureFlagContextProvider (Pragmatic.FeatureFlags)”Builds evaluation context from ambient state.
public interface IFeatureFlagContextProvider{ Task<FeatureFlagContext> GetContextAsync(CancellationToken ct = default);}FeatureFlagContext (Pragmatic.FeatureFlags)
Section titled “FeatureFlagContext (Pragmatic.FeatureFlags)”public sealed record FeatureFlagContext{ public string? TenantId { get; init; } public string? UserId { get; init; } public string? Plan { get; init; } public string? Environment { get; init; } public IReadOnlyDictionary<string, string> Properties { get; init; } public static FeatureFlagContext Empty { get; }}FeatureFlagDefinition (Pragmatic.FeatureFlags)
Section titled “FeatureFlagDefinition (Pragmatic.FeatureFlags)”public sealed record FeatureFlagDefinition{ public required string Name { get; init; } public bool Enabled { get; init; } public string? Description { get; init; } public IReadOnlyList<FeatureFlagRule> Rules { get; init; }}FeatureFlagRule (Pragmatic.FeatureFlags)
Section titled “FeatureFlagRule (Pragmatic.FeatureFlags)”Defined in FeatureFlagDefinition.cs alongside FeatureFlagDefinition.
public sealed record FeatureFlagRule{ public required string Type { get; init; } // "tenant", "user", "plan", "percentage", "property" public IReadOnlyList<string> Values { get; init; } public bool Enabled { get; init; } = true;}FeatureFlagChange (Pragmatic.FeatureFlags)
Section titled “FeatureFlagChange (Pragmatic.FeatureFlags)”public sealed record FeatureFlagChange( string FlagName, bool WasEnabled, bool IsEnabled, DateTimeOffset Timestamp);FeatureFlagStoreExtensions (Pragmatic.FeatureFlags)
Section titled “FeatureFlagStoreExtensions (Pragmatic.FeatureFlags)”public static class FeatureFlagStoreExtensions{ static Task<bool> IsEnabledAsync<TFlag>(this IFeatureFlagStore store, CancellationToken ct = default); static Task<bool> IsEnabledAsync<TFlag>(this IFeatureFlagStore store, FeatureFlagContext context, CancellationToken ct = default); static Task<FeatureFlagDefinition?> GetDefinitionAsync<TFlag>(this IFeatureFlagStore store, CancellationToken ct = default);}12. Internationalization
Section titled “12. Internationalization”IGlobalizationContext (Pragmatic.Internationalization.Context)
Section titled “IGlobalizationContext (Pragmatic.Internationalization.Context)”Current globalization context for formatting operations.
public interface IGlobalizationContext{ CultureInfo Culture { get; } TimeZoneInfo? TimeZone => null; // Null falls back to UTC string? CurrencyCode => null; // e.g., "EUR", "USD"; null derives from culture}13. Pipeline
Section titled “13. Pipeline”ICallContext (Pragmatic.Pipeline)
Section titled “ICallContext (Pragmatic.Pipeline)”Tracks whether the current execution is system-initiated (internal call). When IsInternalCall is true, authorization filters skip permission checks. Event handlers automatically run as internal calls.
public interface ICallContext{ bool IsInternalCall { get; } IDisposable EnterInternalCall(); // Returns disposable that restores previous state; supports nesting}14. Composition
Section titled “14. Composition”IPragmaticBuilder (Pragmatic.Composition)
Section titled “IPragmaticBuilder (Pragmatic.Composition)”Fluent builder for configuring module strategies at startup.
public interface IPragmaticBuilder{ IServiceCollection Services { get; } IConfiguration Configuration { get; } IHostEnvironment Environment { get; }}Each module contributes Use*() extension methods on this interface (e.g., UseMultiTenancy, UseAuthentication).
IPackageDefinition (Pragmatic.Composition)
Section titled “IPackageDefinition (Pragmatic.Composition)”Defines a reusable package that can be imported into a module via [UsePackage<T>].
public interface IPackageDefinition{ static abstract string PackageName { get; } static abstract string? RoutePrefix { get; } static abstract string? Description { get; } static virtual IReadOnlyList<string> RequiredTypeNames => [];}ServiceCollectionDecorateExtensions (Pragmatic.Composition.Extensions)
Section titled “ServiceCollectionDecorateExtensions (Pragmatic.Composition.Extensions)”Decorator support for IServiceCollection.
public static class ServiceCollectionDecorateExtensions{ static IServiceCollection Decorate<TService, TDecorator>(this IServiceCollection services); static IServiceCollection Decorate(this IServiceCollection services, Type serviceType, Type decoratorType); static IServiceCollection Decorate<TService>(this IServiceCollection services, Func<TService, IServiceProvider, TService> decorator);}PragmaticDatabase (Pragmatic.Composition.Database)
Section titled “PragmaticDatabase (Pragmatic.Composition.Database)”Abstract base class for database declarations.
public abstract class PragmaticDatabase{ public virtual IEnumerable<string> GetRequiredConfigKeys();}15. Composition Attributes
Section titled “15. Composition Attributes”All in Pragmatic.Composition.Attributes. See the README for a summary table. Full signatures:
[Module]
Section titled “[Module]”public sealed class ModuleAttribute : Attribute{ public string? Name { get; set; } public string[] DependsOn { get; set; } public string? Version { get; set; } public string? Description { get; set; }}[Service] / [Service<TInterface>]
Section titled “[Service] / [Service<TInterface>]”public sealed class ServiceAttribute : Attribute{ public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Scoped; public Type? As { get; set; } public bool AsSelf { get; set; } public string? Key { get; set; }}
public sealed class ServiceAttribute<TInterface> : Attribute where TInterface : class{ public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Scoped; public string? Key { get; set; }}[Decorator]
Section titled “[Decorator]”public sealed class DecoratorAttribute : Attribute{ public int Order { get; set; }}[Inject]
Section titled “[Inject]”public sealed class InjectAttribute : Attribute{ public bool Required { get; set; } public string? Key { get; set; }}[ServiceFactory] / [Factory]
Section titled “[ServiceFactory] / [Factory]”public sealed class ServiceFactoryAttribute : Attribute;
public sealed class FactoryAttribute : Attribute{ public ServiceLifetime Lifetime { get; set; } = ServiceLifetime.Scoped;}[Include<...>] (3 overloads)
Section titled “[Include<...>] (3 overloads)”public sealed class IncludeAttribute<TModule> : Attribute;public sealed class IncludeAttribute<TModule, TDatabase> : Attribute;public sealed class IncludeAttribute<TModule, TDatabase, TDbContext> : Attribute;[IncludeModule<TModule>]
Section titled “[IncludeModule<TModule>]”public sealed class IncludeModuleAttribute<TModule> : Attribute;public sealed class IncludeModuleAttribute : Attribute { public Type ModuleType { get; } }[DependsOn<TModule>] (Deprecated)
Section titled “[DependsOn<TModule>] (Deprecated)”Use [IncludeModule<T>] instead. Both generic and non-generic forms exist for backward compatibility.
[Obsolete("Use [IncludeModule<T>] instead.")]public sealed class DependsOnAttribute<TModule> : Attribute where TModule : class;
[Obsolete("Use [IncludeModule(typeof(T))] instead.")]public sealed class DependsOnAttribute : Attribute{ public Type ModuleType { get; }}[StartupStep]
Section titled “[StartupStep]”public sealed class StartupStepAttribute : Attribute;[PragmaticDatabase]
Section titled “[PragmaticDatabase]”public sealed class PragmaticDatabaseAttribute : Attribute{ public DatabaseProvider Provider { get; set; } public string ConfigKey { get; set; }}[RequiresConfig]
Section titled “[RequiresConfig]”public sealed class RequiresConfigAttribute : Attribute{ public string SectionPath { get; } public string? Description { get; set; }}[UsePackage<TPackage>]
Section titled “[UsePackage<TPackage>]”public sealed class UsePackageAttribute<TPackage> : Attribute where TPackage : class, IPackageDefinition{ public string? RoutePrefix { get; set; }}[RemoteBoundary<TModule>]
Section titled “[RemoteBoundary<TModule>]”public sealed class RemoteBoundaryAttribute<TModule> : Attribute where TModule : class{ public string? BaseUrl { get; set; }}[PragmaticMetadata]
Section titled “[PragmaticMetadata]”[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]public sealed class PragmaticMetadataAttribute : Attribute{ public MetadataCategory Category { get; } public string SchemaVersion { get; } public string JsonData { get; }}16. Composition Enums
Section titled “16. Composition Enums”ServiceLifetime (Pragmatic.Composition.Attributes)
Section titled “ServiceLifetime (Pragmatic.Composition.Attributes)”public enum ServiceLifetime { Singleton = 0, Scoped = 1, Transient = 2 }DatabaseProvider (Pragmatic.Composition.Enums)
Section titled “DatabaseProvider (Pragmatic.Composition.Enums)”public enum DatabaseProvider { SqlServer, PostgreSql, SQLite, MySql, InMemory }MetadataCategory (Pragmatic.Composition.Metadata)
Section titled “MetadataCategory (Pragmatic.Composition.Metadata)”public enum MetadataCategory{ DI = 0, Mapping = 1, Actions = 2, Startup = 3, Validation = 4, Endpoints = 5, HealthChecks = 6, Identifiers = 7, Module = 8, Translations = 9, Persistence = 10, EventHandlers = 11, HostTopology = 12, Caching = 13, Configuration = 14}17. Telemetry
Section titled “17. Telemetry”ActivityHelper (Pragmatic.Telemetry)
Section titled “ActivityHelper (Pragmatic.Telemetry)”Extension methods for System.Diagnostics.Activity.
public static class ActivityHelper{ static Activity? RecordException(this Activity? activity, Exception ex); static Activity? SetSuccess(this Activity? activity); static Activity? SetFailure(this Activity? activity, string errorCode, string? description = null); static Activity? AddNamedEvent(this Activity? activity, string name, params KeyValuePair<string, object?>[] tags);}TelemetryOptions (Pragmatic.Telemetry)
Section titled “TelemetryOptions (Pragmatic.Telemetry)”public sealed class TelemetryOptions{ public bool Enabled { get; set; } = true; public bool Tracing { get; set; } = true; public bool Metrics { get; set; } = true; public bool Logging { get; set; } = true; public bool UseOtlpExporter { get; set; } // Default false; console in Development public string? ServiceName { get; set; } // Null = assembly name public double SamplingRatio { get; set; } = 0.1; // 10% in production, always 1.0 in dev}Telemetry Convention Classes (Pragmatic.Telemetry.Conventions)
Section titled “Telemetry Convention Classes (Pragmatic.Telemetry.Conventions)”| Class | Tag Constants |
|---|---|
ErrorTags | Type, Message, Stacktrace |
ActionTags | Name, Kind, Result, ErrorCode, MutationMode, EntityType, FilterCount |
DbTags | System, Operation, CollectionName, RowsAffected, BulkBatchSize, FilterCount, FilterMode |
CacheTags | Hit, Key, Operation, Tags |
ResilienceTags | Policy, Attempt, Outcome, CircuitState |
EventTags | Name, Handler, HandlerCount |
I18NTags | UICulture, DataCulture, Currency, TimeZone, Source, RequestedCulture, ResolvedCulture, ValidationResult, ProviderName, ProviderPriority, LocalizationKey, LocalizationCulture, FallbackUsed, Missing, Count, PluralCategory, FilePath, StringsCount, PluralsCount |