< 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
87%
Covered lines: 117
Uncovered lines: 16
Coverable lines: 133
Total lines: 337
Line coverage: 87.9%
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
 40758    private Func<IServiceProvider, IWorkflowDefinitionPublisher> _workflowDefinitionPublisher = sp => ActivatorUtilities
 41259    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; }
 664    private bool FailOnValidationErrors { get; set; } = true;
 65
 66    /// <summary>
 67    /// A set of activity types to make available to the system.
 68    /// </summary>
 7569    public HashSet<Type> ActivityTypes { get; } = [];
 70
 71    /// <summary>
 72    /// A set of variable types to make available to the system.
 73    /// </summary>
 674    public HashSet<VariableDescriptor> VariableDescriptors { get; } =
 375    [
 376        new(typeof(object), PrimitivesCategory, "The root class for all object in the CLR System."),
 377        new(typeof(string), PrimitivesCategory, "Represents a static string of characters."),
 378        new(typeof(bool), PrimitivesCategory, "Represents a true or false value."),
 379        new(typeof(int), PrimitivesCategory, "A 32 bit integer."),
 380        new(typeof(long), PrimitivesCategory, "A 64 bit integer."),
 381        new(typeof(float), PrimitivesCategory, "A 32 bit floating point number."),
 382        new(typeof(double), PrimitivesCategory, "A 64 bit floating point number."),
 383        new(typeof(decimal), PrimitivesCategory, "A decimal number."),
 384        new(typeof(Guid), PrimitivesCategory, "Represents a Globally Unique Identifier."),
 385        new(typeof(DateTime), PrimitivesCategory, "A value type that represents a date and time."),
 386        new(typeof(DateTimeOffset), PrimitivesCategory, "A value type that consists of a DateTime and a time zone offset
 387        new(typeof(TimeSpan), PrimitivesCategory, "Represents a duration of time."),
 388        new(typeof(IDictionary<string, string>), LookupsCategory, "A dictionary with string key and values."),
 389        new(typeof(IDictionary<string, object>), LookupsCategory, "A dictionary with string key and object values."),
 390        new(typeof(ExpandoObject), DynamicCategory, "A dictionary that can be typed as dynamic to access members using d
 391        new(typeof(JsonElement), DynamicCategory, "A JSON element for reading a JSON structure."),
 392        new(typeof(JsonNode), DynamicCategory, "A JSON node for reading and writing a JSON structure."),
 393        new(typeof(JsonObject), DynamicCategory, "A JSON object for reading and writing a JSON structure."),
 394        new(typeof(byte[]), DataCategory, "A byte array."),
 395        new(typeof(Stream), DataCategory, "A stream."),
 396        new(typeof(LogPersistenceMode), SystemCategory, "A LogPersistenceMode enum value.")
 397    ];
 98
 99    /// <summary>
 100    /// Adds the specified activity type to the system.
 101    /// </summary>
 39102    public WorkflowManagementFeature AddActivity<T>() where T : IActivity => AddActivity(typeof(T));
 103
 104    /// <summary>
 105    /// Adds the specified activity type to the system.
 106    /// </summary>
 107    public WorkflowManagementFeature AddActivity(Type activityType)
 108    {
 39109        ActivityTypes.Add(activityType);
 39110        return this;
 111    }
 112
 113    /// <summary>
 114    /// Adds all types implementing <see cref="IActivity"/> to the system.
 115    /// </summary>
 116    public WorkflowManagementFeature AddActivitiesFrom<TMarker>()
 117    {
 27118        var activityTypes = typeof(TMarker).Assembly.GetExportedTypes()
 4515119            .Where(x => typeof(IActivity).IsAssignableFrom(x) && x is { IsAbstract: false, IsInterface: false, IsGeneric
 27120            .ToList();
 27121        return AddActivities(activityTypes);
 122    }
 123
 124    /// <summary>
 125    /// Adds the specified activity types to the system.
 126    /// </summary>
 127    public WorkflowManagementFeature AddActivities(IEnumerable<Type> activityTypes)
 128    {
 27129        ActivityTypes.AddRange(activityTypes);
 27130        return this;
 131    }
 132
 133    /// <summary>
 134    /// Removes the specified activity type from the system.
 135    /// </summary>
 3136    public WorkflowManagementFeature RemoveActivity<T>() where T : IActivity => RemoveActivity(typeof(T));
 137
 138    /// <summary>
 139    /// Adds the specified activity type to the system.
 140    /// </summary>
 141    public WorkflowManagementFeature RemoveActivity(Type activityType)
 142    {
 3143        ActivityTypes.Remove(activityType);
 3144        return this;
 145    }
 146
 147    /// <summary>
 148    /// Configures the system to add a specific activity host type to the workflow management feature.
 149    /// </summary>
 150    /// <typeparam name="T">The type of the activity host to be added.</typeparam>
 151    /// <param name="key">An optional unique key to associate with the activity host type.</param>
 152    public WorkflowManagementFeature AddActivityHost<T>(string? key = null) where T : class
 153    {
 12154        Module.Services.Configure<HostMethodActivitiesOptions>(options => options.AddType<T>(key));
 6155        return this;
 156    }
 157
 158    /// <summary>
 159    /// Configures the system to add a specific activity host type to the workflow management feature.
 160    /// </summary>
 161    /// <param name="hostType">The type of the activity host to be added.</param>
 162    /// <param name="key">An optional unique key to associate with the activity host type.</param>
 163    public WorkflowManagementFeature AddActivityHost(Type hostType, string? key = null)
 164    {
 0165        Module.Services.Configure<HostMethodActivitiesOptions>(options => options.AddType(hostType, key));
 0166        return this;
 167    }
 168
 169    /// <summary>
 170    /// Adds the specified variable type to the system.
 171    /// </summary>
 0172    public WorkflowManagementFeature AddVariableType<T>(string category) => AddVariableType(typeof(T), category);
 173
 174    /// <summary>
 175    /// Adds the specified variable type to the system.
 176    /// </summary>
 0177    public WorkflowManagementFeature AddVariableType(Type type, string category) => AddVariableTypes([type], category);
 178
 179    /// <summary>
 180    /// Adds the specified variable types to the system.
 181    /// </summary>
 182    public WorkflowManagementFeature AddVariableTypes(IEnumerable<Type> types, string category) =>
 27183        AddVariableTypes(types.Select(x => new VariableDescriptor(x, category, x.GetCustomAttribute<DescriptionAttribute
 184
 185    /// <summary>
 186    /// Adds the specified variable types to the system.
 187    /// </summary>
 188    public WorkflowManagementFeature AddVariableTypes(IEnumerable<VariableDescriptor> descriptors)
 189    {
 3190        VariableDescriptors.AddRange(descriptors);
 3191        return this;
 192    }
 193
 194    /// <summary>
 195    /// Sets the compression algorithm to use for compressing workflow state.
 196    /// </summary>
 197    public WorkflowManagementFeature SetCompressionAlgorithm(string algorithm)
 198    {
 0199        CompressionAlgorithm = algorithm;
 0200        return this;
 201    }
 202
 203    /// <summary>
 204    /// Set the default Log Persistence mode to use for worflow state (default is Include)
 205    /// </summary>
 206    /// <param name="logPersistenceMode">The mode persistence value</param>
 207    public WorkflowManagementFeature SetDefaultLogPersistenceMode(LogPersistenceMode logPersistenceMode)
 208    {
 3209        LogPersistenceMode = logPersistenceMode;
 3210        return this;
 211    }
 212
 213    /// <summary>
 214    /// Enables or disables read-only mode for resources such as workflow definitions.
 215    /// </summary>
 216    /// <returns></returns>
 217    public WorkflowManagementFeature UseReadOnlyMode(bool enabled)
 218    {
 3219        IsReadOnlyMode = enabled;
 3220        return this;
 221    }
 222
 223    /// <summary>
 224    /// Enables or disables failing workflow publication when the workflow has validation errors.
 225    /// Defaults to <c>true</c> as of 3.8.0 (publication fails when validation errors are present).
 226    /// Set to <c>false</c> to allow publication to succeed, returning validation errors as warnings.
 227    /// </summary>
 228    public WorkflowManagementFeature UseFailOnValidationErrors(bool enabled = true)
 229    {
 0230        FailOnValidationErrors = enabled;
 0231        return this;
 232    }
 233
 234    public WorkflowManagementFeature UseWorkflowDefinitionPublisher(Func<IServiceProvider, IWorkflowDefinitionPublisher>
 235    {
 0236        _workflowDefinitionPublisher = workflowDefinitionPublisher;
 0237        return this;
 238    }
 239
 240    public WorkflowManagementFeature UseWorkflowReferenceFinder<T>() where T : class, IWorkflowReferenceQuery
 241    {
 0242        Services.TryAddScoped<T>();
 0243        return UseWorkflowReferenceFinder(sp => sp.GetRequiredService<T>());
 244    }
 245
 246    public WorkflowManagementFeature UseWorkflowReferenceFinder(Func<IServiceProvider, IWorkflowReferenceQuery> workflow
 247    {
 0248        _workflowReferenceQuery = workflowReferenceFinder;
 0249        return this;
 250    }
 251
 252    /// <summary>
 253    /// Configures the workflow reference graph builder options.
 254    /// </summary>
 255    /// <param name="configure">A delegate to configure the options.</param>
 256    public WorkflowManagementFeature ConfigureWorkflowReferenceGraph(Action<WorkflowReferenceGraphOptions> configure)
 257    {
 0258        Services.Configure(configure);
 0259        return this;
 260    }
 261
 262    /// <inheritdoc />
 263    [RequiresUnreferencedCode("The assembly containing the specified marker type will be scanned for activity types.")]
 264    public override void Configure()
 265    {
 3266        AddActivitiesFrom<WorkflowManagementFeature>();
 3267    }
 268
 269    /// <inheritdoc />
 270    public override void Apply()
 271    {
 3272        Services
 3273             .AddMemoryStore<WorkflowDefinition, MemoryWorkflowDefinitionStore>()
 3274             .AddMemoryStore<WorkflowInstance, MemoryWorkflowInstanceStore>()
 3275             .AddActivityProvider<TypedActivityProvider>()
 3276             .AddActivityProvider<WorkflowDefinitionActivityProvider>()
 3277             .AddActivityProvider<HostMethodActivityProvider>()
 3278             .AddScoped<IHostMethodActivityDescriber, HostMethodActivityDescriber>()
 3279             .AddScoped<IHostMethodParameterValueProvider, DefaultHostMethodParameterValueProvider>()
 3280             .AddScoped<WorkflowDefinitionActivityDescriptorFactory>()
 3281             .AddScoped<WorkflowDefinitionActivityProvider>()
 3282             .AddScoped<IWorkflowDefinitionActivityRegistryUpdater, WorkflowDefinitionActivityRegistryUpdater>()
 3283             .AddScoped<IMaterializerRegistry, MaterializerRegistry>()
 3284             .AddScoped<IWorkflowDefinitionService, WorkflowDefinitionService>()
 3285             .AddScoped<IWorkflowSerializer, WorkflowSerializer>()
 3286             .AddScoped<IWorkflowValidator, WorkflowValidator>()
 3287             .AddScoped(_workflowReferenceQuery)
 3288             .AddScoped<IWorkflowReferenceGraphBuilder, WorkflowReferenceGraphBuilder>()
 3289             .AddScoped(_workflowDefinitionPublisher)
 3290             .AddScoped<IWorkflowDefinitionImporter, WorkflowDefinitionImporter>()
 3291             .AddScoped<IWorkflowDefinitionExporter, WorkflowDefinitionExporter>()
 3292             .AddSingleton<IFileNameSanitizer, DefaultFileNameSanitizer>()
 3293             .AddScoped<IWorkflowDefinitionManager, WorkflowDefinitionManager>()
 3294             .AddScoped<IWorkflowInstanceManager, WorkflowInstanceManager>()
 3295             .AddScoped<IWorkflowReferenceUpdater, WorkflowReferenceUpdater>()
 3296             .AddScoped<IActivityRegistryPopulator, ActivityRegistryPopulator>()
 3297             .AddSingleton<IExpressionDescriptorRegistry, ExpressionDescriptorRegistry>()
 3298             .AddSingleton<IExpressionDescriptorProvider, DefaultExpressionDescriptorProvider>()
 3299             .AddSerializationOptionsConfigurator<SerializationOptionsConfigurator>()
 3300             .AddScoped<IWorkflowMaterializer, TypedWorkflowMaterializer>()
 3301             .AddScoped<IWorkflowMaterializer, ClrWorkflowMaterializer>()
 3302             .AddScoped<IWorkflowMaterializer, JsonWorkflowMaterializer>()
 3303             .AddScoped<IActivityResolver, WorkflowDefinitionActivityResolver>()
 3304             .AddScoped<IWorkflowInstanceVariableManager, WorkflowInstanceVariableManager>()
 3305             .AddScoped<WorkflowDefinitionMapper>()
 3306             .AddSingleton<VariableDefinitionMapper>()
 3307             .AddSingleton<WorkflowStateMapper>()
 3308             ;
 309
 3310        Services
 3311            .AddNotificationHandler<DeleteWorkflowInstances>()
 3312            .AddNotificationHandler<RefreshActivityRegistry>()
 3313            .AddNotificationHandler<UpdateConsumingWorkflows>()
 3314            .AddNotificationHandler<ValidateWorkflow>()
 3315            .AddNotificationHandler<ValidateOutputConverters>()
 3316            ;
 317
 3318        Services.Configure<ManagementOptions>(options =>
 3319        {
 348320            foreach (var activityType in ActivityTypes.Distinct())
 171321                options.ActivityTypes.Add(activityType);
 3322
 267323            foreach (var descriptor in VariableDescriptors.DistinctBy(x => x.Type))
 87324                options.VariableDescriptors.Add(descriptor);
 3325
 3326            options.CompressionAlgorithm = CompressionAlgorithm;
 3327            options.LogPersistenceMode = LogPersistenceMode;
 3328            options.IsReadOnlyMode = IsReadOnlyMode;
 3329            options.FailOnValidationErrors = FailOnValidationErrors;
 6330        });
 331
 6332        Services.Configure<ExpressionOptions>(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializerContext
 6333        Services.Configure<SerializationTypeOptions>(options => options.RegisterTypeAlias(typeof(ClrWorkflowMaterializer
 6334        Services.Configure<HostMethodActivitiesOptions>(_ => { });
 6335        Services.Configure<WorkflowReferenceGraphOptions>(_ => { });
 3336    }
 337}