elsa-core/src/common/Elsa.Features/Implementations/Module.cs

173 lines
6.4 KiB
C#
Raw Normal View History

using System.ComponentModel;
using System.Reflection;
using Elsa.Extensions;
using Elsa.Features.Attributes;
using Elsa.Features.Contracts;
using Elsa.Features.Models;
using Elsa.Features.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
namespace Elsa.Features.Implementations;
/// <inheritdoc />
public class Module : IModule
{
private sealed record HostedServiceDescriptor(int Order, Type Type);
private Dictionary<Type, IFeature> _features = new();
private readonly HashSet<IFeature> _configuredFeatures = new();
private readonly List<HostedServiceDescriptor> _hostedServiceDescriptors = new();
/// <summary>
/// Constructor.
/// </summary>
public Module(IServiceCollection services)
{
Services = services;
}
/// <inheritdoc />
public IServiceCollection Services { get; }
2023-04-17 21:58:18 +00:00
/// <inheritdoc />
public IDictionary<object, object> Properties { get; } = new Dictionary<object, object>();
Minor improvements and bug fixes following the 3.1 release (#5168) * Move DynamicActivity.cs to Activities directory The DynamicActivity.cs file has been moved from the Models directory to the Activities directory. This reorganization aims to ensure that the file's location correctly reflects its namespace. * Add GetOutput method in ActivityExtensions A new GetOutput method has been added to the ActivityExtensions.cs file. This method allows the retrieval of output with a specific name from an activity. Useful for handling complex types in workflow activities. * Add feature check and refactor dependencies in Elsa The commit introduces a new feature check in the `Module` class and refactors the dependencies in MassTransit features. Specifically, it enables querying for a specific feature before configuring the dispatcher endpoints, increasing flexibility and control. In addition, the responsibility for creating `IEndpointChannelFormatter` has been shifted from `MassTransitWorkflowDispatcherFeature` to `MassTransitFeature`, aligning with responsibility distribution. Fixes #5165 * Add HasFeature method to IModule interface The IModule interface has been updated to include two methods, HasFeature<T>() and HasFeature(Type featureType). These methods are designed to check if a specific type of feature has been configured, enhancing the functionality provided by the interface. * Add WorkflowRuntimeFeature dependency Removed unused namespaces from WorkflowsApiFeature class and added a new dependency on WorkflowRuntimeFeature. This change enhances the code cleanliness and ensures all required dependencies are correctly linked. * Add activity completion functionality to multiple contexts This commit introduces multiple methods to handle activity completion across various contexts, including ActivityExecutionContext and ActivityCompletedContext. It also includes updates to bookmark serialization and the WorkflowRuntime. The resulting changes should improve handling of activity outcomes and status updates in the application flow. * Handle null options in DefaultWorkflowRuntime Added null-conditional operators to prevent potential NullReferenceExceptions in DefaultWorkflowRuntime. This change ensures that even if the 'options' object is null, the code will not throw an exception and will instead use default values where applicable. * Add ElsaDbContextOptions to DbContextOptionsBuilder A line of code is added to enable applying ElsaDbContextOptions as default in DbContextOptionsBuilder within PersistenceFeatureBase. This change specifies the use of ElsaDbContextOptions when configuring the context options, enhancing the database context setup in the EntityFrameworkCore.Common module. * Remove whitespace in Elsa.Server.Web.csproj This commit removes unnecessary whitespaces at the end of the ProjectReference and PackageReference elements, in the Elsa.Server.Web.csproj file. This improves the readability and alignment of the code and follows the best practice for XML file format. * Add MongoDB to docker-compose.yml A MongoDB service has been added to the docker-compose file. The configuration includes port mapping and volume mapping for MongoDB data storage. This allows more flexibility in our environment setup with MongoDB now being spun up automatically. * Add collection check in MongoDbStore before bulk save Adjusted code structure, and divided longer lines of code into smaller, multi-line chunks for better readability. This refactoring makes the underlying operations and structuring of the code more apparent, aiding in future code maintenance and understanding. * Change target branch in packages.yml workflow This commit modifies the Github actions workflow for packaging. The branch from which to fetch changes is now specified explicitly as 'origin/patch/3.1.1' instead of the default 'origin/main'. This adjustment is specific for package creation under certain conditions.
2024-04-02 05:41:46 +00:00
/// <inheritdoc />
public bool HasFeature<T>() where T : class, IFeature
{
return HasFeature(typeof(T));
}
/// <inheritdoc />
public bool HasFeature(Type featureType)
{
return _features.ContainsKey(featureType);
}
/// <inheritdoc />
Fix MongoDB serialization issues (#6762) * Ongoing MongoDB work * Refactor MongoDB serializer configuration and improve type handling - Added `BsonSerializerHelpers` for streamlined serializer registration with error handling. - Introduced `ConfigureMongoDbSerializers` hosted service to centralize serializer setup. - Enhanced `FlowScopeSerializer` to handle additional BSON types. - Cleaned up and reorganized MongoDB feature implementations, removing redundant code and improving consistency. * Remove `BsonSerializerHelpers` and update MongoDB serializer registration - Deleted `BsonSerializerHelpers` as it was redundant. - Updated `ConfigureMongoDbSerializers` to directly register serializers using `BsonSerializer`. - Simplified `FlowScopeSerializer` null handling for improved readability. * Switch persistence provider to Entity Framework Core in `Program.cs`. * Update src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Configures MongoDB services and options. Configures MongoDB services, including client and database creation. Registers default naming strategy and collection naming strategy. Adds BsonClassMap configuration for KeyValuePair. * Simplify null check in `FlowScopeSerializer`. * Allow `FlowScopeSerializer` to handle nullable `FlowScope`. * Registers FlowScope BSON class map Registers the `FlowScope` class with BSON to enable proper serialization and deserialization of workflow scopes within MongoDB. This ensures that workflow scopes, which are used to manage variables within a workflow, are correctly stored and retrieved from the database. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-04 07:46:20 +00:00
public T Configure<T>(Action<T>? configure = null) where T : class, IFeature
{
return Configure(module => (T)Activator.CreateInstance(typeof(T), module)!, configure);
}
/// <inheritdoc />
Fix MongoDB serialization issues (#6762) * Ongoing MongoDB work * Refactor MongoDB serializer configuration and improve type handling - Added `BsonSerializerHelpers` for streamlined serializer registration with error handling. - Introduced `ConfigureMongoDbSerializers` hosted service to centralize serializer setup. - Enhanced `FlowScopeSerializer` to handle additional BSON types. - Cleaned up and reorganized MongoDB feature implementations, removing redundant code and improving consistency. * Remove `BsonSerializerHelpers` and update MongoDB serializer registration - Deleted `BsonSerializerHelpers` as it was redundant. - Updated `ConfigureMongoDbSerializers` to directly register serializers using `BsonSerializer`. - Simplified `FlowScopeSerializer` null handling for improved readability. * Switch persistence provider to Entity Framework Core in `Program.cs`. * Update src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Configures MongoDB services and options. Configures MongoDB services, including client and database creation. Registers default naming strategy and collection naming strategy. Adds BsonClassMap configuration for KeyValuePair. * Simplify null check in `FlowScopeSerializer`. * Allow `FlowScopeSerializer` to handle nullable `FlowScope`. * Registers FlowScope BSON class map Registers the `FlowScope` class with BSON to enable proper serialization and deserialization of workflow scopes within MongoDB. This ensures that workflow scopes, which are used to manage variables within a workflow, are correctly stored and retrieved from the database. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-04 07:46:20 +00:00
public T Configure<T>(Func<IModule, T> factory, Action<T>? configure = null) where T : class, IFeature
{
2023-04-17 22:08:24 +00:00
if (!_features.TryGetValue(typeof(T), out var feature))
{
feature = factory(this);
2023-04-17 22:08:24 +00:00
_features[typeof(T)] = feature;
}
2023-04-17 22:08:24 +00:00
configure?.Invoke((T)feature);
if (!_isApplying)
return (T)feature;
2023-04-17 21:58:18 +00:00
var dependencies = GetDependencyTypes(feature.GetType()).ToHashSet();
2023-04-17 22:08:24 +00:00
foreach (var dependency in dependencies.Select(GetOrCreateFeature))
2023-04-17 21:58:18 +00:00
ConfigureFeature(dependency);
ConfigureFeature(feature);
2023-04-17 22:08:24 +00:00
return (T)feature;
}
/// <inheritdoc />
public IModule ConfigureHostedService<T>(int priority = 0) where T : class, IHostedService
{
return ConfigureHostedService(typeof(T), priority);
}
/// <inheritdoc />
public IModule ConfigureHostedService(Type hostedServiceType, int priority = 0)
{
Fix MongoDB serialization issues (#6762) * Ongoing MongoDB work * Refactor MongoDB serializer configuration and improve type handling - Added `BsonSerializerHelpers` for streamlined serializer registration with error handling. - Introduced `ConfigureMongoDbSerializers` hosted service to centralize serializer setup. - Enhanced `FlowScopeSerializer` to handle additional BSON types. - Cleaned up and reorganized MongoDB feature implementations, removing redundant code and improving consistency. * Remove `BsonSerializerHelpers` and update MongoDB serializer registration - Deleted `BsonSerializerHelpers` as it was redundant. - Updated `ConfigureMongoDbSerializers` to directly register serializers using `BsonSerializer`. - Simplified `FlowScopeSerializer` null handling for improved readability. * Switch persistence provider to Entity Framework Core in `Program.cs`. * Update src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Configures MongoDB services and options. Configures MongoDB services, including client and database creation. Registers default naming strategy and collection naming strategy. Adds BsonClassMap configuration for KeyValuePair. * Simplify null check in `FlowScopeSerializer`. * Allow `FlowScopeSerializer` to handle nullable `FlowScope`. * Registers FlowScope BSON class map Registers the `FlowScope` class with BSON to enable proper serialization and deserialization of workflow scopes within MongoDB. This ensures that workflow scopes, which are used to manage variables within a workflow, are correctly stored and retrieved from the database. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-04 07:46:20 +00:00
_hostedServiceDescriptors.Add(new(priority, hostedServiceType));
return this;
}
2023-04-17 21:58:18 +00:00
private bool _isApplying;
/// <inheritdoc />
public void Apply()
{
2023-04-17 21:58:18 +00:00
_isApplying = true;
var featureTypes = GetFeatureTypes();
2023-04-17 22:08:24 +00:00
_features = featureTypes.ToDictionary(featureType => featureType, featureType => _features.TryGetValue(featureType, out var existingFeature) ? existingFeature : (IFeature)Activator.CreateInstance(featureType, this)!);
2023-04-17 21:58:18 +00:00
// Iterate over a copy of the features to avoid concurrent modification exceptions.
2023-04-17 22:08:24 +00:00
foreach (var feature in _features.Values.ToList())
{
2023-04-17 21:58:18 +00:00
// This will cause additional features to be added to _features.
ConfigureFeature(feature);
}
// Filter out features that depend on other features that are not installed.
_features = ExcludeFeaturesWithMissingDependencies(_features.Values).ToDictionary(x => x.GetType(), x => x);
// Add hosted services in order of priority.
foreach (var hostedServiceDescriptor in _hostedServiceDescriptors.OrderBy(x => x.Order))
Services.TryAddEnumerable(ServiceDescriptor.Singleton(typeof(IHostedService), hostedServiceDescriptor.Type));
2023-04-17 21:58:18 +00:00
// Make sure to use the complete list of features when applying them.
2023-04-17 22:08:24 +00:00
foreach (var feature in _features.Values)
feature.Apply();
// Add a registry of enabled features to the service collection for client applications to reflect on what features are installed.
var registry = new InstalledFeatureRegistry();
foreach (var feature in _features.Values)
{
var type = feature.GetType();
var name = type.Name.Replace("Feature", string.Empty);
var ns = "Elsa";
var displayName = type.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName ?? name;
var description = type.GetCustomAttribute<DescriptionAttribute>()?.Description;
Fix MongoDB serialization issues (#6762) * Ongoing MongoDB work * Refactor MongoDB serializer configuration and improve type handling - Added `BsonSerializerHelpers` for streamlined serializer registration with error handling. - Introduced `ConfigureMongoDbSerializers` hosted service to centralize serializer setup. - Enhanced `FlowScopeSerializer` to handle additional BSON types. - Cleaned up and reorganized MongoDB feature implementations, removing redundant code and improving consistency. * Remove `BsonSerializerHelpers` and update MongoDB serializer registration - Deleted `BsonSerializerHelpers` as it was redundant. - Updated `ConfigureMongoDbSerializers` to directly register serializers using `BsonSerializer`. - Simplified `FlowScopeSerializer` null handling for improved readability. * Switch persistence provider to Entity Framework Core in `Program.cs`. * Update src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Configures MongoDB services and options. Configures MongoDB services, including client and database creation. Registers default naming strategy and collection naming strategy. Adds BsonClassMap configuration for KeyValuePair. * Simplify null check in `FlowScopeSerializer`. * Allow `FlowScopeSerializer` to handle nullable `FlowScope`. * Registers FlowScope BSON class map Registers the `FlowScope` class with BSON to enable proper serialization and deserialization of workflow scopes within MongoDB. This ensures that workflow scopes, which are used to manage variables within a workflow, are correctly stored and retrieved from the database. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-04 07:46:20 +00:00
registry.Add(new(name, ns, displayName, description));
}
Services.AddSingleton<IInstalledFeatureRegistry>(registry);
Integrate shells (#7279) * Add CShells package references and integrate shell features into the application * Annotate shell features with `[ShellFeature]` attribute and update `TempElsaFeature` to use `ConfigureElsa`. * Revert "Annotate shell features with `[ShellFeature]` attribute and update `TempElsaFeature` to use `ConfigureElsa`." This reverts commit e8a875e8f9d14891c5403df50e8ac7e151db25dd. * Introduce `Elsa.ModularServer.Web` with a minimal API, restructure shell feature configuration, and remove obsolete `CShells` dependency * Update `CShells` package references, add Fody weaver, and configure new CShells package sources in `NuGet.Config`. * Adds CShells integration to Elsa Integrates CShells to enhance modularity and extensibility. - Adds CShells related projects to the solution. - Updates NuGet configuration to include CShells preview feed. - Creates initial app settings for CShells configuration. - Adds CShells.AspNetCore project reference. - Implements CShells extensions in the program file. - Creates shell feature classes in Elsa.Common. - Creates shell feature classes in Elsa.Expressions. - Creates shell feature classes in Elsa.Workflows.Core. - Creates shell feature classes in Elsa.Workflows.Management. - Creates shell feature classes in Elsa.Workflows.Runtime. - Creates shell feature classes in Elsa module. * Refactor CShells: enhance pipeline configuration and features Consolidated updates to CShells including a new `ResolverPipelineBuilder` for customizable resolver strategy pipelines. Improved assembly scanning, error handling in web routing, and streamlined shell feature dependencies for better clarity and functionality. * Add feature registration system and FastEndpoints integration Introduced a feature registration infrastructure with `IInstalledFeatureProvider` and related implementations. Added shell-based feature configurations such as caching, SAS tokens, workflows management, and a FastEndpoints integration module to support dynamic API registration. * Refactor shell routing and enhance global route handling Refactored `ShellEndpointRouteBuilder` to simplify initialization and support a combined shell/global route prefix. Enhanced `ShellEndpointRegistrationHandler` to include global route prefix logic and improved feature discovery using pre-resolved descriptors. Updated `Program.cs` for consistent middleware setup. * Refactor feature endpoints to use `IInstalledFeatureProvider` for improved dependency management and simplified implementation * Add display names, descriptions, and dependency enhancements to shell features Standardized `ShellFeature` attributes across `ElsaFeature`, `WorkflowRuntimeFeature`, and `WorkflowManagementFeature` by adding display names, descriptions, and improving dependency declarations. Updated `ElsaFeature` to register `IInstalledFeatureProvider` for feature bridging. * Add FastEndpoints references and update package versions Added project references to CShells.FastEndpoints and related projects in multiple csproj files. Updated FastEndpoints package versions in `Directory.Packages.props` for compatibility with .NET 8/9/10. Removed obsolete folder references from Elsa.Caching.csproj and refined the namespace in CShells.AspNetCore.Abstractions. * Add Identity and DefaultAuthentication features to appsettings.json configuration * Add project references for Elsa.Identity and CShells.FastEndpoints.Abstractions * Add `Identity` and `DefaultAuthentication` shell features with enhanced authentication and authorization support * Set default signing key in `IdentityTokenOptions` for identity configuration * Add service exclusion infrastructure for shell-specific contexts Introduce `IShellServiceExclusionProvider` and `IShellServiceExclusionRegistry` to manage excluded service types per-shell. Implement ASP.NET Core-specific providers for authentication and authorization to enable shell-specific configurations. Refactor `DefaultShellHost` to use the new exclusion registry for service inheritance filtering. * Refactor CShells authentication and authorization APIs Renamed and unified methods for shell authentication and authorization and added a new combined method `WithAuthenticationAndAuthorization`. Enhanced `AddShells` to automatically register a default configuration provider if none is specified. Updated usage in Elsa.ModularServer to utilize the new API. * Add Elsa-specific FastEndpoints configurator and feature Introduce `ElsaFastEndpointsConfigurator` to customize FastEndpoints serialization and value parsing for Elsa workflows. Register this functionality through the new `ElsaFastEndpointsFeature`, which integrates with the shell's dependency injection system using an `IFastEndpointsConfigurator` interface. * Update Workflow API feature dependency to `ElsaFastEndpoints` * Pass `cancellationToken` to `ReadToEndAsync` in `PostEndpoint` for improved request handling. * Add project references for CShells.AspNetCore and CShells.FastEndpoints.Abstractions * Update CShells package versions to `0.0.6-preview.30` and add `CShells.FastEndpoints.Abstractions` * Configures shell routing and features Enables path routing for shells to allow proper routing within each shell. Configures the ElsaFastEndpoints feature to depend on the FastEndpoints feature. This ensures that FastEndpoints is properly configured before Elsa's FastEndpoints configurations are applied. Registers activity types within the WorkflowManagementFeature. This ensures activities are available for workflow construction and execution. * Add shell lifecycle management and notification handlers Introduced interfaces and handlers for shell activation (`IShellActivatedHandler`) and deactivation (`IShellDeactivatingHandler`) to manage shell lifecycles. Added `ShellStartupHostedService` to coordinate shell activation on startup and deactivation on shutdown. Updated notification system to support new shell lifecycle events and renamed existing notification records for consistency. * Introduces EF Core persistence layer Adds base classes and implementations for EF Core persistence, including database provider configuration and shell feature integration. This change introduces a generic approach to configuring EF Core persistence for various Elsa modules, promoting code reuse and simplifying the process of supporting different database providers. It includes: - Base classes for database provider configurators and shell features. - Implementations for Sqlite, SQL Server, MySql, PostgreSql, and Oracle. - Shell features for Alterations, Identity, Labels, Management (Workflow Definitions and Instances), Runtime, and Tenants modules. * Add comprehensive feature configuration validation system Introduce a feature configuration system with support for binding, auto-configuration, and validation using DataAnnotations, FluentValidation, and composite patterns. Includes new validators, binding logic, and extensions to simplify configuration tasks while ensuring robustness and flexibility. * Add persistence shell features for MySql, Oracle, PostgreSql, and Sqlite Introduced new shell features to configure MySql, Oracle, PostgreSql, and Sqlite persistence for workflow definitions and runtime data. Updated `appsettings.json` to replace individual Sqlite features with a unified `SqliteWorkflowPersistence`. Made minor code cleanup in `FastEndpointsFeature`. * Configure shell features for persistence Added `IServiceCollection` configuration for MySql, Oracle, PostgreSql, and Sqlite shell features to set up persistence services. * Remove DatabaseProviderConfigurators and refactor persistence shell features Deleted DatabaseProviderConfigurator classes and restructured persistence shell features by integrating direct configuration logic for MySql, Oracle, PostgreSql, Sqlite, and SqlServer. Simplified configuration by inheriting from abstract shell feature base classes and removed redundant code. * Correct IWorkflowDefinitionPublisher registration to use WorkflowDefinitionPublisher implementation * Add resilience feature and scoped services configuration for Sqlite persistence - Integrated `Microsoft.Extensions.DependencyInjection` to shell features for Sqlite persistence. - Updated `appsettings.json` and project references to include a new 'Resilience' feature. - Changed `ICommitStateHandler` service registration in `WorkflowRuntimeFeature` to use an implementation. * Add `ResilienceShellFeature` for configuring resilience strategies - Implemented new `ResilienceShellFeature` class to manage services related to resilience features. - Added scoped and singleton service registrations for resilience strategies, exception detection, and activity invocation. - Configured expression options for resilience handling in workflows. * Add new shell features: Alterations, Blob Storage, Caching, Clustering, CSharp, Distributed Runtime, ElsaScript, Flowchart, HTTP, JavaScript, Key-Value, and Labels * Switch project references to package references for CShells libraries and update to version 0.0.7. * Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Fix shell feature discovery and remove duplicate service registrations (#7285) * Initial plan * Address PR review comments: Add ShellFeature attributes, fix duplicates, and improve security Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com> * Update dependencies and fix scoped services registration in `WorkflowRuntimeFeature` * Fix null reference and typo in shell feature provider (#7286) * Initial plan * Fix null StartupType guard in Find() and typo in variable descriptor Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2026-02-12 19:30:02 +00:00
Services.AddSingleton<IInstalledFeatureProvider>(sp => new InstalledFeatureProvider(sp.GetRequiredService<IInstalledFeatureRegistry>()));
}
2023-04-17 21:58:18 +00:00
private IEnumerable<IFeature> ExcludeFeaturesWithMissingDependencies(IEnumerable<IFeature> features)
{
return
from feature in features
let featureType = feature.GetType()
let dependencyOfAttributes = featureType.GetCustomAttributes<DependencyOfAttribute>(true).ToList()
let missingDependencies = dependencyOfAttributes.Where(x => !_features.ContainsKey(x.Type)).ToList()
where missingDependencies.Count == 0
select feature;
}
2023-04-17 21:58:18 +00:00
private void ConfigureFeature(IFeature feature)
{
2023-04-17 22:08:24 +00:00
if (_configuredFeatures.Contains(feature))
2023-04-17 21:58:18 +00:00
return;
feature.Configure();
2023-04-17 22:13:40 +00:00
feature.ConfigureHostedServices();
2023-04-17 22:08:24 +00:00
_features[feature.GetType()] = feature;
2023-04-17 21:58:18 +00:00
_configuredFeatures.Add(feature);
}
private IFeature GetOrCreateFeature(Type featureType)
{
2023-04-17 22:08:24 +00:00
return _features.TryGetValue(featureType, out var existingFeature) ? existingFeature : (IFeature)Activator.CreateInstance(featureType, this)!;
2023-04-17 21:58:18 +00:00
}
private HashSet<Type> GetFeatureTypes()
2023-04-17 21:58:18 +00:00
{
2023-04-17 22:08:24 +00:00
var featureTypes = _features.Keys.ToHashSet();
var featureTypesWithDependencies = featureTypes.Concat(featureTypes.SelectMany(GetDependencyTypes)).ToHashSet();
return featureTypesWithDependencies.TSort(x => x.GetCustomAttributes<DependsOnAttribute>(true).Select(dependsOn => dependsOn.Type)).ToHashSet();
2023-04-17 21:58:18 +00:00
}
// Recursively get dependency types.
private IEnumerable<Type> GetDependencyTypes(Type type)
{
var dependencies = type.GetCustomAttributes<DependsOnAttribute>(true).Select(dependsOn => dependsOn.Type).ToList();
2023-04-17 21:58:18 +00:00
return dependencies.Concat(dependencies.SelectMany(GetDependencyTypes));
}
}