This is the API specification for Port interfaces, Adapter implementation base classes, the Specification pattern, DI registration, and source generator attributes provided by the Functorium framework. For design principles and implementation guides, see Port Architecture and Definitions and Adapter Implementation .
Type Namespace Description IObservablePortFunctorium.Abstractions.ObservabilitiesBase interface for all Ports/Adapters (provides Observability category) IRepository<TAggregate, TId>Functorium.Domains.RepositoriesAggregate Root level Repository CRUD contract IQueryPortFunctorium.Applications.QueriesNon-generic QueryPort marker interface IQueryPort<TEntity, TDto>Functorium.Applications.QueriesSpecification-based query + pagination contract PageRequestFunctorium.Applications.QueriesOffset-based pagination request PagedResult<T>Functorium.Applications.QueriesOffset-based pagination result CursorPageRequestFunctorium.Applications.QueriesKeyset(Cursor)-based pagination request CursorPagedResult<T>Functorium.Applications.QueriesKeyset(Cursor)-based pagination result SortExpressionFunctorium.Applications.QueriesMulti-field sort expression SortFieldFunctorium.Applications.QueriesSort field + direction pair SortDirectionFunctorium.Applications.QueriesSort direction SmartEnum (Ascending, Descending) Specification<T>Functorium.Domains.SpecificationsSpecification pattern abstract base class ExpressionSpecification<T>Functorium.Domains.SpecificationsExpression Tree-based Specification abstract class IExpressionSpec<T>Functorium.Domains.SpecificationsInterface indicating Expression Tree provision capability PropertyMap<TEntity, TModel>Functorium.Domains.Specifications.ExpressionsEntity-Model Expression auto-conversion property mapping SpecificationExpressionResolverFunctorium.Domains.Specifications.ExpressionsUtility for extracting/composing Expression Trees from Specifications EfCoreRepositoryBase<TAggregate, TId, TModel>Functorium.Adapters.RepositoriesEF Core Repository common base class InMemoryRepositoryBase<TAggregate, TId>Functorium.Adapters.RepositoriesInMemory Repository common base class DapperQueryBase<TEntity, TDto>Functorium.Adapters.RepositoriesDapper-based QueryAdapter common base class InMemoryQueryBase<TEntity, TDto>Functorium.Adapters.RepositoriesInMemory QueryAdapter common base class DapperSpecTranslator<TEntity>Functorium.Adapters.RepositoriesSpecification to SQL WHERE clause translation registry IHasStringIdFunctorium.Adapters.RepositoriesCommon string Id interface for EF Core models ObservablePortRegistrationFunctorium.Abstractions.RegistrationsObservable Port DI registration extension methods OptionsConfiguratorFunctorium.Adapters.Abstractions.OptionsFluentValidation-based options validation registration GenerateObservablePortAttributeFunctorium.Adapters.SourceGeneratorsObservable wrapper auto-generation attribute ObservablePortIgnoreAttributeFunctorium.Adapters.SourceGeneratorsObservable wrapper generation exclusion attribute
The base interface implemented by all Ports and Adapters. Identifies the request category in the Observability layer through the RequestCategory property.
namespace Functorium . Abstractions . Observabilities ;
public interface IObservablePort
string RequestCategory { get ; }
Property Type Description RequestCategorystringCategory used in observability logs/metrics (e.g., "Repository", "ExternalApi", "Messaging")
├── IRepository<TAggregate, TId> — Aggregate Root CRUD (Domain Layer)
├── IQueryPort — Non-generic marker (Application Layer)
│ └── IQueryPort<TEntity, TDto> — Specification-based query (Application Layer)
└── (User-defined Port) — External API, Messaging, etc.
Inheriting IObservablePort enables the [GenerateObservablePort] source generator to auto-generate Tracing, Logging, and Metrics.
A persistence contract at the Aggregate Root level. Generic constraints enforce Aggregate Root-level persistence at compile time.
namespace Functorium . Domains . Repositories ;
public interface IRepository<TAggregate, TId> : IObservablePort
where TAggregate : AggregateRoot<TId>
where TId : struct , IEntityId<TId>
FinT<IO, TAggregate> Create (TAggregate aggregate);
FinT<IO, TAggregate> GetById (TId id);
FinT<IO, TAggregate> Update (TAggregate aggregate);
FinT<IO, int > Delete (TId id);
FinT<IO, Seq<TAggregate>> CreateRange (IReadOnlyList<TAggregate> aggregates);
FinT<IO, Seq<TAggregate>> GetByIds (IReadOnlyList<TId> ids);
FinT<IO, Seq<TAggregate>> UpdateRange (IReadOnlyList<TAggregate> aggregates);
FinT<IO, int > DeleteRange (IReadOnlyList<TId> ids);
Type Parameter Constraint Description TAggregateAggregateRoot<TId>Only Aggregate Roots can be Repository targets (prevents direct Entity persistence) TIdstruct, IEntityId<TId>Ulid-based EntityId implementation type
Method Return Type Description Create(aggregate)FinT<IO, TAggregate>Creates a single Aggregate GetById(id)FinT<IO, TAggregate>Retrieves an Aggregate by ID (NotFound error if absent) Update(aggregate)FinT<IO, TAggregate>Updates a single Aggregate Delete(id)FinT<IO, int>Deletes an Aggregate by ID (returns deleted count) CreateRange(aggregates)FinT<IO, Seq<TAggregate>>Batch creation GetByIds(ids)FinT<IO, Seq<TAggregate>>Batch retrieval (PartialNotFound error if some are missing) UpdateRange(aggregates)FinT<IO, Seq<TAggregate>>Batch update DeleteRange(ids)FinT<IO, int>Batch deletion (returns deleted count)
All methods return FinT<IO, T>. Success is expressed as Fin.Succ(value), and failure is expressed as domain/adapter errors.
A read-only port for Specification-based queries and direct DTO returns. Corresponds to the Read model in CQRS.
namespace Functorium . Applications . Queries ;
public interface IQueryPort : IObservablePort { }
A non-generic marker interface used for runtime type checking, DI scanning, and generic constraints.
public interface IQueryPort<TEntity, TDto> : IQueryPort
FinT<IO, PagedResult<TDto>> Search (
Specification<TEntity> spec,
FinT<IO, CursorPagedResult<TDto>> SearchByCursor (
Specification<TEntity> spec,
CursorPageRequest cursor,
IAsyncEnumerable<TDto> Stream (
Specification<TEntity> spec,
CancellationToken cancellationToken = default );
Method Return Type Description Search(spec, page, sort)FinT<IO, PagedResult<TDto>>Offset-based pagination search SearchByCursor(spec, cursor, sort)FinT<IO, CursorPagedResult<TDto>>Keyset(Cursor)-based pagination search. O(1) performance for deep pages Stream(spec, sort, ct)IAsyncEnumerable<TDto>Streaming query for large data. Yields without loading everything into memory
Type Parameter Description TEntityDomain entity type (Specification target) TDtoReturn DTO type (directly returned to presentation layer)
An offset-based pagination request. This is an Application-level query concern, not a domain invariant.
namespace Functorium . Applications . Queries ;
public sealed record PageRequest
public const int DefaultPageSize = 20 ;
public const int MaxPageSize = 10_000 ;
public int PageSize { get ; }
public int Skip => (Page - 1 ) * PageSize;
public PageRequest ( int page = 1 , int pageSize = DefaultPageSize);
Property/Constant Type Description DefaultPageSizeintDefault page size (20) MaxPageSizeintMaximum page size (10,000) PageintCurrent page number (corrected to 1 if less than 1) PageSizeintPage size (corrected to DefaultPageSize if less than 1, capped at MaxPageSize) SkipintNumber of items to skip (computed property: (Page - 1) * PageSize)
An offset-based pagination result container.
public sealed record PagedResult <T>(
public int TotalPages => ( int ) Math . Ceiling (( double )TotalCount / PageSize);
public bool HasPreviousPage => Page > 1 ;
public bool HasNextPage => Page < TotalPages;
Property Type Description ItemsIReadOnlyList<T>List of items for the current page TotalCountintTotal number of items PageintCurrent page number PageSizeintPage size TotalPagesintTotal number of pages (computed property) HasPreviousPageboolWhether a previous page exists HasNextPageboolWhether a next page exists
A keyset(cursor)-based pagination request. Provides O(1) performance for deep pages compared to offset-based pagination.
public sealed record CursorPageRequest
public const int DefaultPageSize = 20 ;
public const int MaxPageSize = 10_000 ;
public string ? After { get ; }
public string ? Before { get ; }
public int PageSize { get ; }
public CursorPageRequest (
int pageSize = DefaultPageSize);
Property/Constant Type Description DefaultPageSizeintDefault page size (20) MaxPageSizeintMaximum page size (10,000) Afterstring?Retrieve items after this cursor (forward pagination) Beforestring?Retrieve items before this cursor (backward pagination) PageSizeintPage size (corrected to DefaultPageSize if less than 1, capped at MaxPageSize)
A keyset(cursor)-based pagination result container.
public sealed record CursorPagedResult <T>(
Property Type Description ItemsIReadOnlyList<T>List of items for the current page NextCursorstring?Next page cursor (null if no more items) PrevCursorstring?Previous page cursor HasMoreboolWhether more pages exist
A multi-field sort expression. Combines sort conditions via Fluent API.
public sealed class SortExpression
public Seq<SortField> Fields { get ; }
public bool IsEmpty { get ; }
public static SortExpression Empty { get ; }
public static SortExpression By ( string fieldName);
public static SortExpression By ( string fieldName, SortDirection direction);
public SortExpression ThenBy ( string fieldName);
public SortExpression ThenBy ( string fieldName, SortDirection direction);
Member Type Description FieldsSeq<SortField>List of sort fields (applied in order) IsEmptyboolWhether sort conditions are empty EmptySortExpressionNo sorting (static property) By(fieldName)SortExpressionCreates single field ascending sort (static factory) By(fieldName, direction)SortExpressionCreates single field + direction sort (static factory) ThenBy(fieldName)SortExpressionChains additional sort field (ascending) ThenBy(fieldName, direction)SortExpressionChains additional sort field + direction
A pair of sort field and direction.
public sealed record SortField ( string FieldName, SortDirection Direction);
Property Type Description FieldNamestringField name to sort by DirectionSortDirectionSort direction
A SmartEnum representing sort direction.
public sealed class SortDirection : SmartEnum<SortDirection, string >
public static readonly SortDirection Ascending; // Value: "asc"
public static readonly SortDirection Descending; // Value: "desc"
public static SortDirection Parse ( string ? value);
Member Value Description Ascending"asc"Ascending order Descending"desc"Descending order Parse(value)- Parses "asc"/"desc" case-insensitively. Returns Ascending for null/empty string
An abstract base class that encapsulates domain conditions and supports And/Or/Not composition.
namespace Functorium . Domains . Specifications ;
public abstract class Specification <T>
public static Specification<T> All { get ; }
public virtual bool IsAll => false ;
public abstract bool IsSatisfiedBy (T entity);
public Specification<T> And (Specification<T> other);
public Specification<T> Or (Specification<T> other);
public Specification<T> Not ();
public static Specification<T> operator & (Specification<T> left, Specification<T> right);
public static Specification<T> operator | (Specification<T> left, Specification<T> right);
public static Specification<T> operator ! (Specification<T> spec);
Member Type Description AllSpecification<T>Specification satisfied by all entities (Null Object). All & X = X IsAllboolWhether this Specification is the identity element (All) IsSatisfiedBy(entity)boolChecks whether the entity satisfies the condition And(other)Specification<T>AND composition Or(other)Specification<T>OR composition Not()Specification<T>NOT negation
Operator overloading:
Operator Equivalent Method Description &And()AND composition. Includes All identity optimization (All & X = X) |Or()OR composition !Not()NOT negation
An Expression Tree-based Specification abstract class. Implementing ToExpression() automatically provides IsSatisfiedBy().
public abstract class ExpressionSpecification <T> : Specification<T>, IExpressionSpec<T>
public abstract Expression<Func<T, bool >> ToExpression ();
public sealed override bool IsSatisfiedBy (T entity); // Expression compile + caching
Member Description ToExpression()Returns the condition as Expression<Func<T, bool>> (must be implemented by subclass) IsSatisfiedBy(entity)Compiles and evaluates the Expression. Compiled delegate is cached (sealed)
An interface indicating that a Specification can provide an Expression Tree. Used by LINQ providers such as EF Core for automatic SQL translation.
namespace Functorium . Domains . Specifications ;
public interface IExpressionSpec<T>
Expression<Func<T, bool >> ToExpression ();
Property mapping for auto-converting Entity Expression to Model Expression. Used in EfCoreRepositoryBase’s BuildQuery() method for Specification to SQL conversion.
namespace Functorium . Domains . Specifications . Expressions ;
public sealed class PropertyMap <TEntity, TModel>
public PropertyMap<TEntity, TModel> Map <TValue, TModelValue>(
Expression<Func<TEntity, TValue>> entityProp,
Expression<Func<TModel, TModelValue>> modelProp);
public string ? TranslateFieldName ( string entityFieldName);
public Expression<Func<TModel, bool >> Translate (Expression<Func<TEntity, bool >> expression);
Method Return Type Description Map(entityProp, modelProp)PropertyMap<TEntity, TModel>Registers Entity-Model property mapping. Fluent API TranslateFieldName(name)string?Translates Entity field name to Model field name (null if no mapping) Translate(expression)Expression<Func<TModel, bool>>Converts Entity Expression to Model Expression
Supported Entity property expressions:
Form Example Direct member access p => p.NameType conversion p => (decimal)p.PriceToString() callp => p.Id.ToString()
A utility that extracts Expression Trees from Specifications and recursively composes And/Or/Not combinations.
namespace Functorium . Domains . Specifications . Expressions ;
public static class SpecificationExpressionResolver
public static Expression<Func<T, bool >>? TryResolve <T>(Specification<T> spec);
Method Return Type Description TryResolve(spec)Expression<Func<T, bool>>?Extracts Expression from Specification. Direct extraction for IExpressionSpec implementations, recursive composition for And/Or/Not combinations. Returns null if unsupported
Common base class for EF Core Repositories. Includes declared in the constructor are automatically applied to all read queries through ReadQuery(), structurally preventing N+1 problems.
namespace Functorium . Adapters . Repositories ;
public abstract class EfCoreRepositoryBase <TAggregate, TId, TModel>
: IRepository<TAggregate, TId>
where TAggregate : AggregateRoot<TId>
where TId : struct , IEntityId<TId>
where TModel : class , IHasStringId
protected EfCoreRepositoryBase (
IDomainEventCollector eventCollector,
Func<IQueryable<TModel>, IQueryable<TModel>>? applyIncludes = null ,
PropertyMap<TAggregate, TModel>? propertyMap = null );
Type Parameter Constraint Description TAggregateAggregateRoot<TId>Aggregate Root type TIdstruct, IEntityId<TId>Ulid-based EntityId type TModelclass, IHasStringIdEF Core entity model (string Id required)
Parameter Type Description eventCollectorIDomainEventCollectorDomain event collector applyIncludesFunc<IQueryable<TModel>, IQueryable<TModel>>?Navigation Property Include declaration (N+1 prevention). No Includes if null propertyMapPropertyMap<TAggregate, TModel>?Mapping for Specification to Model Expression conversion. Required when using BuildQuery/ExistsBySpec
Member Type Description DbContextDbContextEF Core DbContext (abstract property) DbSetDbSet<TModel>Entity model’s DbSet (abstract property) ToDomain(model)TAggregateModel to Domain mapping (abstract method) ToModel(aggregate)TModelDomain to Model mapping (abstract method)
Member Type Description EventCollectorIDomainEventCollectorDomain event collector PropertyMapPropertyMap<TAggregate, TModel>?Specification to Model property mapping IdBatchSizeint (virtual, default 500)Batch size for preventing SQL IN clause parameter limit ReadQuery()IQueryable<TModel>Read-only query with Includes auto-applied (AsNoTracking) ReadQueryIgnoringFilters()IQueryable<TModel>Read query with Includes + global filter bypass (for Soft Delete queries) BuildQuery(spec)Fin<IQueryable<TModel>>Specification to Model Expression query builder (PropertyMap required) ExistsBySpec(spec)FinT<IO, bool>Specification-based existence check (PropertyMap required) ByIdPredicate(id)Expression<Func<TModel, bool>>Single ID matching Expression (virtual, default IHasStringId-based implementation) ByIdsPredicate(ids)Expression<Func<TModel, bool>>Multiple ID matching Expression (virtual, default IHasStringId-based implementation)
Method Description NotFoundError(id)Creates AdapterErrorType.NotFound error. Actual subclass name is included in the error code PartialNotFoundError(requestedIds, foundAggregates)Creates AdapterErrorType.PartialNotFound error. Includes list of missing IDs NotConfiguredError(message)Creates AdapterErrorType.NotConfigured error NotSupportedError(currentValue, message)Creates AdapterErrorType.NotSupported error
String Id interface that EF Core models must implement. Provides default implementation for EfCoreRepositoryBase’s ByIdPredicate/ByIdsPredicate.
namespace Functorium . Adapters . Repositories ;
public interface IHasStringId
Common base class for InMemory Repositories. Provides default implementation of full IRepository CRUD based on ConcurrentDictionary.
namespace Functorium . Adapters . Repositories ;
public abstract class InMemoryRepositoryBase <TAggregate, TId>
: IRepository<TAggregate, TId>
where TAggregate : AggregateRoot<TId>
where TId : struct , IEntityId<TId>
protected InMemoryRepositoryBase (IDomainEventCollector eventCollector);
Member Type Description StoreConcurrentDictionary<TId, TAggregate>In-memory store (abstract property). Subclass provides a static instance
Member Type Description EventCollectorIDomainEventCollectorDomain event collector RequestCategorystring (virtual, default "Repository")Observability category
Common infrastructure for Dapper-based QueryAdapters. Subclasses are responsible only for SQL declaration and WHERE building.
namespace Functorium . Adapters . Repositories ;
public abstract class DapperQueryBase <TEntity, TDto>
protected DapperQueryBase (IDbConnection connection);
protected DapperQueryBase (
IDbConnection connection,
DapperSpecTranslator<TEntity> translator,
Member Type Description SelectSqlstringSELECT query (up to FROM + JOIN, excluding WHERE) CountSqlstringCOUNT query (up to FROM + JOIN, excluding WHERE) DefaultOrderBystringDefault ORDER BY clause (e.g., "p.created_at DESC") AllowedSortColumnsDictionary<string, string>Allowed sort column mapping (DTO field name to DB column name)
Method Description BuildWhereClause(spec)Specification to SQL WHERE clause conversion. Default implementation provided when DapperSpecTranslator is injected. Otherwise, subclass override is required PaginationClauseDB dialect-specific Offset pagination clause (virtual, default "LIMIT @PageSize OFFSET @Skip") CursorPaginationClauseDB dialect-specific Keyset pagination clause (virtual, default "LIMIT @PageSize") GetCursorValue(item, fieldName)Extract cursor value from DTO (virtual, Reflection-based default implementation + caching) Params(values)DynamicParameters creation helper (static method)
Method Return Type Description Search(spec, page, sort)FinT<IO, PagedResult<TDto>>Offset-based pagination search (COUNT + SELECT multi-query) SearchByCursor(spec, cursor, sort)FinT<IO, CursorPagedResult<TDto>>Keyset-based search (PageSize + 1 strategy for HasMore determination) Stream(spec, sort, ct)IAsyncEnumerable<TDto>Streaming query via QueryUnbufferedAsync (DbConnection required)
Common infrastructure for InMemory-based QueryAdapters. InMemory counterpart base class for DapperQueryBase.
namespace Functorium . Adapters . Repositories ;
public abstract class InMemoryQueryBase <TEntity, TDto>
// (No constructor parameters)
Member Type Description DefaultSortFieldstringDefault sort field name GetProjectedItems(spec)IEnumerable<TDto>Filtering + DTO projection (including JOIN logic) SortSelector(fieldName)Func<TDto, object>Sort key selector (field name to selector function)
Method Return Type Description Search(spec, page, sort)FinT<IO, PagedResult<TDto>>Offset-based pagination search SearchByCursor(spec, cursor, sort)FinT<IO, CursorPagedResult<TDto>>Keyset-based search Stream(spec, sort, ct)IAsyncEnumerable<TDto>In-memory streaming query
A registry that translates Specifications to SQL WHERE clauses. Once configured per entity type, multiple Dapper adapters can share it with different table aliases.
namespace Functorium . Adapters . Repositories ;
public sealed class DapperSpecTranslator <TEntity>
public DapperSpecTranslator<TEntity> WhenAll (
Func< string , ( string Where, DynamicParameters Params)> handler);
public DapperSpecTranslator<TEntity> When <TSpec>(
Func<TSpec, string , ( string Where, DynamicParameters Params)> handler)
where TSpec : Specification<TEntity>;
public ( string Where, DynamicParameters Params) Translate (
Specification<TEntity> spec, string tableAlias = "" );
public static DynamicParameters Params ( params ( string Name, object Value)[] values);
public static string Prefix ( string tableAlias);
Method Return Type Description WhenAll(handler)DapperSpecTranslator<TEntity>Register IsAll (identity) Specification handler (Fluent API) When<TSpec>(handler)DapperSpecTranslator<TEntity>Register SQL translation handler for a specific Specification type (Fluent API) Translate(spec, alias)(string Where, DynamicParameters Params)Translates Specification to SQL WHERE clause Params(values)DynamicParametersDynamicParameters creation helper (static)Prefix(tableAlias)stringReturns table alias prefix (e.g., "p" to "p.", "" to "")
A collection of IServiceCollection extension methods for registering IObservablePort implementations in the DI container. Uses ActivatorUtilities.CreateInstance to auto-inject ActivitySource, ILogger, and IMeterFactory into implementation type constructors.
namespace Functorium . Abstractions . Registrations ;
public static class ObservablePortRegistration
// Single interface registration
public static IServiceCollection RegisterScopedObservablePort <TService, TImpl>(...);
public static IServiceCollection RegisterTransientObservablePort <TService, TImpl>(...);
public static IServiceCollection RegisterSingletonObservablePort <TService, TImpl>(...);
// Multiple interfaces to single implementation registration (For suffix)
public static IServiceCollection RegisterScopedObservablePortFor <T1, T2, TImpl>(...);
public static IServiceCollection RegisterScopedObservablePortFor <T1, T2, T3, TImpl>(...);
public static IServiceCollection RegisterScopedObservablePortFor <TImpl>(
..., params Type[] serviceTypes);
public static IServiceCollection RegisterTransientObservablePortFor <T1, T2, TImpl>(...);
public static IServiceCollection RegisterTransientObservablePortFor <T1, T2, T3, TImpl>(...);
public static IServiceCollection RegisterTransientObservablePortFor <TImpl>(
..., params Type[] serviceTypes);
public static IServiceCollection RegisterSingletonObservablePortFor <T1, T2, TImpl>(...);
public static IServiceCollection RegisterSingletonObservablePortFor <T1, T2, T3, TImpl>(...);
public static IServiceCollection RegisterSingletonObservablePortFor <TImpl>(
..., params Type[] serviceTypes);
Pattern Description Register{Lifetime}ObservablePort<TService, TImpl>Register a single interface with one implementation Register{Lifetime}ObservablePortFor<T1, T2, TImpl>Register 2 interfaces with one implementation Register{Lifetime}ObservablePortFor<T1, T2, T3, TImpl>Register 3 interfaces with one implementation Register{Lifetime}ObservablePortFor<TImpl>(params Type[])Register N interfaces with one implementation (4 or more)
Lifetime Instance sharing scope ScopedOne instance per HTTP request TransientNew instance per request SingletonOne instance for the entire application
All service interface type parameters have the class, IObservablePort constraint. The params Type[] overload validates IObservablePort implementation and interface implementation of the implementation class at runtime.
Methods with the For suffix first register the implementation, then register each service interface to reference the same instance via GetRequiredService<TImplementation>(). This enables resolving a single implementation through multiple interfaces.
// Usage example: Register IProductRepository and IProductQuery with the same Observable implementation
services . RegisterScopedObservablePortFor <IProductRepository, IProductQuery, ProductObservable>();
A utility for registering FluentValidation-based options validation in DI.
namespace Functorium . Adapters . Abstractions . Options ;
public static class OptionsConfigurator
public static OptionsBuilder<TOptions> RegisterConfigureOptions <TOptions, TValidator>(
this IServiceCollection services,
string configurationSectionName)
where TValidator : class , IValidator<TOptions>;
Order Behavior Description 1 IValidator<TOptions> registrationRegisters TValidator as Scoped in DI 2 BindConfigurationBinds the configurationSectionName section of appsettings.json to TOptions 3 FluentValidation connection Connects FluentValidation validation through IValidateOptions<TOptions> implementation 4 ValidateOnStartRun options validation at program startup 5 IStartupOptionsLogger auto-registrationIf TOptions implements IStartupOptionsLogger, auto-registers for options value logging at startup
services . RegisterConfigureOptions <DatabaseOptions, DatabaseOptionsValidator>( " Database " );
Applying this attribute to an Adapter class causes the source generator to automatically generate an Observable wrapper class. The generated Observable provides OpenTelemetry-based Tracing, Logging, and Metrics.
namespace Functorium . Adapters . SourceGenerators ;
[AttributeUsage( AttributeTargets . Class , AllowMultiple = false , Inherited = false )]
public sealed class GenerateObservablePortAttribute : Attribute;
Property Value Description AttributeTargetsClassCan only be applied to classes AllowMultiplefalseApplied only once per class InheritedfalseNot inherited by derived classes
Prerequisites:
The project must reference the Functorium.SourceGenerators package
Interface methods in the Adapter class require the virtual keyword (Pipeline overrides)
public class ProductRepositoryInMemory
: InMemoryRepositoryBase<Product, ProductId>, IProductRepository
// -> ProductRepositoryInMemoryObservable class is auto-generated
An attribute that excludes a specific method from Observable wrapper generation. Used for helper methods or internal methods where observability is unnecessary.
namespace Functorium . Adapters . SourceGenerators ;
[AttributeUsage( AttributeTargets . Method , AllowMultiple = false , Inherited = false )]
public sealed class ObservablePortIgnoreAttribute : Attribute;
Property Value Description AttributeTargetsMethodCan only be applied to methods AllowMultiplefalseApplied only once per method InheritedfalseNot inherited by derived classes
public class ProductRepository : InMemoryRepositoryBase<Product, ProductId>, IProductRepository
public virtual FinT<IO, int > GetCount () => .. .; // Excluded from Observable wrapper