FractalDataWorks.Configuration 0.6.0-rc.1

This is a prerelease version of FractalDataWorks.Configuration.
dotnet add package FractalDataWorks.Configuration --version 0.6.0-rc.1
                    
NuGet\Install-Package FractalDataWorks.Configuration -Version 0.6.0-rc.1
                    
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.Configuration" Version="0.6.0-rc.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FractalDataWorks.Configuration" Version="0.6.0-rc.1" />
                    
Directory.Packages.props
<PackageReference Include="FractalDataWorks.Configuration" />
                    
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.Configuration --version 0.6.0-rc.1
                    
#r "nuget: FractalDataWorks.Configuration, 0.6.0-rc.1"
                    
#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.Configuration@0.6.0-rc.1
                    
#: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.Configuration&version=0.6.0-rc.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FractalDataWorks.Configuration&version=0.6.0-rc.1&prerelease
                    
Install as a Cake Tool

FractalDataWorks.Configuration

Generic multi-tenant hierarchical configuration provider for Microsoft.Extensions.Configuration.

Overview

FractalDataWorks.Configuration provides a flexible configuration system that separates data loading (Sources) from data processing (Provider). This enables integration with various storage backends while maintaining a consistent configuration interface.

Architecture:

  • FdwConfigurationProvider - Generic provider that flattens and merges hierarchical configuration data
  • ConfigurationBase<T> - Base class for strongly-typed configuration objects
  • IGenericConfiguration - Interface for configuration metadata
  • Configuration Sources - Pluggable data sources (SQL Server, JSON, etc.)

Key Features:

  • Multi-Tenant Hierarchy - Four levels: DEFAULT, APPLICATION, TENANT, USER
  • Source-Agnostic Provider - Works with any data source via delegate pattern
  • Type-Safe Configurations - Generic base class for configuration inheritance
  • Microsoft.Extensions.Configuration Integration - Standard .NET configuration system

Core Components

IGenericConfiguration - Base Interface

From IGenericConfiguration.cs:1-41:

namespace FractalDataWorks.Configuration;

using System;

/// <summary>
/// Base interface for all configuration objects in the FractalDataWorks framework.
/// Provides common properties for all configuration types.
/// </summary>
public interface IGenericConfiguration
{
    /// <summary>
    /// Gets the unique identifier for this configuration instance.
    /// </summary>
    Guid Id { get; set; }

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

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

}

/// <summary>
/// Generic configuration interface for type-safe configuration.
/// </summary>
/// <typeparam name="T">The concrete configuration type.</typeparam>
/// <remarks>
/// ServiceType discriminators are defined on domain-specific interfaces
/// (e.g., IConnectionConfiguration.ConnectionType, IAuthenticationConfiguration.AuthenticationType).
/// This allows each domain to use its own naming convention.
/// </remarks>
public interface IGenericConfiguration<T> : IGenericConfiguration
    where T : IGenericConfiguration<T>
{
}

ConfigurationBase<T> - Typed Configuration Base Class

From ConfigurationBase.cs:1-65:

using System;

namespace FractalDataWorks.Configuration;

/// <summary>
/// Base class for all configuration types in the FractalDataWorks framework.
/// Provides common metadata properties for immutable configuration instances.
/// </summary>
/// <typeparam name="T">The derived configuration type (for type-safe chaining).</typeparam>
/// <remarks>
/// <para>
/// This base class provides:
/// <list type="bullet">
/// <item><description>Identity (Id, Name, SectionName)</description></item>
/// <item><description>Audit timestamps (CreatedAt, ModifiedAt)</description></item>
/// <item><description>Immutability via init-only properties</description></item>
/// </list>
/// </para>
/// <para>
/// Configuration discriminators are defined on domain-specific interfaces
/// (e.g., IConnectionConfiguration.ConnectionType).
/// </para>
/// </remarks>
public abstract class ConfigurationBase<T> : IGenericConfiguration<T>
    where T : ConfigurationBase<T>
{
    /// <summary>
    /// Gets the unique identifier for this configuration instance.
    /// </summary>
    public Guid Id { get; set; } = Guid.NewGuid();

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

    /// <summary>
    /// Gets the section name for this configuration in appsettings or database.
    /// Must be overridden by derived classes.
    /// </summary>
    /// <example>"Email", "Database", "Notification"</example>
    public abstract string SectionName { get; }

    /// <summary>
    /// Gets the timestamp when this configuration instance was created.
    /// </summary>
    public DateTime CreatedAt { get; init; } = DateTime.UtcNow;

    /// <summary>
    /// Gets the timestamp when this configuration was last modified.
    /// </summary>
    public DateTime? ModifiedAt { get; init; }
}

FdwConfigurationProvider - Generic Provider

From FdwConfigurationProvider.cs:1-91:

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;

namespace FractalDataWorks.Configuration;

/// <summary>
/// Generic multi-tenant configuration provider that flattens hierarchical configuration data.
/// Works with any IConfigurationSource that provides hierarchical data.
/// </summary>
public class FdwConfigurationProvider : ConfigurationProvider
{
    private readonly IConfigurationSource _source;
    private readonly Func<IDictionary<int, IDictionary<string, object>>> _loadHierarchy;
    private readonly string _sectionName;

    /// <summary>
    /// Initializes a new instance of the provider.
    /// </summary>
    /// <param name="source">The configuration source.</param>
    /// <param name="loadHierarchy">Function to load hierarchical data from the source.</param>
    /// <param name="sectionName">Optional section name prefix for configuration keys.</param>
    public FdwConfigurationProvider(
        IConfigurationSource source,
        Func<IDictionary<int, IDictionary<string, object>>> loadHierarchy,
        string sectionName = "")
    {
        _source = source ?? throw new ArgumentNullException(nameof(source));
        _loadHierarchy = loadHierarchy ?? throw new ArgumentNullException(nameof(loadHierarchy));
        _sectionName = sectionName ?? string.Empty;
    }

    /// <summary>
    /// Loads configuration data by calling the source's LoadHierarchy function
    /// and flattening the result.
    /// </summary>
    public override void Load()
    {
        var hierarchy = _loadHierarchy();
        Data = FlattenHierarchy(hierarchy);
    }

    /// <summary>
    /// Flattens hierarchical configuration into a single dictionary.
    /// Merges levels in order: DEFAULT (0) → APPLICATION (1) → TENANT (2) → USER (3).
    /// Higher levels override lower levels.
    /// </summary>
    private Dictionary<string, string?> FlattenHierarchy(
        IDictionary<int, IDictionary<string, object>> hierarchy)
    {
        var flattened = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);

        // Merge in order: DEFAULT (0) → APPLICATION (1) → TENANT (2) → USER (3)
        for (int level = 0; level < 4; level++)
        {
            if (hierarchy.TryGetValue(level, out var levelData))
            {
                foreach (var kvp in levelData)
                {
                    // Skip hierarchy metadata columns
                    if (IsMetadataColumn(kvp.Key))
                    {
                        continue;
                    }

                    // Add with optional section prefix
                    var key = string.IsNullOrEmpty(_sectionName)
                        ? kvp.Key
                        : $"{_sectionName}:{kvp.Key}";

                    flattened[key] = kvp.Value?.ToString() ?? string.Empty;
                }
            }
        }

        return flattened;
    }

    /// <summary>
    /// Determines if a column is metadata that should be excluded from configuration.
    /// </summary>
    private static bool IsMetadataColumn(string columnName)
    {
        return columnName switch
        {
            "Id" or "Level" or "TenantId" or "UserId" or "CreatedAt" or "ModifiedAt" => true,
            _ => false
        };
    }
}

Hierarchical Multi-Tenant Configuration

The configuration system supports a 4-level hierarchy that allows progressive overriding:

Level Name Purpose Example Use Case
0 DEFAULT System-wide defaults Factory defaults for all tenants
1 APPLICATION Application-level settings Environment-specific (Dev/Staging/Prod)
2 TENANT Tenant-specific overrides Per-customer customization
3 USER User-specific settings Individual user preferences

Merge Behavior:

  • Values are merged from level 0 → 1 → 2 → 3
  • Higher-level values override lower-level values
  • Only non-metadata columns are included in the final configuration

Metadata Columns (Excluded):

  • Id - Configuration row identifier
  • Level - Hierarchy level (0-3)
  • TenantId - Tenant identifier (null for levels 0-1)
  • UserId - User identifier (null for levels 0-2)
  • CreatedAt - Timestamp when created
  • ModifiedAt - Timestamp when modified

Creating Configurations

Example: MsSql Connection Configuration

From MsSqlConnectionConfiguration.cs:43-143:

[ManagedConfiguration(
    Schema = "cfg",
    TableName = "MsSqlConnection",
    Parent = nameof(ConnectionConfigurationBase<MsSqlConnectionConfiguration>),
    ServiceCategory = "Connection",
    ServiceType = "MsSql")]
public partial class MsSqlConnectionConfiguration : ConnectionConfigurationBase<MsSqlConnectionConfiguration>
{
    /// <summary>
    /// Gets the connection type name. Always returns "MsSql" for SQL Server connections.
    /// </summary>
    public override string ConnectionType => "MsSql";

    /// <summary>
    /// Gets the configuration section name for this connection.
    /// </summary>
    public override string SectionName => string.IsNullOrEmpty(Name) ? "Connections" : $"Connections:{Name}";

    #region SQL Server Specific Properties

    /// <summary>
    /// Gets or sets the SQL Server hostname or IP address.
    /// </summary>
    public string Server { get; set; } = "localhost";

    /// <summary>
    /// Gets or sets the database name.
    /// </summary>
    public string Database { get; set; } = string.Empty;

    /// <summary>
    /// Gets or sets the SQL Server port. Default is 1433.
    /// </summary>
    public int Port { get; set; } = 1433;

    /// <summary>
    /// Gets or sets the command timeout in seconds.
    /// </summary>
    public int CommandTimeoutSeconds { get; set; } = 30;

    /// <summary>
    /// Gets or sets the connection timeout in seconds.
    /// </summary>
    public int ConnectionTimeoutSeconds { get; set; } = 15;

    /// <summary>
    /// Gets or sets the default schema to use for operations.
    /// </summary>
    public string DefaultSchema { get; set; } = "dbo";

    #endregion
}

Configuration Sources

Configuration sources implement IConfigurationSource and are responsible for querying the data store and providing configuration data.

MsSqlConfigurationSource

From MsSqlConfigurationSource.cs:23-65:

/// <summary>
/// SQL Server configuration source using FractalDataWorks DataCommands.
/// Reads configuration from cfg.* tables and provides it to IConfiguration.
/// </summary>
public sealed class MsSqlConfigurationSource : IConfigurationSource
{
    /// <summary>
    /// Gets or sets the data connection to the configuration database.
    /// </summary>
    public IDataConnection? Connection { get; set; }

    /// <summary>
    /// Gets or sets the service provider for resolving dependencies.
    /// </summary>
    public IServiceProvider? ServiceProvider { get; set; }

    /// <summary>
    /// Gets or sets the section name prefix for configuration keys.
    /// </summary>
    public string SectionName { get; set; } = string.Empty;

    /// <summary>
    /// Gets or sets the service category filter (e.g., "Connection", "DataStore").
    /// </summary>
    public string? ServiceCategory { get; set; }

    /// <summary>
    /// Gets or sets the tenant ID for multi-tenant configuration.
    /// </summary>
    public string? TenantId { get; set; }

    /// <summary>
    /// Gets or sets the user ID for user-specific configuration.
    /// </summary>
    public string? UserId { get; set; }

    /// <inheritdoc/>
    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new MsSqlConfigurationProvider(this);
    }
}

Available Sources

  • FractalDataWorks.Configuration.MsSql - SQL Server source using DataCommands

See individual source packages for usage examples.

Usage with Microsoft.Extensions.Configuration

Basic Setup with IOptions

From ConfigurationIntegrationTests.cs:18-59:

// Arrange: Setup in-memory configuration
var configData = new Dictionary<string, string?>
{
    ["TestConnection:Name"] = "TestConnection",
    ["TestConnection:ConnectionString"] = "Server=localhost;Database=Test;",
    ["TestConnection:Timeout"] = "30"
};

var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(configData)
    .Build();

var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);

// Configure options binding for test configuration
services.Configure<TestConnectionConfiguration>(
    configuration.GetSection("TestConnection"));

var serviceProvider = services.BuildServiceProvider();

// Act: Resolve configuration from DI
var options = serviceProvider.GetRequiredService<IOptions<TestConnectionConfiguration>>();
var config = options.Value;

// Assert: Configuration loaded correctly
config.Name.ShouldBe("TestConnection");
config.ConnectionString.ShouldBe("Server=localhost;Database=Test;");
config.Timeout.ShouldBe(30);

Using IOptionsSnapshot for Scoped Configuration

From ConfigurationIntegrationTests.cs:64-109:

var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(configData)
    .Build();

var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(configuration);

// Configure options binding for scoped snapshot
services.Configure<TestConnectionConfiguration>(
    configuration.GetSection("TestConnection"));

var serviceProvider = services.BuildServiceProvider();

// Create scope and resolve IOptionsSnapshot
using var scope = serviceProvider.CreateScope();
var snapshot = scope.ServiceProvider
    .GetRequiredService<IOptionsSnapshot<TestConnectionConfiguration>>();
var config = snapshot.Value;

// IOptionsSnapshot reloads configuration per scope
// In production with database-backed config, values could differ per scope

Architecture Principles

1. Separation of Concerns

Source Responsibilities:

  • Connect to data store (SQL Server, JSON file, etc.)
  • Execute queries/reads
  • Transform raw data into configuration key-value pairs
  • Handle connection/query errors

Provider Responsibilities:

  • Receive hierarchy data via delegate
  • Flatten multi-level structure
  • Merge levels in correct order
  • Filter metadata columns
  • Apply section name prefixes

2. Delegate Pattern

The provider accepts a Func<IDictionary<int, IDictionary<string, object>>> delegate, allowing the source to control data loading while the provider handles processing. See the FdwConfigurationProvider implementation above for the actual pattern.

3. No Repository Pattern

Sources directly query the data store without an additional repository abstraction. This keeps the architecture simple and follows the single responsibility principle.

Example: Multi-Tenant Email Configuration

Database Schema

CREATE TABLE EmailConfiguration
(
    Id INT IDENTITY(1,1) PRIMARY KEY,
    Level INT NOT NULL,                  -- 0=DEFAULT, 1=APP, 2=TENANT, 3=USER
    TenantId NVARCHAR(50) NULL,         -- NULL for levels 0-1
    UserId NVARCHAR(50) NULL,           -- NULL for levels 0-2
    SmtpHost NVARCHAR(100),
    SmtpPort INT,
    Username NVARCHAR(100),
    Password NVARCHAR(255),
    EnableSsl BIT,
    TimeoutSeconds INT,
    CreatedAt DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    ModifiedAt DATETIME2 NULL
);

Sample Data

-- Level 0: DEFAULT - System-wide defaults
INSERT INTO EmailConfiguration (Level, SmtpHost, SmtpPort, EnableSsl, TimeoutSeconds)
VALUES (0, 'smtp.gmail.com', 587, 1, 30);

-- Level 1: APPLICATION - Production environment settings
INSERT INTO EmailConfiguration (Level, SmtpHost, SmtpPort)
VALUES (1, 'smtp.company.com', 25);

-- Level 2: TENANT - Tenant-specific override
INSERT INTO EmailConfiguration (Level, TenantId, SmtpHost, Username, Password)
VALUES (2, 'acme-corp', 'smtp.acme.com', 'noreply@acme.com', 'encrypted-password');

-- Level 3: USER - User preference
INSERT INTO EmailConfiguration (Level, TenantId, UserId, TimeoutSeconds)
VALUES (3, 'acme-corp', 'john.doe', 60);

Result After Merge

For TenantId = "acme-corp" and UserId = "john.doe":

{
  "Email:SmtpHost": "smtp.acme.com",        // From TENANT (level 2)
  "Email:SmtpPort": "25",                   // From APPLICATION (level 1)
  "Email:Username": "noreply@acme.com",     // From TENANT (level 2)
  "Email:Password": "encrypted-password",   // From TENANT (level 2)
  "Email:EnableSsl": "True",                // From DEFAULT (level 0)
  "Email:TimeoutSeconds": "60"              // From USER (level 3)
}

Installation

<PackageReference Include="FractalDataWorks.Configuration" />
<PackageReference Include="FractalDataWorks.Configuration.MsSql" />

Dependencies

  • FractalDataWorks.Abstractions - Contains IGenericConfiguration interface
  • Microsoft.Extensions.Configuration - .NET configuration system
  • Microsoft.Extensions.Configuration.Abstractions - Configuration abstractions

Best Practices

  1. Use ConfigurationBase<T> for strongly-typed configurations
  2. Override SectionName to match your configuration section naming convention
  3. Leverage the hierarchy - put shared defaults at DEFAULT level, tenant customizations at TENANT level
  4. Use metadata wisely - Id, Name, CreatedAt, ModifiedAt are automatically excluded from configuration values
  5. Keep sources focused - Sources should only handle data loading, not processing
  6. Test multi-tenant scenarios - Verify different TenantId/UserId combinations produce correct merged values

OptionsLoader TypeCollection

The OptionsLoaderTypes TypeCollection provides three loader implementations that wrap the Microsoft.Extensions.Options interfaces.

From OptionsLoaderTypes.cs:1-36:

/// <summary>
/// Type collection for options loader types.
/// Source generator creates compile-time discovery of all options loader implementations.
/// </summary>
/// <remarks>
/// <para>
/// Available options loaders (discovered via [TypeOption] attribute):
/// </para>
/// <list type="bullet">
/// <item><description><b>Singleton</b>: IOptions, loaded once at startup (best for static configuration)</description></item>
/// <item><description><b>Scoped</b>: IOptionsSnapshot, reloaded per scope/request (best for multi-tenant scenarios)</description></item>
/// <item><description><b>Reloadable</b>: IOptionsMonitor, supports hot reload with change notifications (best for runtime configuration changes)</description></item>
/// </list>
/// </remarks>
[TypeCollection(typeof(OptionsLoaderBase), typeof(IOptionsLoader), typeof(OptionsLoaderTypes))]
public sealed partial class OptionsLoaderTypes : TypeCollectionBase<OptionsLoaderBase, IOptionsLoader>
{
}

Configuration Source to OptionsLoader Mapping

Configuration Source Recommended OptionsLoader Reason
appsettings.json (static) SingletonOptionsLoader Config loaded once at startup
appsettings.json (file-watched) ReloadableOptionsLoader Supports hot reload when file changes
Database (MsSqlConfigurationSource) ReloadableOptionsLoader Detects config changes via polling/change tracking
Environment variables SingletonOptionsLoader Env vars typically do not change during runtime
Multi-tenant configuration ScopedOptionsLoader Reloads per tenant/request scope

SingletonOptionsLoader

From SingletonOptionsLoader.cs:23-50:

/// <summary>
/// Options loader that uses IOptions for singleton configuration loading.
/// Configuration is loaded once at application startup and cached for the lifetime of the application.
/// </summary>
/// <remarks>
/// Use this when:
/// - Configuration doesn't change at runtime
/// - You want the best performance (no reload overhead)
/// - Configuration is the same for all scopes/requests
///
/// Does NOT support:
/// - Hot reload / configuration changes at runtime
/// - Per-scope/per-request configuration
/// </remarks>
[TypeOption(typeof(OptionsLoaderTypes), "Singleton")]
public sealed class SingletonOptionsLoader : OptionsLoaderBase
{
    public SingletonOptionsLoader() : base(1, "Singleton") { }

    public override string OptionsInterfaceName => "IOptions";
    public override bool SupportsHotReload => false;
    public override string CurrentValueAccessor => ".Value";
    public override bool RequiresDisposable => false;
}

ScopedOptionsLoader

From ScopedOptionsLoader.cs:27-47:

/// <summary>
/// Options loader that uses IOptionsSnapshot for scoped configuration loading.
/// Configuration is reloaded at the beginning of each scope/request.
/// </summary>
/// <remarks>
/// Use this when:
/// - Configuration might differ per scope/request (multi-tenant scenarios)
/// - You want configuration reloading but don't need instant hot reload
/// - Services are registered as Scoped
///
/// Does NOT support:
/// - Instant hot reload within a scope
/// - Singleton services (scoped options can't be injected into singletons)
/// </remarks>
[TypeOption(typeof(OptionsLoaderTypes), "Scoped")]
public sealed class ScopedOptionsLoader : OptionsLoaderBase
{
    public ScopedOptionsLoader() : base(2, "Scoped") { }

    public override string OptionsInterfaceName => "IOptionsSnapshot";
    public override bool SupportsHotReload => false;
    public override string CurrentValueAccessor => ".Value";
    public override bool RequiresDisposable => false;
}

ReloadableOptionsLoader

From ReloadableOptionsLoader.cs:28-48:

/// <summary>
/// Options loader that uses IOptionsMonitor for reloadable configuration with hot reload support.
/// Configuration can be reloaded at runtime with change notifications.
/// </summary>
/// <remarks>
/// Use this when:
/// - Configuration can change at runtime (database-backed config, config file changes)
/// - You need instant hot reload without restarting the application
/// - You want to respond to configuration changes via OnChange notifications
///
/// Requires:
/// - IDisposable implementation to clean up OnChange subscriptions
/// </remarks>
[TypeOption(typeof(OptionsLoaderTypes), "Reloadable")]
public sealed class ReloadableOptionsLoader : OptionsLoaderBase
{
    public ReloadableOptionsLoader() : base(3, "Reloadable") { }

    public override string OptionsInterfaceName => "IOptionsMonitor";
    public override bool SupportsHotReload => true;
    public override string CurrentValueAccessor => ".CurrentValue";
    public override bool RequiresDisposable => true;
}

Using OptionsLoader with ServiceTypes

ServiceTypes accept an OptionsLoaderBase parameter in their constructor:

From ServiceTypeBase.cs:260-270:

protected ServiceTypeBase(
    string name,
    string sectionName,
    string displayName,
    string description,
    OptionsLoaderBase optionsLoader,
    string? category = null)
    : base(Id, name, sectionName, displayName, description, category)
{
    OptionsLoader = optionsLoader ?? throw new ArgumentNullException(nameof(optionsLoader));
}

Recommendation: Use the simplest loader that meets your requirements. If configuration does not change at runtime, use SingletonOptionsLoader.

  • FractalDataWorks.Configuration.MsSql - SQL Server configuration source
  • FractalDataWorks.Configuration.Abstractions - Configuration interfaces and base classes
  • FractalDataWorks.Abstractions - Core interfaces including IGenericConfiguration

See Also

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 (1)

Showing the top 1 NuGet packages that depend on FractalDataWorks.Configuration:

Package Downloads
FractalDataWorks.Configuration.MsSql

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.6.0-rc.1 43 2/9/2026
Loading failed