FractalDataWorks.ServiceTypes
0.30.0-alpha.1227
dotnet add package FractalDataWorks.ServiceTypes --version 0.30.0-alpha.1227
NuGet\Install-Package FractalDataWorks.ServiceTypes -Version 0.30.0-alpha.1227
<PackageReference Include="FractalDataWorks.ServiceTypes" Version="0.30.0-alpha.1227" />
<PackageVersion Include="FractalDataWorks.ServiceTypes" Version="0.30.0-alpha.1227" />
<PackageReference Include="FractalDataWorks.ServiceTypes" />
paket add FractalDataWorks.ServiceTypes --version 0.30.0-alpha.1227
#r "nuget: FractalDataWorks.ServiceTypes, 0.30.0-alpha.1227"
#:package FractalDataWorks.ServiceTypes@0.30.0-alpha.1227
#addin nuget:?package=FractalDataWorks.ServiceTypes&version=0.30.0-alpha.1227&prerelease
#tool nuget:?package=FractalDataWorks.ServiceTypes&version=0.30.0-alpha.1227&prerelease
FractalDataWorks.ServiceTypes
A plugin architecture framework that provides type-safe service registration, discovery, and factory creation with source-generated lookups.
Overview
ServiceTypes extend TypeCollections to provide service-specific capabilities including:
- Factory registration and resolution
- Configuration binding with IOptions/IOptionsSnapshot/IOptionsMonitor
- Three-phase registration pattern for DI integration
- Provider-based service resolution
Target Framework
This package targets netstandard2.0 and net10.0.
Core Components
IServiceType Interface Hierarchy
From IServiceType.cs:18-74:
public interface IServiceType<TKey, TService, TFactory, TConfiguration> : IServiceType<TKey, TService, TFactory>
where TKey : IEquatable<TKey>
where TService : IGenericService
where TFactory : IServiceFactory<TService, TConfiguration>
where TConfiguration : IGenericConfiguration
{
}
public interface IServiceType<TKey, TService, TFactory> : IServiceType<TKey, TService>
where TKey : IEquatable<TKey>
where TService : IGenericService
where TFactory : IServiceFactory<TService>
{
}
public interface IServiceType<TKey, TService> : IServiceType<TKey>
where TKey : IEquatable<TKey>
where TService : IGenericService
{
}
public interface IServiceType<TKey> : ITypeOption<TKey, IServiceType<TKey>>
where TKey : IEquatable<TKey>
{
Type ServiceType { get; }
Type FactoryType { get; }
Type ConfigurationType { get; }
}
The non-generic IServiceType interface provides registration methods:
From IServiceType.cs:80-136:
public interface IServiceType : IServiceType<Guid>
{
IServiceCollection RegisterRequiredServices(IServiceCollection services);
void RegisterFactory(ServiceProvider provider, IServiceProvider services);
void RegisterProviderServices(ServiceProvider provider, IServiceProvider services);
}
ServiceTypeBase Hierarchy
From ServiceTypeBase.cs:157-271:
public abstract class ServiceTypeBase<TService, TFactory> : TypeOptionBase<Guid, IServiceType<Guid>>, IServiceType<Guid, TService, TFactory>, IServiceType
where TService : class, IGenericService
where TFactory : class, IServiceFactory<TService>
{
[TypeLookup("ById")]
public new static Guid Id { get; }
[TypeLookup("ByName")]
public new string Name => base.Name;
[TypeLookup("ServiceType")]
public Type ServiceType => typeof(TService);
[TypeLookup("FromConfigurationType")]
public virtual Type ConfigurationType => typeof(IGenericConfiguration);
public string SectionName => ConfigurationKey;
public OptionsLoaderBase OptionsLoader { get; }
public Type FactoryType => typeof(TFactory);
public abstract IServiceCollection RegisterRequiredServices(IServiceCollection services);
public virtual void RegisterFactory(ServiceProvider provider, IServiceProvider services) { }
public virtual void RegisterProviderServices(ServiceProvider provider, IServiceProvider services) { }
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));
}
}
The three-parameter variant adds configuration binding:
From ServiceTypeBase.cs:98-148:
public abstract class ServiceTypeBase<TService, TFactory, TConfiguration> : ServiceTypeBase<TService, TFactory>, IServiceType<Guid, TService, TFactory, TConfiguration>
where TService : class, IGenericService
where TConfiguration : class, IGenericConfiguration
where TFactory : class, IServiceFactory<TService, TConfiguration>
{
[TypeLookup("FromConfigurationType")]
public override Type ConfigurationType => typeof(TConfiguration);
protected void RegisterConfiguration(IServiceCollection services)
{
services.AddOptions<TConfiguration>()
.BindConfiguration(SectionName)
.ValidateDataAnnotations()
.ValidateOnStart();
}
}
The four-parameter variant adds typed provider support:
From ServiceTypeBase.cs:19-88:
public abstract class ServiceTypeBase<TService, TFactory, TConfiguration, TProvider> : ServiceTypeBase<TService, TFactory, TConfiguration>
where TService : class, IGenericService
where TConfiguration : class, IGenericConfiguration
where TFactory : class, IServiceFactory<TService, TConfiguration>
where TProvider : ServiceProvider
{
public abstract void RegisterFactory(TProvider provider, IServiceProvider services);
public virtual void RegisterProviderServices(TProvider provider, IServiceProvider services) { }
}
ServiceTypeCollectionBase
From ServiceTypeCollectionBase.cs:1-35:
public abstract class ServiceTypeCollectionBase<TBase, TGeneric, TService, TConfiguration, TFactory>
where TBase : class, IServiceType<Guid, TService, TFactory, TConfiguration>
where TGeneric : IServiceType<Guid, TService, TFactory, TConfiguration>
where TService : class, IGenericService
where TConfiguration : class, IGenericConfiguration
where TFactory : class, IServiceFactory<TService, TConfiguration>
{
// Source generator provides all implementation:
// - Empty sentinel
// - ById(TKey) method
// - ByName(string) method
// - All() method
// - RegisterAll(IServiceCollection) convenience method
// - Custom lookup methods from [TypeLookup] attributes
// - Static extension methods for each ServiceTypeOption
}
ServiceProvider (Mini-IoC)
From ServiceProvider.cs:1-67:
public class ServiceProvider
{
private readonly Dictionary<Type, object> _services = new();
public ServiceProvider AddSingleton<T>(T instance) where T : class
{
_services[typeof(T)] = instance;
return this;
}
public T GetRequiredService<T>() where T : class
{
if (!_services.TryGetValue(typeof(T), out var service))
{
throw new InvalidOperationException(
$"Service of type {typeof(T).Name} is not registered.");
}
return (T)service;
}
public T? GetService<T>() where T : class
{
return _services.TryGetValue(typeof(T), out var service) ? (T)service : null;
}
}
Attributes
ServiceTypeCollectionAttribute
From ServiceTypeCollectionAttribute.cs:1-115:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ServiceTypeCollectionAttribute : Attribute
{
public ServiceTypeCollectionAttribute(
Type baseType,
Type interfaceType,
Type collectionType,
Type? parentCollection = null,
string? name = null)
{ }
public Type BaseType { get; }
public Type InterfaceType { get; }
public Type CollectionType { get; }
public Type? ParentCollection { get; }
public string? Name { get; }
public bool RestrictToCurrentCompilation { get; set; }
public string? DefaultOptionsLoader { get; set; }
public bool GenerateProvider { get; set; }
public Type? ServiceInterface { get; set; }
public Type? ConfigurationInterface { get; set; }
public Type? ProviderType { get; set; }
public Type? ProviderInterface { get; set; }
}
ServiceTypeOptionAttribute
From ServiceTypeOptionAttribute.cs:1-38:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ServiceTypeOptionAttribute : Attribute
{
public ServiceTypeOptionAttribute(Type collectionType, string name)
{
CollectionType = collectionType;
Name = name;
}
public Type CollectionType { get; }
public string Name { get; }
}
TypeLookupAttribute
From TypeLookupAttribute.cs:1-42:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class TypeLookupAttribute : Attribute
{
public TypeLookupAttribute(
string methodName,
bool returnsList = false,
Type? returnType = null)
{
MethodName = methodName;
ReturnsList = returnsList;
ReturnType = returnType;
}
public string MethodName { get; }
public bool ReturnsList { get; }
public Type? ReturnType { get; }
}
Real-World Example: Connection Types
Collection Declaration
From ConnectionTypes.cs:1-25:
[ServiceTypeCollection(
typeof(ConnectionTypeBase<IGenericConnection, IConnectionFactory<IGenericConnection, IConnectionConfiguration>, IConnectionConfiguration>),
typeof(IConnectionType),
typeof(ConnectionTypes),
GenerateProvider = true,
ServiceInterface = typeof(IGenericConnection),
ConfigurationInterface = typeof(IConnectionConfiguration),
ProviderType = typeof(DefaultConnectionProvider),
ProviderInterface = typeof(IConnectionProvider))]
public partial class ConnectionTypes : ServiceTypeCollectionBase<
ConnectionTypeBase<IGenericConnection, IConnectionFactory<IGenericConnection, IConnectionConfiguration>, IConnectionConfiguration>,
IConnectionType<IGenericConnection, IConnectionConfiguration, IConnectionFactory<IGenericConnection, IConnectionConfiguration>>>
{
}
Base Class
From ConnectionTypeBase.cs:30-55:
public abstract class ConnectionTypeBase<TService, TFactory, TConfiguration> :
ServiceTypeBase<TService, TFactory, TConfiguration, DefaultConnectionProvider>,
IConnectionType<TService, TConfiguration, TFactory>
where TService : class, IGenericConnection
where TConfiguration : class, IConnectionConfiguration
where TFactory : class, IConnectionFactory<TService, TConfiguration>
{
protected ConnectionTypeBase(
string name,
string sectionName,
string displayName,
string description,
OptionsLoaderBase? optionsLoader = null,
string? category = null)
: base(name, sectionName, displayName, description, optionsLoader ?? OptionsLoaderTypes.Reloadable, category ?? "Connection")
{
}
}
Concrete Implementation
From MsSqlConnectionType.cs:41-86:
[ServiceTypeOption(typeof(ConnectionTypes), "MsSql")]
public sealed class MsSqlConnectionType : ConnectionTypeBase<IGenericConnection, IMsSqlConnectionFactory, MsSqlConnectionConfiguration>
{
public MsSqlConnectionType() : base(
name: "MsSql",
sectionName: "MsSql",
displayName: "SQL Server",
description: "Microsoft SQL Server database connection",
category: "Database")
{
}
public override IServiceCollection RegisterRequiredServices(IServiceCollection services)
{
services.AddSingleton<IMsSqlConnectionFactory, MsSqlConnectionFactory>();
return services;
}
public override void RegisterFactory(DefaultConnectionProvider provider, IServiceProvider services)
{
var factory = services.GetRequiredService<IMsSqlConnectionFactory>();
provider.RegisterFactory(Name, factory);
}
}
OptionsLoader Types
ServiceTypes use OptionsLoader to control configuration lifetime. Three options are available:
From SingletonOptionsLoader.cs:24-31:
[TypeOption(typeof(OptionsLoaderTypes), "Singleton")]
public sealed class SingletonOptionsLoader : OptionsLoaderBase
{
public SingletonOptionsLoader() : base(1, "Singleton") { }
public override string OptionsInterfaceName => "IOptions";
public override bool SupportsHotReload => false;
}
From ScopedOptionsLoader.cs:27-34:
[TypeOption(typeof(OptionsLoaderTypes), "Scoped")]
public sealed class ScopedOptionsLoader : OptionsLoaderBase
{
public ScopedOptionsLoader() : base(2, "Scoped") { }
public override string OptionsInterfaceName => "IOptionsSnapshot";
public override bool SupportsHotReload => false;
}
From ReloadableOptionsLoader.cs:28-35:
[TypeOption(typeof(OptionsLoaderTypes), "Reloadable")]
public sealed class ReloadableOptionsLoader : OptionsLoaderBase
{
public ReloadableOptionsLoader() : base(3, "Reloadable") { }
public override string OptionsInterfaceName => "IOptionsMonitor";
public override bool SupportsHotReload => true;
}
| Loader | IOptions Interface | When to Use |
|---|---|---|
SingletonOptionsLoader |
IOptions<T> | Static configuration that never changes |
ScopedOptionsLoader |
IOptionsSnapshot<T> | Multi-tenant, per-request configuration |
ReloadableOptionsLoader |
IOptionsMonitor<T> | Database config, hot reload needed |
Cross-Assembly Registration
ServiceTypes use a deferred freeze pattern for cross-assembly type discovery. This ensures ServiceTypeOptions defined in separate NuGet packages are registered before the collection is accessed.
The Problem
sequenceDiagram
participant App as Your Application
participant Col as ConnectionTypes
participant Lib as MsSql Package
Note over App: Application starts
App->>Col: ConnectionTypes.All()
Note over Col: Collection freezes!
Col-->>App: Returns 0 items
Note over Lib: MsSql static ctor never ran
Static constructors only run when something in that assembly is accessed. If you call ConnectionTypes.All() before any code references MsSqlConnectionType, the MsSql library is never loaded.
The Solution: Module Initializers
The Registration source generator creates module initializers in consuming assemblies that register all ServiceTypeOptions from referenced packages:
sequenceDiagram
participant CLR as .NET Runtime
participant Init as Module Initializer
participant Col as ConnectionTypes
participant App as Main()
Note over CLR: Assembly loads
CLR->>Init: [ModuleInitializer] runs
Init->>Col: RegisterMember(new MsSqlConnectionType())
Note over Col: Added to pending list
CLR->>App: Main() starts
App->>Col: ConnectionTypes.All()
Note over Col: Freezes with MsSql
Col-->>App: Returns 1 item
Registration Flow
flowchart TB
subgraph CompileTime["Compile Time"]
A[Library defines ServiceTypeOption] --> B[Static ctor registers local options]
C[Consumer references library] --> D[Registration generator scans references]
D --> E[Generates module initializer]
end
subgraph BeforeMain["Runtime - Before Main()"]
F[Assembly loads] --> G[Module initializer runs]
G --> H[RegisterMember called]
H --> I[Options in pending list]
end
subgraph FirstAccess["Runtime - First Access"]
J[Code calls All/ByName] --> K[EnsureFrozen]
K --> L[Collection freezes]
L --> M[FrozenDictionary created]
end
CompileTime --> BeforeMain --> FirstAccess
Generated Code
The collection generator produces this registration infrastructure:
public partial class ConnectionTypes
{
// Pending registrations (before freeze)
private static readonly List<IServiceType> _pendingRegistrations = new();
private static readonly object _lock = new();
private static volatile bool _frozen;
private static FrozenDictionary<Guid, IConnectionType>? _all;
// Static constructor - registers options discovered at compile time
static ConnectionTypes()
{
// Only options in THIS assembly (Abstractions has none)
}
// Called by module initializers from consuming assemblies
public static void RegisterMember(IServiceType type)
{
if (_frozen)
throw new InvalidOperationException("Collection is frozen");
lock (_lock)
{
if (!_pendingRegistrations.Any(p => p.Id == type.Id))
_pendingRegistrations.Add(type);
}
}
// Called on first access to Any lookup method
private static void EnsureFrozen()
{
if (_all != null) return;
lock (_lock)
{
_frozen = true;
_all = _pendingRegistrations
.Cast<IConnectionType>()
.ToFrozenDictionary(x => x.Id);
}
}
}
The Registration generator produces this in consuming assemblies:
// Generated in YOUR application
internal static class ServiceTypeOptionModuleInitializer
{
[ModuleInitializer]
internal static void RegisterServiceTypeOptions()
{
ConnectionTypes.RegisterMember(new MsSqlConnectionType());
}
}
For Package Authors
To enable transitive registration for consumers, embed the Registration generator:
<ItemGroup>
<ProjectReference Include="..\Collections.SourceGenerators.Registration\..."
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
<None Include="$(OutputPath)FractalDataWorks.Collections.SourceGenerators.Registration.dll"
Pack="true"
PackagePath="analyzers/dotnet/cs" />
</ItemGroup>
Configuration Binding
Each ServiceTypeOption is responsible for binding its own configuration section via the Configure() method:
// MsSqlConnectionType.cs
public override void Configure(IServiceCollection services, IConfiguration configuration)
{
services.Configure<List<MsSqlConnectionConfiguration>>(
configuration.GetSection("Connections:MsSql"));
}
The source-generated ConfigureAll() method iterates through all registered ServiceTypes:
// Generated in ConnectionTypes
public static void ConfigureAll(IServiceCollection services, IConfiguration configuration)
{
EnsureFrozen(); // Freezes the collection first!
foreach (var serviceType in _all!.Values)
{
serviceType.Configure(services, configuration);
}
}
Configuration Binding Flow
sequenceDiagram
participant Init as Module Initializer
participant Col as ConnectionTypes
participant App as Program.cs
participant MsSql as MsSqlConnectionType
Note over Init: Assembly loads (before Main)
Init->>Col: RegisterMember(new MsSqlConnectionType())
Note over Col: Added to pending list
Note over App: ConfigureServices starts
App->>Col: ConnectionTypes.ConfigureAll(services, config)
Col->>Col: EnsureFrozen()
Note over Col: Collection freezes with MsSql included
loop For each ServiceType
Col->>MsSql: Configure(services, configuration)
MsSql->>App: services.Configure<List<MsSqlConfig>>(...)
end
Note over App: Configuration sections bound to IOptions
Critical: ConfigureAll() calls EnsureFrozen() first. All ServiceTypeOptions must be registered (via module initializers) BEFORE ConfigureAll() is called, otherwise their configuration won't be bound.
Usage in Program.cs
var builder = WebApplication.CreateBuilder(args);
// Configuration binding - must happen after module initializers run
// (which happens automatically before Main())
ConnectionTypes.ConfigureAll(builder.Services, builder.Configuration);
// Three-phase DI registration
ConnectionTypes.RegisterAll(builder.Services);
var app = builder.Build();
// Initialize factories (Phase 2 completion)
ConnectionTypes.InitializeFactories(app.Services);
Three-Phase DI Registration Pattern
ServiceTypes use a three-phase registration pattern for DI integration:
flowchart LR
subgraph Phase1["Phase 1: RegisterRequiredServices"]
A[Register factories as singletons]
B[Register infrastructure services]
end
subgraph Phase2["Phase 2: RegisterFactory"]
C[Resolve factory from DI]
D[Register with typed provider]
end
subgraph Phase3["Phase 3: RegisterProviderServices"]
E[Register config loaders]
F[Register provider-scoped services]
end
Phase1 --> Phase2 --> Phase3
Phase 1: RegisterRequiredServices - Register infrastructure and factories with main DI container Phase 2: RegisterFactory - Resolve factories from DI and register with typed provider Phase 3: RegisterProviderServices - Register services scoped to the provider
See the MsSqlConnectionType example above for the complete pattern.
Configuration Self-Registration Pattern
Each ServiceType is responsible for loading its own configuration from the database. This replaces the previous centralized header table pattern (cfg.Configuration) with a distributed approach where each service type manages its own configuration tables.
How It Works
- Define Configuration Table: Use
[ManagedConfiguration]attribute to specify database schema:
[ManagedConfiguration(
Schema = "cfg",
TableName = "MsSqlConnection",
Parent = nameof(ConnectionConfigurationBase<MsSqlConnectionConfiguration>),
ServiceCategory = "Connection",
ServiceType = "MsSql")]
public partial class MsSqlConnectionConfiguration : ConnectionConfigurationBase<MsSqlConnectionConfiguration>
{
// Type-specific properties loaded from cfg.MsSqlConnection table
}
- Implement Configure Method: Each ServiceType should implement a
Configure()method to load its configuration:
// TODO: This pattern is being implemented via ConfigureAll()
public override void Configure(IConfiguration configuration, IServiceProvider services)
{
// Load type-specific configuration from database
var configService = services.GetRequiredService<IConfigurationService>();
var configs = await configService.LoadAsync<MsSqlConnectionConfiguration>();
// Register with IOptions or directly with provider
}
- ConfigureAll Pattern: The
{ServiceType}Types.ConfigureAll()method will iterate through all registered service types and call theirConfigure()methods.
Benefits
- Decoupled: Each ServiceType manages its own configuration independently
- Extensible: New service types can define their own tables without modifying core schema
- Type-Safe: Configuration classes are strongly typed via source generation
- Lazy Loading: Configuration is loaded only when the ServiceType is used
Dependencies
- FractalDataWorks.Abstractions
- FractalDataWorks.Results
- FractalDataWorks.Configuration.Abstractions
- Microsoft.Extensions.Configuration.Abstractions
- Microsoft.Extensions.DependencyInjection.Abstractions
- Microsoft.Extensions.Options
Related Packages
- FractalDataWorks.Collections - Base TypeCollection framework
- FractalDataWorks.Configuration - OptionsLoader implementations
- FractalDataWorks.Services.Connections - Connection service types
| Product | Versions 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. |
-
.NETStandard 2.0
- FractalDataWorks.Abstractions (>= 0.30.0-alpha.1227)
- FractalDataWorks.Configuration.Abstractions (>= 0.30.0-alpha.1227)
- FractalDataWorks.MessageLogging.Abstractions (>= 0.30.0-alpha.1227)
- FractalDataWorks.Results (>= 0.30.0-alpha.1227)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Options (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
- Microsoft.Extensions.Options.DataAnnotations (>= 10.0.0)
-
net10.0
- FractalDataWorks.Abstractions (>= 0.30.0-alpha.1227)
- FractalDataWorks.Configuration.Abstractions (>= 0.30.0-alpha.1227)
- FractalDataWorks.MessageLogging.Abstractions (>= 0.30.0-alpha.1227)
- FractalDataWorks.Results (>= 0.30.0-alpha.1227)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Options (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
- Microsoft.Extensions.Options.DataAnnotations (>= 10.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on FractalDataWorks.ServiceTypes:
| Package | Downloads |
|---|---|
|
CyberdyneDevelopment.Mc3Po.Tools.Abstractions
Tool abstractions for FractalDataWorks Roslyn development tools. Provides TypeCollections for tool categories and parameter types. |
|
|
CyberdyneDevelopment.Mc3Po.Protocols
Protocol infrastructure for mc3-po - base classes, provider, and ServiceType integration |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|