< Summary

Information
Class: Elsa.Workflows.Management.Features.WorkflowManagementFeature
Assembly: Elsa.Workflows.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs
Line coverage
89%
Covered lines: 114
Uncovered lines: 14
Coverable lines: 128
Total lines: 323
Line coverage: 89%
Branch coverage
78%
Covered branches: 11
Total branches: 14
Branch coverage: 78.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs

#LineLine coverage
 1using System.ComponentModel;
 2using System.Diagnostics.CodeAnalysis;
 3using System.Dynamic;
 4using System.Reflection;
 5using System.Text.Json;
 6using System.Text.Json.Nodes;
 7using Elsa.Caching.Features;
 8using Elsa.Common.Codecs;
 9using Elsa.Common.Features;
 10using Elsa.Expressions.Contracts;
 11using Elsa.Expressions.Options;
 12using Elsa.Extensions;
 13using Elsa.Features.Abstractions;
 14using Elsa.Features.Attributes;
 15using Elsa.Features.Services;
 16using Elsa.Workflows.Features;
 17using Elsa.Workflows.LogPersistence;
 18using Elsa.Workflows.Management.Activities.HostMethod;
 19using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
 20using Elsa.Workflows.Management.Contracts;
 21using Elsa.Workflows.Management.Entities;
 22using Elsa.Workflows.Management.Handlers.Notifications;
 23using Elsa.Workflows.Management.Mappers;
 24using Elsa.Workflows.Management.Materializers;
 25using Elsa.Workflows.Management.Models;
 26using Elsa.Workflows.Management.Options;
 27using Elsa.Workflows.Management.Providers;
 28using Elsa.Workflows.Management.Services;
 29using Elsa.Workflows.Management.Stores;
 30using Elsa.Workflows.Options;
 31using Elsa.Workflows.Serialization.Serializers;
 32using JetBrains.Annotations;
 33using Microsoft.Extensions.DependencyInjection;
 34using Microsoft.Extensions.DependencyInjection.Extensions;
 35using Elsa.Common.Serialization;
 36
 37namespace Elsa.Workflows.Management.Features;
 38
 39/// <summary>
 40/// Installs and configures the workflow management feature.
 41/// </summary>
 42[DependsOn(typeof(StringCompressionFeature))]
 43[DependsOn(typeof(MediatorFeature))]
 44[DependsOn(typeof(MemoryCacheFeature))]
 45[DependsOn(typeof(SystemClockFeature))]
 46[DependsOn(typeof(WorkflowsFeature))]
 47[DependsOn(typeof(WorkflowDefinitionsFeature))]
 48[DependsOn(typeof(WorkflowInstancesFeature))]
 49[UsedImplicitly]
 350public class WorkflowManagementFeature(IModule module) : FeatureBase(module)
 51{
 52    private const string PrimitivesCategory = "Primitives";
 53    private const string LookupsCategory = "Lookups";
 54    private const string DynamicCategory = "Dynamic";
 55    private const string DataCategory = "Data";
 56    private const string SystemCategory = "System";
 57
 40258    private Func<IServiceProvider, IWorkflowDefinitionPublisher> _workflowDefinitionPublisher = sp => ActivatorUtilities
 40759    private Func<IServiceProvider, IWorkflowReferenceQuery> _workflowReferenceQuery = sp => ActivatorUtilities.CreateIns
 60
 661    private string CompressionAlgorithm { get; set; } = nameof(None);
 962    private LogPersistenceMode LogPersistenceMode { get; set; } = LogPersistenceMode.Include;
 663    private bool IsReadOnlyMode { get; set; }
 64
 65    /// <summary>
 66    /// A set of activity types to make available to the system.
 67    /// </summary>
 7568    public HashSet<Type> ActivityTypes { get; } = [];
 69
 70    /// <summary>
 71    /// A set of variable types to make available to the system.
 72    /// </summary>
 673    public HashSet<VariableDescriptor> VariableDescriptors { get; } =
 374    [
 375        new(typeof(object), PrimitivesCategory, "The root class for all object in the CLR System."),
 376        new(typeof(string), PrimitivesCategory, "Represents a static string of characters."),
 377        new(typeof(bool), PrimitivesCategory, "Represents a true or false value."),
 378        new(typeof(int), PrimitivesCategory, "A 32 bit integer."),
 379        new(typeof(long), PrimitivesCategory, "A 64 bit integer."),
 380        new(typeof(float), PrimitivesCategory, "A 32 bit floating point number."),
 381        new(typeof(double), PrimitivesCategory, "A 64 bit floating point number."),
 382        new(typeof(decimal), PrimitivesCategory, "A decimal number."),
 383        new(typeof(Guid), PrimitivesCategory, "Represents a Globally Unique Identifier."),
 384        new(typeof(DateTime), PrimitivesCategory, "A value type that represents a date and time."),
 385        new(typeof(DateTimeOffset), PrimitivesCategory, "A value type that consists of a DateTime and a time zone offset
 386        new(typeof(TimeSpan), PrimitivesCategory, "Represents a duration of time."),
 387        new(typeof(IDictionary<string, string>), LookupsCategory, "A dictionary with string key and values."),
 388        new(typeof(IDictionary<string, object>), LookupsCategory, "A dictionary with string key and object values."),
 389        new(typeof(ExpandoObject), DynamicCategory, "A dictionary that can be typed as dynamic to access members using d
 390        new(typeof(JsonElement), DynamicCategory, "A JSON element for reading a JSON structure."),
 391        new(typeof(JsonNode), DynamicCategory, "A JSON node for reading and writing a JSON structure."),
 392        new(typeof(JsonObject), DynamicCategory, "A JSON object for reading and writing a JSON structure."),
 393        new(typeof(byte[]), DataCategory, "A byte array."),
 394        new(typeof(Stream), DataCategory, "A stream."),
 395        new(typeof(LogPersistenceMode), SystemCategory, "A LogPersistenceMode enum value.")
 396    ];
 97
 98    /// <summary>
 99    /// Adds the specified activity type to the system.
 100    /// </summary>
 39101    public WorkflowManagementFeature AddActivity<T>() where T : IActivity => AddActivity(typeof(T));
 102
 103    /// <summary>
 104    /// Adds the specified activity type to the system.
 105    /// </summary>
 106    public WorkflowManagementFeature AddActivity(Type activityType)
 107    {
 39108        ActivityTypes.Add(activityType);
 39109        return this;
 110    }
 111
 112    /// <summary>
 113    /// Adds all types implementing <see cref="IActivity"/> to the system.
 114    /// </summary>
 115    public WorkflowManagementFeature AddActivitiesFrom<TMarker>()
 116    {
 27117        var activityTypes = typeof(TMarker).Assembly.GetExportedTypes()
 4404118            .Where(x => typeof(IActivity).IsAssignableFrom(x) && x is { IsAbstract: false, IsInterface: false, IsGeneric
 27119            .ToList();
 27120        return AddActivities(activityTypes);
 121    }
 122
 123    /// <summary>
 124    /// Adds the specified activity types to the system.
 125    /// </summary>
 126    public WorkflowManagementFeature AddActivities(IEnumerable<Type> activityTypes)
 127    {
 27128        ActivityTypes.AddRange(activityTypes);
 27129        return this;
 130    }
 131
 132    /// <summary>
 133    /// Removes the specified activity type from the system.
 134    /// </summary>
 3135    public WorkflowManagementFeature RemoveActivity<T>() where T : IActivity => RemoveActivity(typeof(T));
 136
 137    /// <summary>
 138    /// Adds the specified activity type to the system.
 139    /// </summary>
 140    public WorkflowManagementFeature RemoveActivity(Type activityType)
 141    {
 3142        ActivityTypes.Remove(activityType);
 3143        return this;
 144    }
 145
 146    /// <summary>
 147    /// Configures the system to add a specific activity host type to the workflow management feature.
 148    /// </summary>
 149    /// <typeparam name="T">The type of the activity host to be added.</typeparam>
 150    /// <param name="key">An optional unique key to associate with the activity host type.</param>
 151    public WorkflowManagementFeature AddActivityHost<T>(string? key = null) where T : class
 152    {
 12153        Module.Services.Configure<HostMethodActivitiesOptions>(options => options.AddType<T>(key));
 6154        return this;
 155    }
 156
 157    /// <summary>
 158    /// Configures the system to add a specific activity host type to the workflow management feature.
 159    /// </summary>
 160    /// <param name="hostType">The type of the activity host to be added.</param>
 161    /// <param name="key">An optional unique key to associate with the activity host type.</param>
 162    public WorkflowManagementFeature AddActivityHost(Type hostType, string? key = null)
 163    {
 0164        Module.Services.Configure<HostMethodActivitiesOptions>(options => options.AddType(hostType, key));
 0165        return this;
 166    }
 167
 168    /// <summary>
 169    /// Adds the specified variable type to the system.
 170    /// </summary>
 0171    public WorkflowManagementFeature AddVariableType<T>(string category) => AddVariableType(typeof(T), category);
 172
 173    /// <summary>
 174    /// Adds the specified variable type to the system.
 175    /// </summary>
 0176    public WorkflowManagementFeature AddVariableType(Type type, string category) => AddVariableTypes([type], category);
 177
 178    /// <summary>
 179    /// Adds the specified variable types to the system.
 180    /// </summary>
 181    public WorkflowManagementFeature AddVariableTypes(IEnumerable<Type> types, string category) =>
 27182        AddVariableTypes(types.Select(x => new VariableDescriptor(x, category, x.GetCustomAttribute<DescriptionAttribute
 183
 184    /// <summary>
 185    /// Adds the specified variable types to the system.
 186    /// </summary>
 187    public WorkflowManagementFeature AddVariableTypes(IEnumerable<VariableDescriptor> descriptors)
 188    {
 3189        VariableDescriptors.AddRange(descriptors);
 3190        return this;
 191    }
 192
 193    /// <summary>
 194    /// Sets the compression algorithm to use for compressing workflow state.
 195    /// </summary>
 196    public WorkflowManagementFeature SetCompressionAlgorithm(string algorithm)
 197    {
 0198        CompressionAlgorithm = algorithm;
 0199        return this;
 200    }
 201
 202    /// <summary>
 203    /// Set the default Log Persistence mode to use for worflow state (default is Include)
 204    /// </summary>
 205    /// <param name="logPersistenceMode">The mode persistence value</param>
 206    public WorkflowManagementFeature SetDefaultLogPersistenceMode(LogPersistenceMode logPersistenceMode)
 207    {
 3208        LogPersistenceMode = logPersistenceMode;
 3209        return this;
 210    }
 211
 212    /// <summary>
 213    /// Enables or disables read-only mode for resources such as workflow definitions.
 214    /// </summary>
 215    /// <returns></returns>
 216    public WorkflowManagementFeature UseReadOnlyMode(bool enabled)
 217    {
 3218        IsReadOnlyMode = enabled;
 3219        return this;
 220    }
 221
 222    public WorkflowManagementFeature UseWorkflowDefinitionPublisher(Func<IServiceProvider, IWorkflowDefinitionPublisher>
 223    {
 0224        _workflowDefinitionPublisher = workflowDefinitionPublisher;
 0225        return this;
 226    }
 227
 228    public WorkflowManagementFeature UseWorkflowReferenceFinder<T>() where T : class, IWorkflowReferenceQuery
 229    {
 0230        Services.TryAddScoped<T>();
 0231        return UseWorkflowReferenceFinder(sp => sp.GetRequiredService<T>());
 232    }
 233
 234    public WorkflowManagementFeature UseWorkflowReferenceFinder(Func<IServiceProvider, IWorkflowReferenceQuery> workflow
 235    {
 0236        _workflowReferenceQuery = workflowReferenceFinder;
 0237        return this;
 238    }
 239
 240    /// <summary>
 241    /// Configures the workflow reference graph builder options.
 242    /// </summary>
 243    /// <param name="configure">A delegate to configure the options.</param>
 244    public WorkflowManagementFeature ConfigureWorkflowReferenceGraph(Action<WorkflowReferenceGraphOptions> configure)
 245    {
 0246        Services.Configure(configure);
 0247        return this;
 248    }
 249
 250    /// <inheritdoc />
 251    [RequiresUnreferencedCode("The assembly containing the specified marker type will be scanned for activity types.")]
 252    public override void Configure()
 253    {
 3254        AddActivitiesFrom<WorkflowManagementFeature>();
 3255    }
 256
 257    /// <inheritdoc />
 258    public override void Apply()
 259    {
 3260        Services
 3261             .AddMemoryStore<WorkflowDefinition, MemoryWorkflowDefinitionStore>()
 3262             .AddMemoryStore<WorkflowInstance, MemoryWorkflowInstanceStore>()
 3263             .AddActivityProvider<TypedActivityProvider>()
 3264             .AddActivityProvider<WorkflowDefinitionActivityProvider>()
 3265             .AddActivityProvider<HostMethodActivityProvider>()
 3266             .AddScoped<IHostMethodActivityDescriber, HostMethodActivityDescriber>()
 3267             .AddScoped<IHostMethodParameterValueProvider, DefaultHostMethodParameterValueProvider>()
 3268             .AddScoped<WorkflowDefinitionActivityDescriptorFactory>()
 3269             .AddScoped<WorkflowDefinitionActivityProvider>()
 3270             .AddScoped<IWorkflowDefinitionActivityRegistryUpdater, WorkflowDefinitionActivityRegistryUpdater>()
 3271             .AddScoped<IMaterializerRegistry, MaterializerRegistry>()
 3272             .AddScoped<IWorkflowDefinitionService, WorkflowDefinitionService>()
 3273             .AddScoped<IWorkflowSerializer, WorkflowSerializer>()
 3274             .AddScoped<IWorkflowValidator, WorkflowValidator>()
 3275             .AddScoped(_workflowReferenceQuery)
 3276             .AddScoped<IWorkflowReferenceGraphBuilder, WorkflowReferenceGraphBuilder>()
 3277             .AddScoped(_workflowDefinitionPublisher)
 3278             .AddScoped<IWorkflowDefinitionImporter, WorkflowDefinitionImporter>()
 3279             .AddScoped<IWorkflowDefinitionExporter, WorkflowDefinitionExporter>()
 3280             .AddSingleton<IFileNameSanitizer, DefaultFileNameSanitizer>()
 3281             .AddScoped<IWorkflowDefinitionManager, WorkflowDefinitionManager>()
 3282             .AddScoped<IWorkflowInstanceManager, WorkflowInstanceManager>()
 3283             .AddScoped<IWorkflowReferenceUpdater, WorkflowReferenceUpdater>()
 3284             .AddScoped<IActivityRegistryPopulator, ActivityRegistryPopulator>()
 3285             .AddSingleton<IExpressionDescriptorRegistry, ExpressionDescriptorRegistry>()
 3286             .AddSingleton<IExpressionDescriptorProvider, DefaultExpressionDescriptorProvider>()
 3287             .AddSerializationOptionsConfigurator<SerializationOptionsConfigurator>()
 3288             .AddScoped<IWorkflowMaterializer, TypedWorkflowMaterializer>()
 3289             .AddScoped<IWorkflowMaterializer, ClrWorkflowMaterializer>()
 3290             .AddScoped<IWorkflowMaterializer, JsonWorkflowMaterializer>()
 3291             .AddScoped<IActivityResolver, WorkflowDefinitionActivityResolver>()
 3292             .AddScoped<IWorkflowInstanceVariableManager, WorkflowInstanceVariableManager>()
 3293             .AddScoped<WorkflowDefinitionMapper>()
 3294             .AddSingleton<VariableDefinitionMapper>()
 3295             .AddSingleton<WorkflowStateMapper>()
 3296             ;
 297
 3298        Services
 3299            .AddNotificationHandler<DeleteWorkflowInstances>()
 3300            .AddNotificationHandler<RefreshActivityRegistry>()
 3301            .AddNotificationHandler<UpdateConsumingWorkflows>()
 3302            .AddNotificationHandler<ValidateWorkflow>()
 3303            ;
 304
 3305        Services.Configure<ManagementOptions>(options =>
 3306        {
 348307            foreach (var activityType in ActivityTypes.Distinct())
 171308                options.ActivityTypes.Add(activityType);
 3309
 267310            foreach (var descriptor in VariableDescriptors.DistinctBy(x => x.Type))
 87311                options.VariableDescriptors.Add(descriptor);
 3312
 3313            options.CompressionAlgorithm = CompressionAlgorithm;
 3314            options.LogPersistenceMode = LogPersistenceMode;
 3315            options.IsReadOnlyMode = IsReadOnlyMode;
 6316        });
 317
 6318        Services.Configure<ExpressionOptions>(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializerContext
 6319        Services.Configure<SerializationTypeOptions>(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializer
 6320        Services.Configure<HostMethodActivitiesOptions>(_ => { });
 6321        Services.Configure<WorkflowReferenceGraphOptions>(_ => { });
 3322    }
 323}