FractalDataWorks.Services 0.4.0-preview.6

This is a prerelease version of FractalDataWorks.Services.
The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package FractalDataWorks.Services --version 0.4.0-preview.6
                    
NuGet\Install-Package FractalDataWorks.Services -Version 0.4.0-preview.6
                    
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.Services" Version="0.4.0-preview.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FractalDataWorks.Services" Version="0.4.0-preview.6" />
                    
Directory.Packages.props
<PackageReference Include="FractalDataWorks.Services" />
                    
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.Services --version 0.4.0-preview.6
                    
#r "nuget: FractalDataWorks.Services, 0.4.0-preview.6"
                    
#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.Services@0.4.0-preview.6
                    
#: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.Services&version=0.4.0-preview.6&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=FractalDataWorks.Services&version=0.4.0-preview.6&prerelease
                    
Install as a Cake Tool

FractalDataWorks.Services

Service factory implementations for the FractalDataWorks framework. Provides base classes for service factories, provider registration, and DI container integration using Railway-Oriented Programming patterns.

Overview

This package contains concrete implementations of service infrastructure:

  • ServiceFactory<TService, TConfiguration> - Base factory with FastGenericNew instantiation
  • GenericServiceFactory<TService, TConfiguration> - Default factory for most services
  • ServiceFactoryProvider - Thread-safe registry for service factories
  • FactoryRegistration - Registration metadata with lifetime support
  • MessageLogging classes for structured logging

Target Framework

  • net10.0

Installation

<PackageReference Include="FractalDataWorks.Services" Version="1.0.0" />

Key Components

ServiceFactory - Base Factory Implementation

From ServiceFactory.cs:21-77:

public abstract class ServiceFactory<TService, TConfiguration> : IServiceFactory<TService, TConfiguration> where TService : class
    where TConfiguration : class, IGenericConfiguration
{
    private readonly ILogger _logger;

    protected ILogger Logger => _logger;

    protected ServiceFactory(ILogger? logger)
    {
        _logger = logger ?? NullLogger.Instance;
    }

    public virtual IGenericResult<TService> Create(TConfiguration configuration)
    {
        var serviceTypeName = typeof(TService).Name;

        if (configuration == null)
        {
            return GenericResult<TService>.Failure(ServiceLogger.InvalidConfigurationWarning(_logger, "Configuration cannot be null"));
        }

        ServiceLogger.ValidatingServiceConfiguration(_logger, serviceTypeName);

        var serviceLogger = NullLogger<TService>.Instance;
        if (FastNew.TryCreateInstance<TService, ILogger<TService>, TConfiguration>(serviceLogger, configuration, out var service))
        {
            ServiceLogger.FastGenericServiceCreated(_logger, serviceTypeName);
            ServiceLogger.ServiceStarted(_logger, serviceTypeName);

            return GenericResult<TService>.Success(service, $"Service created successfully: {serviceTypeName}");
        }

        ServiceLogger.FastGenericServiceCreationFailed(_logger, serviceTypeName);
        var exception = new InvalidOperationException("FastNew failed to create service");

        return GenericResult<TService>.Failure(ServiceFactoryLogger.CreateServiceError(_logger, exception, serviceTypeName));
    }
}

GenericServiceFactory - Default Factory

From GenericServiceFactory.cs:22-71:

public class GenericServiceFactory<TService, TConfiguration> : ServiceFactory<TService, TConfiguration>
    where TService : class, IGenericService
    where TConfiguration : class, IGenericConfiguration
{
    private readonly ILogger<GenericServiceFactory<TService, TConfiguration>> _logger;

    public GenericServiceFactory(ILogger<GenericServiceFactory<TService, TConfiguration>> logger)
        : base(logger)
    {
        _logger = logger;
    }

    public GenericServiceFactory()
        : base(null)
    {
        _logger = NullLogger<GenericServiceFactory<TService, TConfiguration>>.Instance;
    }

    public override IGenericResult<TService> Create(TConfiguration configuration)
    {
        var serviceTypeName = typeof(TService).Name;

        ServiceFactoryLogger.CreatingService(_logger, serviceTypeName, configuration.Name ?? "unnamed");

        var serviceLogger = NullLogger<TService>.Instance;
        if (FastNew.TryCreateInstance<TService, ILogger<TService>, TConfiguration>(serviceLogger, configuration, out var service))
        {
            ServiceFactoryLogger.ServiceCreatedWithFastNew(_logger, serviceTypeName);
            return GenericResult<TService>.Success(service, ServiceLogger.ConfigurationCannotBeNull(_logger, serviceTypeName));
        }

        return GenericResult<TService>.Failure(ServiceFactoryLogger.ServiceCreationFailed(_logger, serviceTypeName, "No suitable constructor found"));
    }
}

ServiceFactoryProvider - Factory Registry

From ServiceFactoryProvider.cs:18-92:

public sealed class ServiceFactoryProvider : IServiceFactoryProvider
{
    private readonly Dictionary<string, FactoryRegistration> _registrations;
    private readonly object _lock;

    public ServiceFactoryProvider()
    {
        _registrations = new Dictionary<string, FactoryRegistration>(StringComparer.OrdinalIgnoreCase);
        _lock = new object();
    }

    public IGenericResult RegisterFactory(string typeName, IServiceFactory factory)
    {
        return RegisterFactory(typeName, factory, ServiceLifetimes.Scoped);
    }

    public IGenericResult RegisterFactory(string typeName, IServiceFactory factory, IServiceLifetime lifetime)
    {
        if (string.IsNullOrWhiteSpace(typeName))
            return GenericResult.Failure("Service type name cannot be null or empty");

        if (factory == null)
            return GenericResult.Failure("Factory cannot be null");

        if (lifetime == null)
            return GenericResult.Failure("Lifetime cannot be null");

        lock (_lock)
        {
            if (_registrations.ContainsKey(typeName))
            {
                return GenericResult.Failure($"Factory for service type '{typeName}' is already registered");
            }

            _registrations[typeName] = new FactoryRegistration
            {
                Factory = factory,
                Lifetime = lifetime,
                TypeName = typeName
            };
        }

        return GenericResult.Success();
    }

    public IGenericResult<IServiceFactory> GetFactory(string typeName)
    {
        if (string.IsNullOrWhiteSpace(typeName))
            return GenericResult<IServiceFactory>.Failure("Service type name cannot be null or empty");

        lock (_lock)
        {
            if (_registrations.TryGetValue(typeName, out var registration))
            {
                return GenericResult<IServiceFactory>.Success(registration.Factory);
            }
        }

        var availableTypes = string.Join(", ", GetRegisteredTypeNames());
        return GenericResult<IServiceFactory>.Failure(
            $"No factory registered for service type '{typeName}'. Available types: {availableTypes}");
    }
}

FactoryRegistration - Registration Metadata

From FactoryRegistration.cs:17-66:

public sealed class FactoryRegistration
{
    public IServiceFactory Factory { get; set; } = null!;

    public IServiceLifetime Lifetime { get; set; } = ServiceLifetimes.Scoped;

    public string TypeName { get; set; } = string.Empty;

    public int Priority { get; set; } = 50;

    public IDictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>(StringComparer.Ordinal);
}

DI Registration Extensions

From Extensions/ServiceFactoryRegistrationExtensions.cs:31-68:

public static class ServiceFactoryRegistrationExtensions
{
    public static IServiceCollection AddServiceFactoryProvider(this IServiceCollection services)
    {
        services.AddSingleton<IServiceFactoryProvider, ServiceFactoryProvider>();
        return services;
    }

    public static IServiceCollection RegisterConnectionFactories(
        this IServiceCollection services,
        Action<IConnectionFactoryRegistrationBuilder> configure)
    {
        if (configure == null)
            throw new ArgumentNullException(nameof(configure));

        services.AddServiceFactoryProvider();

        var builder = new ConnectionFactoryRegistrationBuilder(services);

        configure(builder);

        return services;
    }
}

Logging Infrastructure

ServiceLogger - Service Operation Logging

From Logging/ServiceLogger.cs:10-75:

public static partial class ServiceLogger
{
    [MessageLogging(EventId = 5001, Level = LogLevel.Warning, Message = "Configuration cannot be null for service type '{serviceTypeName}'")]
    public static partial IGenericMessage ConfigurationCannotBeNull(ILogger logger, string serviceTypeName);

    [MessageLogging(EventId = 5002, Level = LogLevel.Warning, Message = "{errorMessage}")]
    public static partial IGenericMessage InvalidConfigurationWarning(ILogger logger, string errorMessage);

    [MessageLogging(EventId = 5003, Level = LogLevel.Debug, Message = "Validating service configuration for '{serviceTypeName}'")]
    public static partial IGenericMessage ValidatingServiceConfiguration(ILogger logger, string serviceTypeName);

    [MessageLogging(EventId = 5004, Level = LogLevel.Information, Message = "Fast generic service created: '{serviceTypeName}'")]
    public static partial IGenericMessage FastGenericServiceCreated(ILogger logger, string serviceTypeName);

    [MessageLogging(EventId = 5005, Level = LogLevel.Information, Message = "Service started: '{serviceTypeName}'")]
    public static partial IGenericMessage ServiceStarted(ILogger logger, string serviceTypeName);

    [MessageLogging(EventId = 5006, Level = LogLevel.Error, Message = "Fast generic service creation failed for '{serviceTypeName}'")]
    public static partial IGenericMessage FastGenericServiceCreationFailed(ILogger logger, string serviceTypeName);

    [MessageLogging(EventId = 5007, Level = LogLevel.Error, Message = "Service type cast failed: cannot cast '{sourceType}' to '{targetType}'")]
    public static partial IGenericMessage ServiceTypeCastFailed(ILogger logger, string sourceType, string targetType);
}

ServiceFactoryLogger - Factory Logging

From Logging/ServiceFactoryLogger.cs:12-118:

public static partial class ServiceFactoryLogger
{
    [MessageLogging(
        EventId = 7001,
        Level = LogLevel.Debug,
        Message = "Creating service '{serviceType}' with configuration '{configurationName}'")]
    public static partial IGenericMessage CreatingService(
        ILogger logger,
        string serviceType,
        string configurationName);

    [MessageLogging(
        EventId = 7003,
        Level = LogLevel.Information,
        Message = "Service '{serviceType}' created successfully using FastGenericNew")]
    public static partial IGenericMessage ServiceCreatedWithFastNew(
        ILogger logger,
        string serviceType);

    [MessageLogging(
        EventId = 7004,
        Level = LogLevel.Error,
        Message = "Failed to create service '{serviceType}': {reason}")]
    public static partial IGenericMessage ServiceCreationFailed(
        ILogger logger,
        string serviceType,
        string reason);

    [MessageLogging(
        EventId = 7007,
        Level = LogLevel.Error,
        Message = "Failed to create service of type '{serviceType}'")]
    public static partial IGenericMessage CreateServiceError(
        ILogger logger,
        Exception exception,
        string serviceType);
}

Message Types

The package includes predefined message types for service operations:

  • ConfigurationCannotBeNullMessage - Configuration validation
  • ConfigurationNotInitializedMessage - Initialization errors
  • FastGenericCreationFailedMessage - FastGenericNew failures
  • ServiceCreatedSuccessfullyMessage - Successful creation
  • ServiceCreationFailedMessage - Creation failures
  • RegistrationFailedMessage - DI registration errors
  • InvalidCommandTypeMessage - Command type mismatches
  • ValidationFailedMessage - Validation errors

Dependencies

Project references from FractalDataWorks.Services.csproj:

  • FractalDataWorks.MessageLogging.Abstractions - MessageLogging infrastructure
  • FractalDataWorks.MessageLogging.SourceGenerators - Source generator (analyzer)
  • FractalDataWorks.Collections - TypeCollection support
  • FractalDataWorks.Configuration - Configuration base classes
  • FractalDataWorks.Messages - Message infrastructure
  • FractalDataWorks.Results - IGenericResult implementation
  • FractalDataWorks.Services.Abstractions - ServiceType discovery
  • FractalDataWorks.Services.Abstractions - Service interfaces
  • FractalDataWorks.Services.Connections.Abstractions - Connection abstractions
  • FractalDataWorks.Etl.Abstractions - ETL abstractions

Package references:

  • FastGenericNew.SourceGenerator - High-performance object creation
  • FluentValidation - Configuration validation
  • Microsoft.Extensions.DependencyInjection.Abstractions - DI integration
  • Microsoft.Extensions.Diagnostics.HealthChecks - Health check support
  • Microsoft.Extensions.Hosting.Abstractions - Hosting integration
  • Microsoft.Extensions.Logging.Abstractions - Logging
  • Microsoft.Extensions.Options - Options pattern

Best Practices

  1. Use ServiceFactory<TService, TConfiguration> as base for custom factories
  2. Use GenericServiceFactory<TService, TConfiguration> for standard service creation
  3. Register factories with AddServiceFactoryProvider() for centralized management
  4. Use MessageLogging methods for structured logging with IGenericMessage return
  5. Return IGenericResult from all factory methods instead of throwing exceptions
  6. Use ServiceLifetimes.Scoped, ServiceLifetimes.Singleton, or ServiceLifetimes.Transient for lifetime specification

License

Copyright FractalDataWorks. All rights reserved.

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
Loading failed