FractalDataWorks.Abstractions 0.9.0-alpha.1011.ged0a6c6e98

This is a prerelease version of FractalDataWorks.Abstractions.
dotnet add package FractalDataWorks.Abstractions --version 0.9.0-alpha.1011.ged0a6c6e98
                    
NuGet\Install-Package FractalDataWorks.Abstractions -Version 0.9.0-alpha.1011.ged0a6c6e98
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FractalDataWorks.Abstractions" Version="0.9.0-alpha.1011.ged0a6c6e98" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FractalDataWorks.Abstractions" Version="0.9.0-alpha.1011.ged0a6c6e98" />
                    
Directory.Packages.props
<PackageReference Include="FractalDataWorks.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FractalDataWorks.Abstractions --version 0.9.0-alpha.1011.ged0a6c6e98
                    
#r "nuget: FractalDataWorks.Abstractions, 0.9.0-alpha.1011.ged0a6c6e98"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FractalDataWorks.Abstractions@0.9.0-alpha.1011.ged0a6c6e98
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FractalDataWorks.Abstractions&version=0.9.0-alpha.1011.ged0a6c6e98&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FractalDataWorks.Abstractions&version=0.9.0-alpha.1011.ged0a6c6e98&prerelease
                    
Install as a Cake Tool

FractalDataWorks.Abstractions

Core abstractions and base interfaces for the FractalDataWorks framework. This package provides the fundamental contracts that all other framework components build upon, ensuring consistent patterns across services, commands, results, and configuration.

Overview

FractalDataWorks.Abstractions serves as the foundation layer of the FractalDataWorks ecosystem, providing:

  • Core Service Contracts - IGenericService and IServiceFactory interfaces
  • Command Infrastructure - IGenericCommand base interface for all commands
  • Result Contracts - IGenericResult and IGenericResult<T> for Railway-Oriented Programming
  • Message Contracts - IGenericMessage for structured operation feedback
  • Configuration Contracts - IGenericConfiguration for type-safe settings

This package is designed for maximum compatibility and is placed in the abstractions layer to avoid circular dependencies with source generators and other framework components.

Target Frameworks: .NET Standard 2.0, .NET 10.0 Dependencies: FractalDataWorks.Collections

Why This Package Exists

The framework follows a strict dependency hierarchy to prevent circular references:

FractalDataWorks.Abstractions (this package)
    ↓
FractalDataWorks.Results
    ↓
FractalDataWorks.Services.Abstractions
    ↓
FractalDataWorks.Services (concrete implementations)

By placing foundational interfaces in this package, we ensure:

  • Source generators can reference these interfaces without circular dependencies
  • All framework components share consistent base contracts
  • Maximum compatibility through .NET Standard 2.0 support
  • Clean separation of concerns

Core Interfaces

IGenericService

Base interface for all services in the framework. Services represent operational components that execute commands and return results.

public interface IGenericService
{
    /// <summary>
    /// Gets the unique identifier for this service instance.
    /// </summary>
    string Id { get; }

    /// <summary>
    /// Gets the display name of the service.
    /// </summary>
    string ServiceType { get; }

    /// <summary>
    /// Gets a value indicating whether the service is currently available for use.
    /// </summary>
    bool IsAvailable { get; }

    /// <summary>
    /// Executes a data command and returns a typed result.
    /// </summary>
    Task<IGenericResult<T>> Execute<T>(IGenericCommand command, CancellationToken cancellationToken);

    /// <summary>
    /// Executes a data command and returns a non-typed result.
    /// </summary>
    Task<IGenericResult> Execute(IGenericCommand command, CancellationToken cancellationToken);
}

Key Characteristics:

  • All services have a unique identifier and type name
  • Services report availability status
  • Command execution uses the Railway-Oriented Programming pattern via IGenericResult
  • Supports both typed and non-typed command execution
  • Full cancellation token support for async operations

Usage Example:

public class DatabaseService : IGenericService
{
    public string Id => "db-service-001";
    public string ServiceType => "Database";
    public bool IsAvailable => _connection?.State == ConnectionState.Open;

    public async Task<IGenericResult<T>> Execute<T>(
        IGenericCommand command,
        CancellationToken cancellationToken)
    {
        if (!IsAvailable)
            return GenericResult<T>.Failure("Service unavailable");

        // Execute command logic
        var result = await ExecuteCommandAsync<T>(command, cancellationToken);
        return GenericResult<T>.Success(result);
    }

    public async Task<IGenericResult> Execute(
        IGenericCommand command,
        CancellationToken cancellationToken)
    {
        if (!IsAvailable)
            return GenericResult.Failure("Service unavailable");

        await ExecuteCommandAsync(command, cancellationToken);
        return GenericResult.Success();
    }
}

IGenericCommand

Base interface for all commands in the framework. Commands represent operations to be executed by services.

public interface IGenericCommand
{
    /// <summary>
    /// Gets the unique identifier for this command instance.
    /// </summary>
    Guid CommandId { get; }

    /// <summary>
    /// Gets the timestamp when this command was created.
    /// </summary>
    DateTime CreatedAt { get; }

    /// <summary>
    /// Gets the command type identifier.
    /// </summary>
    string CommandType { get; }
}

Key Characteristics:

  • Every command has a unique GUID for tracking and correlation
  • Creation timestamp enables performance measurement and timeout handling
  • Command type identifier enables routing and logging
  • Designed for immutability - properties should be set at creation

Usage Example:

public class QueryCommand : IGenericCommand
{
    public Guid CommandId { get; } = Guid.NewGuid();
    public DateTime CreatedAt { get; } = DateTime.UtcNow;
    public string CommandType => "Query";

    public string Query { get; }
    public object[] Parameters { get; }

    public QueryCommand(string query, params object[] parameters)
    {
        Query = query;
        Parameters = parameters;
    }
}

// Usage
var command = new QueryCommand("SELECT * FROM Users WHERE Id = @id", userId);
var result = await service.Execute<User>(command, cancellationToken);

IGenericResult and IGenericResult<T>

Result interfaces that implement the Railway-Oriented Programming pattern for handling operation outcomes.

public interface IGenericResult
{
    /// <summary>
    /// Gets a value indicating whether the operation succeeded.
    /// </summary>
    bool IsSuccess { get; }

    /// <summary>
    /// Gets a value indicating whether the operation failed.
    /// </summary>
    bool IsFailure { get; }

    /// <summary>
    /// Gets a value indicating whether this represents an empty result.
    /// </summary>
    bool IsEmpty { get; }

    /// <summary>
    /// Gets a value indicating whether this result represents an error.
    /// </summary>
    bool Error { get; }

    /// <summary>
    /// Gets the most recent message (LIFO - Last In, First Out).
    /// </summary>
    string? CurrentMessage { get; }

    /// <summary>
    /// Gets the collection of messages associated with this result.
    /// </summary>
    IReadOnlyList<IGenericMessage> Messages { get; }
}

public interface IGenericResult<out T> : IGenericResult
{
    /// <summary>
    /// Gets the result value if successful.
    /// </summary>
    T? Value { get; }
}

Key Characteristics:

  • Replaces exceptions for expected failure scenarios
  • IsSuccess and IsFailure are mutually exclusive
  • Error is an alias for IsFailure
  • IsEmpty indicates no messages (implementation-specific)
  • CurrentMessage provides the most recent message using LIFO ordering
  • Generic variant carries typed values on success
  • Covariant (out T) for safe variance

Usage Patterns:

// Check result and handle accordingly
IGenericResult<User> result = await service.Execute<User>(command, cancellationToken);

if (result.IsSuccess)
{
    User user = result.Value;
    Console.WriteLine($"Found user: {user.Name}");
}
else
{
    Console.WriteLine($"Error: {result.CurrentMessage}");
    foreach (var msg in result.Messages)
    {
        Console.WriteLine($"  - {msg.Message}");
    }
}

// Railway-oriented composition
IGenericResult<int> ageResult = result
    .Map(user => user.Age)
    .Match(
        success: age => age > 18 ? GenericResult<int>.Success(age) : GenericResult<int>.Failure("Under age"),
        failure: error => GenericResult<int>.Failure(error)
    );

IGenericMessage

Interface for structured messages that provide context about operations.

public interface IGenericMessage
{
    /// <summary>
    /// Gets the message text.
    /// </summary>
    string Message { get; }

    /// <summary>
    /// Gets the message code or identifier.
    /// </summary>
    string? Code { get; }

    /// <summary>
    /// Gets the source component or operation that generated the message.
    /// </summary>
    string? Source { get; }
}

public interface IGenericMessage<TSeverity> : IGenericMessage
    where TSeverity : Enum
{
    /// <summary>
    /// Gets the severity level of the message.
    /// </summary>
    TSeverity Severity { get; }
}

Key Characteristics:

  • Provides structured feedback about operations
  • Optional Code for programmatic message handling
  • Optional Source for debugging and tracing
  • Generic variant supports strongly-typed severity levels
  • Integrates with IGenericResult for detailed operation feedback

Usage Example:

public enum MessageSeverity
{
    Information,
    Warning,
    Error,
    Critical
}

public class GenericMessage : IGenericMessage<MessageSeverity>
{
    public string Message { get; }
    public string? Code { get; }
    public string? Source { get; }
    public MessageSeverity Severity { get; }

    public GenericMessage(
        string message,
        MessageSeverity severity = MessageSeverity.Information,
        string? code = null,
        string? source = null)
    {
        Message = message;
        Severity = severity;
        Code = code;
        Source = source;
    }
}

// Usage in results
var messages = new List<IGenericMessage>
{
    new GenericMessage("Connection established", MessageSeverity.Information, source: "DatabaseService"),
    new GenericMessage("Using cached credentials", MessageSeverity.Warning, code: "CACHE_001")
};

return GenericResult.Success(messages);

IGenericConfiguration

Base interface for all configuration objects in the framework.

public interface IGenericConfiguration
{
    /// <summary>
    /// Gets the unique identifier for this configuration instance.
    /// </summary>
    int Id { get; }

    /// <summary>
    /// Gets the name of this configuration for lookup and display.
    /// </summary>
    string Name { get; }

    /// <summary>
    /// Gets the section name for this configuration in appsettings.
    /// </summary>
    string SectionName { get; }
}

public interface IGenericConfiguration<T> : IGenericConfiguration
    where T : IGenericConfiguration<T>
{
    /// <summary>
    /// Gets the service type identifier for this configuration.
    /// </summary>
    string ServiceType { get; }
}

Key Characteristics:

  • Every configuration has a unique integer identifier
  • Name provides human-readable identification
  • SectionName maps to configuration file sections (e.g., appsettings.json)
  • Generic variant uses CRTP (Curiously Recurring Template Pattern) for type safety
  • ServiceType links configuration to specific service implementations

Usage Example:

// appsettings.json
{
  "Database": {
    "ConnectionString": "Server=localhost;Database=MyDb",
    "CommandTimeout": 30
  }
}

// Configuration class
public class DatabaseConfiguration : IGenericConfiguration<DatabaseConfiguration>
{
    public int Id => 1;
    public string Name => "Primary Database";
    public string SectionName => "Database";
    public string ServiceType => "SqlServer";

    public string ConnectionString { get; set; } = string.Empty;
    public int CommandTimeout { get; set; } = 30;
}

// Loading configuration
var config = configuration
    .GetSection("Database")
    .Get<DatabaseConfiguration>();

IServiceFactory

Generic factory interface for creating service instances with configuration.

public interface IServiceFactory
{
    /// <summary>
    /// Creates a service instance of the specified type.
    /// </summary>
    IGenericResult<T> Create<T>(IGenericConfiguration configuration) where T : IGenericService;

    /// <summary>
    /// Creates a service instance.
    /// </summary>
    IGenericResult<IGenericService> Create(IGenericConfiguration configuration);
}

public interface IServiceFactory<TService> : IServiceFactory
{
    /// <summary>
    /// Creates a service instance of the specified type.
    /// </summary>
    new IGenericResult<TService> Create(IGenericConfiguration configuration);
}

public interface IServiceFactory<TService, in TConfiguration> : IServiceFactory<TService>
    where TConfiguration : IGenericConfiguration
{
    /// <summary>
    /// Creates a service instance using the strongly-typed configuration.
    /// </summary>
    IGenericResult<TService> Create(TConfiguration configuration);
}

Key Characteristics:

  • Progressive constraint refinement from base to specific implementations
  • Returns IGenericResult for consistent error handling
  • Supports both generic and non-generic service creation
  • Strongly-typed configuration binding in most specific variant
  • Enables factory pattern for service instantiation

Usage Example:

public class DatabaseServiceFactory : IServiceFactory<IDatabaseService, DatabaseConfiguration>
{
    private readonly ILogger<DatabaseServiceFactory> _logger;

    public DatabaseServiceFactory(ILogger<DatabaseServiceFactory> logger)
    {
        _logger = logger;
    }

    public IGenericResult<IDatabaseService> Create(DatabaseConfiguration configuration)
    {
        try
        {
            var service = new DatabaseService(
                configuration.ConnectionString,
                configuration.CommandTimeout,
                _logger);

            return GenericResult<IDatabaseService>.Success(service);
        }
        catch (Exception ex)
        {
            return GenericResult<IDatabaseService>.Failure($"Failed to create service: {ex.Message}");
        }
    }

    public IGenericResult<IDatabaseService> Create(IGenericConfiguration configuration)
    {
        if (configuration is not DatabaseConfiguration dbConfig)
            return GenericResult<IDatabaseService>.Failure("Invalid configuration type");

        return Create(dbConfig);
    }

    public IGenericResult<IGenericService> Create(IGenericConfiguration configuration)
    {
        return Create(configuration as DatabaseConfiguration
            ?? throw new ArgumentException("Invalid configuration"));
    }
}

Framework Integration Patterns

Service Registration

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddDatabaseService(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        // Register configuration
        services.Configure<DatabaseConfiguration>(
            configuration.GetSection("Database"));

        // Register factory
        services.AddSingleton<IServiceFactory<IDatabaseService, DatabaseConfiguration>,
            DatabaseServiceFactory>();

        // Register service
        services.AddScoped<IDatabaseService>(sp =>
        {
            var config = sp.GetRequiredService<IOptions<DatabaseConfiguration>>().Value;
            var factory = sp.GetRequiredService<IServiceFactory<IDatabaseService, DatabaseConfiguration>>();

            var result = factory.Create(config);
            return result.IsSuccess
                ? result.Value
                : throw new InvalidOperationException(result.CurrentMessage);
        });

        return services;
    }
}

Command Execution Flow

public class DataOperationHandler
{
    private readonly IGenericService _service;

    public DataOperationHandler(IGenericService service)
    {
        _service = service;
    }

    public async Task<IGenericResult<TResult>> ExecuteAsync<TResult>(
        IGenericCommand command,
        CancellationToken cancellationToken = default)
    {
        // Check service availability
        if (!_service.IsAvailable)
        {
            return GenericResult<TResult>.Failure(
                $"Service '{_service.ServiceType}' is not available");
        }

        // Execute command
        var result = await _service.Execute<TResult>(command, cancellationToken);

        // Log execution
        if (result.IsSuccess)
        {
            Console.WriteLine($"Command {command.CommandId} executed successfully");
        }
        else
        {
            Console.WriteLine($"Command {command.CommandId} failed: {result.CurrentMessage}");
            foreach (var msg in result.Messages)
            {
                Console.WriteLine($"  [{msg.Source}] {msg.Message}");
            }
        }

        return result;
    }
}

Railway-Oriented Error Handling

public async Task<IGenericResult<Order>> ProcessOrderAsync(
    int orderId,
    CancellationToken cancellationToken)
{
    // Chain of operations using railway-oriented programming
    var getOrderCommand = new GetOrderCommand(orderId);
    var orderResult = await _service.Execute<Order>(getOrderCommand, cancellationToken);

    if (orderResult.IsFailure)
        return orderResult; // Propagate failure

    var order = orderResult.Value;

    // Validate order
    if (order.Status != OrderStatus.Pending)
        return GenericResult<Order>.Failure("Order is not in pending status");

    // Process payment
    var paymentCommand = new ProcessPaymentCommand(order.Id, order.TotalAmount);
    var paymentResult = await _service.Execute(paymentCommand, cancellationToken);

    if (paymentResult.IsFailure)
        return GenericResult<Order>.Failure($"Payment failed: {paymentResult.CurrentMessage}");

    // Update order status
    var updateCommand = new UpdateOrderStatusCommand(order.Id, OrderStatus.Completed);
    var updateResult = await _service.Execute<Order>(updateCommand, cancellationToken);

    return updateResult; // Return final result
}

Architecture Guidelines

When to Implement These Interfaces

  • IGenericService: Implement for all operational components (database services, API clients, file handlers)
  • IGenericCommand: Implement for all operations that services can execute
  • IGenericConfiguration: Implement for all configuration classes that bind to appsettings
  • IServiceFactory: Implement when services require complex initialization or dependency injection

Interface Hierarchy Best Practices

  1. Keep This Package Minimal: Only add interfaces that are truly foundational
  2. Avoid Implementation Details: Keep interfaces abstract and implementation-agnostic
  3. Use Concrete Implementations Elsewhere: Implement these interfaces in higher-level packages
  4. Maintain .NET Standard 2.0 Compatibility: Ensures maximum reach
  5. Document Contract Expectations: Clearly specify expected behavior in XML comments

Relationship to Other Packages

FractalDataWorks.Abstractions (foundational contracts)
├── Extended by: FractalDataWorks.Results (IGenericResult implementations)
├── Extended by: FractalDataWorks.Messages (IGenericMessage implementations)
├── Extended by: FractalDataWorks.Commands.Abstractions (command types)
├── Extended by: FractalDataWorks.Services.Abstractions (service types)
└── Used by: All framework packages (universal dependency)

Best Practices

  1. Always Return Results, Not Exceptions: Use IGenericResult for expected failures
  2. Use Cancellation Tokens: Support graceful cancellation in all async operations
  3. Command Immutability: Design commands as immutable data structures
  4. Service Availability Checks: Always check IsAvailable before executing commands
  5. Structured Messages: Use IGenericMessage for rich feedback instead of plain strings
  6. Factory Pattern: Use IServiceFactory for complex service initialization
  7. Configuration Binding: Map SectionName to configuration file sections
  8. Unique Identifiers: Ensure CommandId and service Id are unique for tracking

Dependencies

  • FractalDataWorks.Collections: Provides TypeCollections infrastructure for extensible type systems

Multi-Targeting

This package multi-targets:

  • .NET Standard 2.0: Maximum compatibility with older frameworks and Blazor WASM
  • .NET 10.0: Access to latest runtime features and performance improvements

Project Configuration

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net10.0</TargetFrameworks>
    <RootNamespace>FractalDataWorks</RootNamespace>
    <ImplicitUsings>disable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

Notes

  • This package is intentionally minimal to avoid circular dependencies
  • Extended versions of these interfaces (with additional functionality) exist in higher-level packages
  • All interfaces follow generic naming conventions (IGeneric*) for consistency
  • The framework uses Railway-Oriented Programming extensively through IGenericResult
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (10)

Showing the top 5 NuGet packages that depend on FractalDataWorks.Abstractions:

Package Downloads
FractalDataWorks.Configuration

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Messages

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.ServiceTypes

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Services.Abstractions

Development tools and utilities for the FractalDataWorks ecosystem. Build:

FractalDataWorks.Data.DataStores

Development tools and utilities for the FractalDataWorks ecosystem. Build:

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0-alpha.1011.ged0a6c6e98 0 11/18/2025
0.9.0-alpha.1010.gecd88aac50 0 11/18/2025
0.9.0-alpha.1009.g7f6817e985 0 11/18/2025
0.9.0-alpha.1006.gf287016c0c 0 11/18/2025
0.8.0-alpha.1011 0 11/18/2025
0.7.0-alpha.1022 172 11/3/2025
0.7.0-alpha.1021 194 11/3/2025
0.7.0-alpha.1008 121 11/2/2025
0.7.0-alpha.1006 143 10/30/2025
0.7.0-alpha.1005 142 10/30/2025
0.7.0-alpha.1004 154 10/30/2025
0.7.0-alpha.1001 139 10/29/2025
0.6.0-alpha.1006 133 10/29/2025
0.6.0-alpha.1005 197 10/28/2025
0.6.0-alpha.1004 146 10/28/2025
0.6.0-alpha.1002 125 10/28/2025