diff --git a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Entities/Order.cs b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Entities/Order.cs index 90309c9faf..a4d4a7f8c0 100644 --- a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Entities/Order.cs +++ b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Entities/Order.cs @@ -1,3 +1,3 @@ namespace Elsa.Samples.AspNet.WorkflowContexts.Entities; -public class Order{} \ No newline at end of file +public class Order; \ No newline at end of file diff --git a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Providers/CustomerWorkflowContextProvider.cs b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Providers/CustomerWorkflowContextProvider.cs index 5813e8ace8..54133efd68 100644 --- a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Providers/CustomerWorkflowContextProvider.cs +++ b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Providers/CustomerWorkflowContextProvider.cs @@ -6,26 +6,19 @@ namespace Elsa.Samples.AspNet.WorkflowContexts.Providers; -public class CustomerWorkflowContextProvider : WorkflowContextProvider +public class CustomerWorkflowContextProvider(ICustomerStore customerStore) : WorkflowContextProvider { - private readonly ICustomerStore _customerStore; - - public CustomerWorkflowContextProvider(ICustomerStore customerStore) - { - _customerStore = customerStore; - } - protected override async ValueTask LoadAsync(WorkflowExecutionContext workflowExecutionContext) { var customerId = workflowExecutionContext.GetCustomerId(); - return customerId != null ? await _customerStore.GetAsync(customerId) : null; + return customerId != null ? await customerStore.GetAsync(customerId) : null; } protected override async ValueTask SaveAsync(WorkflowExecutionContext workflowExecutionContext, Customer? context) { if (context != null) { - await _customerStore.SaveAsync(context); + await customerStore.SaveAsync(context); workflowExecutionContext.SetCustomerId(context.Id); } } diff --git a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/README.md b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/README.md index 1a514869eb..bf37ae2c6c 100644 --- a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/README.md +++ b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/README.md @@ -1,6 +1,14 @@ # Server -This project represents an Elsa application that hosts workflows and exposes API endpoints to manage & execute workflows. +This project demonstrates how to use Workflow Contexts. + +A Workflow Context represents a custom, application-specific object provided to the workflow at runtime. +For example, if your workflow handles a Customer, a custom workflow context provider could provide this customer automatically to the workflow without the need for custom activities that load & persist updates to this customer. +Instead, the custom context provider would load the customer into memory once before the workflow starts and persists changes made to the customer (if any) when the workflow execution ends. + +In this sample project, we handle two custom objects: Customer and Order. + +To start the `CustomerCommunicationsWorkflow`, start it using the REST API or from Elsa Studio. ## Secrets The following are the secrets stored in hashed form in appsettings.json: diff --git a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Workflows/CustomerCommunicationsWorkflow.cs b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Workflows/CustomerCommunicationsWorkflow.cs index 91ffb48a53..4b4597c2ef 100644 --- a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Workflows/CustomerCommunicationsWorkflow.cs +++ b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/Workflows/CustomerCommunicationsWorkflow.cs @@ -10,11 +10,12 @@ namespace Elsa.Samples.AspNet.WorkflowContexts.Workflows; -/// -/// A workflow that sends annoying emails to customers. -/// +/// A workflow that sends helpful emails to customers. public class CustomerCommunicationsWorkflow : WorkflowBase { + private static string CustomerId = "2"; + + /// protected override void Build(IWorkflowBuilder builder) { builder.AddWorkflowContextProvider(); @@ -23,35 +24,34 @@ protected override void Build(IWorkflowBuilder builder) { Activities = { - SetWorkflowContextParameter.For( - context => context.GetInput("CustomerId")!), + SetWorkflowContextParameter.For(CustomerId), Delay.FromSeconds(5), new SendEmail { Subject = new(context => $"Welcome to our family, {context.GetCustomer().Name}!"), Body = new("Welcome aboard!"), - To = new(context => new[] { context.GetCustomer().Email }) + To = new(context => [context.GetCustomer().Email]) }, Delay.FromSeconds(5), new SendEmail { Subject = new(context => $"{context.GetCustomer().Name}, we got great deals for you!"), Body = new("Get your creditcard ready!"), - To = new(context => new[] { context.GetCustomer().Email }) + To = new(context => [context.GetCustomer().Email]) }, Delay.FromSeconds(5), new SendEmail { Subject = new(context => $"{context.GetCustomer().Name}, you're missing out!"), Body = new("Sale ends in 2 hours!"), - To = new(context => new[] { context.GetCustomer().Email }) + To = new(context => [context.GetCustomer().Email]) }, Delay.FromSeconds(5), new SendEmail { Subject = new(context => $"{context.GetCustomer().Name}, the clock is ticking!"), Body = new("Tick tik tick!"), - To = new(context => new[] { context.GetCustomer().Email }) + To = new(context => [context.GetCustomer().Email]) }, } }; diff --git a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/appsettings.json b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/appsettings.json index b8d0788786..a5f549d8db 100644 --- a/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/appsettings.json +++ b/samples/aspnet/Elsa.Samples.AspNet.WorkflowContexts/appsettings.json @@ -1,14 +1,8 @@ { "Logging": { "LogLevel": { - "Default": "Debug", - "Elsa.Mediator": "Warning", - "MassTransit": "Warning", - "Microsoft.Extensions.Http": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "Microsoft.EntityFrameworkCore": "Warning", - "Microsoft.AspNetCore": "Warning", - "System.Net.Http": "Warning" + "Default": "Warning", + "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", @@ -17,7 +11,7 @@ }, "Identity": { "Tokens": { - "SigningKey": "secret-signing-key", + "SigningKey": "or*bHQ26K9yjT4wsqk8k7h*!jCgvctzM89Zt@ENFGeuT-xZWQ9i.36u6YBhXBZut", "AccessTokenLifetime": "1:00:00:00", "RefreshTokenLifetime": "1:00:10:00" }, diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs index 4d2ba3ef55..f3fe5d0ebe 100644 --- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinition.cs @@ -58,11 +58,6 @@ public class WorkflowDefinition : LinkedEntity /// public IDictionary CustomProperties { get; set; } = new Dictionary(); - /// - /// Stores custom information about the workflow. Can be used to store application-specific properties to associate with the workflow. - /// - public PropertyBag PropertyBag { get; set; } = new(); - /// /// The name of the workflow provider that created this workflow, if any. /// diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs index 76dba636d3..a617b54f35 100644 --- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs +++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowDefinitionModel.cs @@ -55,11 +55,6 @@ public class WorkflowDefinitionModel : LinkedEntity /// public IDictionary? CustomProperties { get; set; } - /// - /// Stores custom information about the workflow. Can be used to store application-specific properties to associate with the workflow. - /// - public PropertyBag PropertyBag { get; set; } = new(); - /// /// Gets or sets whether the workflow definition is read-only. /// diff --git a/src/modules/Elsa.Common/Extensions/PropertyBagExtensions.cs b/src/modules/Elsa.Common/Extensions/PropertyBagExtensions.cs deleted file mode 100644 index ad0359c213..0000000000 --- a/src/modules/Elsa.Common/Extensions/PropertyBagExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Text.Json; -using Elsa.Common.Models; - -// ReSharper disable once CheckNamespace -namespace Elsa.Extensions; - -/// -/// Provides extension methods for the PropertyBag class. -/// -public static class PropertyBagExtensions -{ - /// - /// Tries to retrieve a value from the PropertyBag based on the provided key. - /// If the specified key does not exist in the PropertyBag, the method will return the default value obtained from the defaultValue function. - /// - /// The type of the value to retrieve. - /// The PropertyBag to retrieve the value from. - /// The key of the value to retrieve. - /// A function that returns the default value to be returned if the key does not exist in the PropertyBag. - /// Optional JSON serializer options. - /// The value associated with the key, or the default value if the key does not exist. - public static T TryGetValueOrDefault(this PropertyBag propertyBag, string key, Func defaultValue, JsonSerializerOptions? options = null) - { - if (!propertyBag.TryGetValue(key, out var value)) - return defaultValue(); - - var json = (string)value; - return JsonSerializer.Deserialize(json, options); - } - - /// - /// Tries to retrieve a value from the PropertyBag based on the provided key. - /// If the specified key does not exist in the PropertyBag, the method will return the default value obtained from the defaultValue function. - /// - /// The type of the value to retrieve. - /// The PropertyBag to retrieve the value from. - /// The key of the value to retrieve. - /// The deserialized value. - /// Optional JSON serializer options. - /// True if the value exists, false otherwise. - public static bool TryGetValue(this PropertyBag propertyBag, string key, out T value, JsonSerializerOptions? options = null) - { - if (!propertyBag.TryGetValue(key, out var v)) - { - value = default!; - return false; - } - - var json = (string)v; - value = JsonSerializer.Deserialize(json, options); - return true; - } - - /// - /// Sets a value in the PropertyBag based on the provided key. - /// The value is serialized using JSON. - /// - /// The PropertyBag to set the value in. - /// The key to associate with the value. - /// The value to store in the PropertyBag. - /// /// Optional JSON serializer options. - public static void SetValue(this PropertyBag propertyBag, string key, object value, JsonSerializerOptions? options = null) - { - var json = JsonSerializer.Serialize(value); - propertyBag[key] = json; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.Common/Models/PropertyBag.cs b/src/modules/Elsa.Common/Models/PropertyBag.cs deleted file mode 100644 index 0f6209e811..0000000000 --- a/src/modules/Elsa.Common/Models/PropertyBag.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Elsa.Common.Models; - -/// A dictionary of values that is skipped by polymorphic serialization. -public class PropertyBag : Dictionary -{ - /// - [JsonConstructor] - public PropertyBag() : base(StringComparer.OrdinalIgnoreCase) - { - } - - /// - public PropertyBag(IDictionary dictionary) : this() - { - foreach (var kvp in dictionary) - Add(kvp.Key, kvp.Value); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs index 7f25567ddd..02cdccc5c8 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/Configurations.cs @@ -17,7 +17,6 @@ public void Configure(EntityTypeBuilder builder) builder.Ignore(x => x.Outputs); builder.Ignore(x => x.Outcomes); builder.Ignore(x => x.CustomProperties); - builder.Ignore(x => x.PropertyBag); builder.Ignore(x => x.Options); builder.Property("Data"); builder.Property("UsableAsActivity"); diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs index 7421e59382..2c68860757 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionStore.cs @@ -152,7 +152,7 @@ public async Task GetIsNameUnique(string name, string? definitionId = defa private ValueTask OnSaveAsync(ManagementElsaDbContext managementElsaDbContext, WorkflowDefinition entity, CancellationToken cancellationToken) { - var data = new WorkflowDefinitionState(entity.Options, entity.Variables, entity.Inputs, entity.Outputs, entity.Outcomes, entity.CustomProperties, entity.PropertyBag); + var data = new WorkflowDefinitionState(entity.Options, entity.Variables, entity.Inputs, entity.Outputs, entity.Outcomes, entity.CustomProperties); var json = _payloadSerializer.Serialize(data); managementElsaDbContext.Entry(entity).Property("Data").CurrentValue = json; @@ -165,7 +165,7 @@ private ValueTask OnLoadAsync(ManagementElsaDbContext managementElsaDbContext, W if (entity == null) return ValueTask.CompletedTask; - var data = new WorkflowDefinitionState(entity.Options, entity.Variables, entity.Inputs, entity.Outputs, entity.Outcomes, entity.CustomProperties, entity.PropertyBag); + var data = new WorkflowDefinitionState(entity.Options, entity.Variables, entity.Inputs, entity.Outputs, entity.Outcomes, entity.CustomProperties); var json = (string?)managementElsaDbContext.Entry(entity).Property("Data").CurrentValue; if (!string.IsNullOrWhiteSpace(json)) @@ -177,7 +177,6 @@ private ValueTask OnLoadAsync(ManagementElsaDbContext managementElsaDbContext, W entity.Outputs = data.Outputs; entity.Outcomes = data.Outcomes; entity.CustomProperties = data.CustomProperties; - entity.PropertyBag = data.PropertyBag; return ValueTask.CompletedTask; } @@ -226,8 +225,7 @@ public WorkflowDefinitionState( ICollection inputs, ICollection outputs, ICollection outcomes, - IDictionary customProperties, - PropertyBag propertyBag + IDictionary customProperties ) { Options = options; @@ -236,7 +234,6 @@ PropertyBag propertyBag Outputs = outputs; Outcomes = outcomes; CustomProperties = customProperties; - PropertyBag = propertyBag; } public WorkflowOptions Options { get; set; } = new(); @@ -244,10 +241,6 @@ PropertyBag propertyBag public ICollection Inputs { get; set; } = new List(); public ICollection Outputs { get; set; } = new List(); public ICollection Outcomes { get; set; } = new List(); - - [Obsolete("Use PropertyBag instead")] public IDictionary CustomProperties { get; set; } = new Dictionary(); - - public PropertyBag PropertyBag { get; set; } = new(); } } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Activities/SetWorkflowContextParameter.cs b/src/modules/Elsa.WorkflowContexts/Activities/SetWorkflowContextParameter.cs index e6406b55ef..00fbf01c93 100644 --- a/src/modules/Elsa.WorkflowContexts/Activities/SetWorkflowContextParameter.cs +++ b/src/modules/Elsa.WorkflowContexts/Activities/SetWorkflowContextParameter.cs @@ -6,13 +6,14 @@ using Elsa.Workflows.Attributes; using Elsa.Workflows.Models; using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; namespace Elsa.WorkflowContexts.Activities; /// /// Sets a workflow context parameter for a given workflow context provider. /// -[Activity("Elsa", "Primitives", "Sets a workflow context parameter for a given workflow context provider.")] +[Activity("Elsa", "Workflow Context", "Sets a workflow context parameter for a given workflow context provider.")] [PublicAPI] public class SetWorkflowContextParameter : CodeActivity { @@ -100,13 +101,17 @@ public static SetWorkflowContextParameter For(Func ParameterValue { get; set; } = default!; /// - protected override void Execute(ActivityExecutionContext context) + protected override async ValueTask ExecuteAsync(ActivityExecutionContext context) { var providerType = ProviderType.Get(context); var parameterName = ParameterName.GetOrDefault(context); var scopedParameterName = providerType.GetScopedParameterName(parameterName); var parameterValue = ParameterValue.Get(context); + // Update the parameter. context.WorkflowExecutionContext.SetProperty(scopedParameterName, parameterValue); + + // Load the context. + await context.WorkflowExecutionContext.LoadWorkflowContextAsync(providerType); } } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/ActivityExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/ActivityExtensions.cs index d5c22cc0ea..8e9038f94c 100644 --- a/src/modules/Elsa.WorkflowContexts/Extensions/ActivityExtensions.cs +++ b/src/modules/Elsa.WorkflowContexts/Extensions/ActivityExtensions.cs @@ -1,3 +1,5 @@ +using System.Text.Json; +using System.Text.Json.Nodes; using Elsa.WorkflowContexts.Models; using Elsa.Workflows.Contracts; @@ -10,6 +12,12 @@ namespace Elsa.Extensions; public static class ActivityExtensions { private const string ActivityWorkflowContextSettingsKey = "ActivityWorkflowContextSettingsKey"; + + private static readonly JsonSerializerOptions JsonSerializerOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true + }; /// /// Gets the workflow context settings for the specified activity. @@ -18,20 +26,20 @@ public static class ActivityExtensions /// The workflow context settings. public static IDictionary GetWorkflowContextSettings(this IActivity activity) { - var contextSetttings = activity.CustomProperties.GetOrAdd(ActivityWorkflowContextSettingsKey, () => new Dictionary())!; - - var result = new Dictionary(); - - foreach(var (key,value) in contextSetttings) - { - var targetType = Type.GetType(key); - - if(targetType != null) - { - result.Add(targetType, value); - } - } - + var contextSettings = activity.CustomProperties.GetOrAdd(ActivityWorkflowContextSettingsKey, () => new JsonObject()); + var result = new Dictionary(); + + foreach(var (key, jsonNode) in contextSettings) + { + var targetType = Type.GetType(key); + + if(targetType != null) + { + var value = jsonNode.Deserialize(JsonSerializerOptions)!; + result.Add(targetType, value); + } + } + return result; } @@ -72,7 +80,7 @@ public static TActivity SaveContext(this TActivity activity, Type pro /// The workflow context settings. public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings(this TActivity activity, Type providerType) where TActivity: IActivity { - var dictionary = activity.GetWorkflowContextSettings()!; + var dictionary = activity.GetWorkflowContextSettings(); return dictionary.GetActivityWorkflowContextSettings(providerType); } @@ -84,7 +92,7 @@ public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings /// The workflow context settings. public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings(this IDictionary dictionary, Type providerType) { - var settings = dictionary.ContainsKey(providerType) ? dictionary[providerType] : default; + var settings = dictionary.TryGetValue(providerType, out ActivityWorkflowContextSettings? value) ? value : default; if(settings == null) { diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/TransientPropertiesExecutionContextExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/TransientPropertiesExecutionContextExtensions.cs new file mode 100644 index 0000000000..adf0ce713e --- /dev/null +++ b/src/modules/Elsa.WorkflowContexts/Extensions/TransientPropertiesExecutionContextExtensions.cs @@ -0,0 +1,190 @@ +using Elsa.Expressions.Models; +using Elsa.WorkflowContexts.Contracts; +using Elsa.Workflows; +using JetBrains.Annotations; + +// ReSharper disable once CheckNamespace +namespace Elsa.Extensions; + +/// Adds extension methods to . +[PublicAPI] +public static class TransientPropertiesExecutionContextExtensions +{ + private static readonly object WorkflowContextsKey = new(); + + /// + /// Sets a workflow context provider parameter. + /// + /// The workflow execution context. + /// The type of the workflow context provider. + /// The value to set. + public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, Type providerType, object? value) + { + SetWorkflowContextParameter(context, providerType, null, value); + } + + /// + /// Sets a workflow context provider parameter. + /// + /// The workflow execution context. + /// The value to set. + /// The type of the workflow context provider. + public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, object? value) where T : IWorkflowContextProvider + { + SetWorkflowContextParameter(context, typeof(T), null, value); + } + + /// + /// Sets a workflow context provider parameter. + /// + /// The workflow execution context. + /// The type of the workflow context provider. + /// The name of the parameter. + /// The value to set. + public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, Type providerType, string? parameterName, object? value) + { + var scopedParameterName = providerType.GetScopedParameterName(parameterName); + context.SetProperty(scopedParameterName, value); + } + + /// + /// Sets a workflow context provider parameter. + /// + /// The workflow execution context. + /// The name of the parameter. + /// The value to set. + /// The type of the workflow context provider. + public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, string? parameterName, object? value) + { + SetWorkflowContextParameter(context, typeof(T), parameterName, value); + } + + /// + /// Gets a workflow context provider parameter. + /// + /// The workflow execution context. + /// The type of the workflow context provider. + /// The name of the parameter. + /// The type of the parameter. + /// The parameter value. + public static T? GetWorkflowContextParameter(this WorkflowExecutionContext context, Type providerType, string? parameterName = default) + { + var scopedParameterName = providerType.GetScopedParameterName(parameterName); + return context.GetProperty(scopedParameterName); + } + + /// + /// Gets a workflow context provider parameter. + /// + /// The workflow execution context. + /// The name of the parameter. + /// The type of the workflow context provider. + /// The type of the parameter. + /// The parameter value. + public static TParameter? GetWorkflowContextParameter(this WorkflowExecutionContext context, string? parameterName = default) where TProvider : IWorkflowContextProvider + { + return GetWorkflowContextParameter(context, typeof(TProvider), parameterName); + } + + /// + /// Sets the specified workflow context value. + /// + /// The workflow execution context. + /// The type of the workflow context provider. + /// The value to set. + public static void SetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, Type providerType, object value) + { + workflowExecutionContext.TransientProperties.SetWorkflowContext(providerType, value); + } + + /// + /// Sets the specified workflow context value. + /// + /// The expression execution context. + /// The type of the workflow context provider. + /// The value to set. + public static void SetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, Type providerType, object value) + { + expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.SetWorkflowContext(providerType, value); + } + + /// + /// Gets the workflow context value. + /// + /// The workflow execution context. + /// The type of the workflow context value. + /// The type of the workflow context provider. + /// The workflow context value. + public static T? GetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext) + { + return (T?)workflowExecutionContext.TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider)); + } + + /// + /// Gets the workflow context value. + /// + /// The expression execution context. + /// The type of the workflow context value. + /// The type of the workflow context provider. + /// The workflow context value. + public static T GetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext) + { + return (T)expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider))!; + } + + /// + /// Gets the workflow context value. + /// + /// The workflow execution context. + /// The type of the workflow context provider. + /// The workflow context value. + public static object GetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, Type providerType) + { + return workflowExecutionContext.TransientProperties.GetWorkflowContext(providerType); + } + + /// + /// Gets the workflow context value. + /// + /// The expression execution context. + /// The type of the workflow context provider. + /// The workflow context value. + public static object GetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, Type providerType) + { + return expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContext(providerType); + } + + private static void SetWorkflowContext(this IDictionary transientProperties, Type providerType, object value) + { + var contextDictionary = GetWorkflowContextDictionary(transientProperties); + contextDictionary[providerType] = value; + } + + private static object GetWorkflowContext(this IDictionary transientProperties, Type providerType) + { + var contextDictionary = transientProperties.GetWorkflowContextDictionary(); + return contextDictionary[providerType]; + } + + private static object? GetWorkflowContextByProviderType(this IDictionary transientProperties, Type providerType) + { + return transientProperties.FindWorkflowContext(x => x == providerType); + } + + private static object? FindWorkflowContext(this IDictionary transientProperties, Func filter) + { + var contextDictionary = transientProperties.GetWorkflowContextDictionary(); + + var query = + from entry in contextDictionary + where filter(entry.Key) + select entry.Value; + + return query.FirstOrDefault(); + } + + private static IDictionary GetWorkflowContextDictionary(this IDictionary transientProperties) + { + return transientProperties.GetOrAdd(WorkflowContextsKey, () => new Dictionary()); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowBuilderExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowBuilderExtensions.cs index b10faf2265..e001dc87e8 100644 --- a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowBuilderExtensions.cs +++ b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowBuilderExtensions.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Nodes; using Elsa.WorkflowContexts; using Elsa.WorkflowContexts.Contracts; using Elsa.Workflows.Contracts; @@ -6,9 +7,7 @@ // ReSharper disable once CheckNamespace namespace Elsa.Extensions; -/// /// Adds extension methods to . -/// [PublicAPI] public static class WorkflowBuilderExtensions { @@ -29,8 +28,8 @@ public static IWorkflowBuilder AddWorkflowContextProvider(this IWorkflowBuild /// The type of the provider to add. public static IWorkflowBuilder AddWorkflowContextProvider(this IWorkflowBuilder workflow, Type providerType) { - var providerTypes = workflow.CustomProperties.GetOrAdd(Constants.WorkflowContextProviderTypesKey, () => new List())!; - providerTypes.Add(providerType); + var providerTypes = workflow.CustomProperties.GetOrAdd(Constants.WorkflowContextProviderTypesKey, () => new JsonArray()); + providerTypes.Add(providerType.GetSimpleAssemblyQualifiedName()); return workflow; } } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/ModuleExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextModuleExtensions.cs similarity index 93% rename from src/modules/Elsa.WorkflowContexts/Extensions/ModuleExtensions.cs rename to src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextModuleExtensions.cs index b861c76a08..2ad3cf781d 100644 --- a/src/modules/Elsa.WorkflowContexts/Extensions/ModuleExtensions.cs +++ b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextModuleExtensions.cs @@ -9,7 +9,7 @@ namespace Elsa.Extensions; /// Extension methods for to add workflow context providers. /// [PublicAPI] -public static class ModuleExtensions +public static class WorkflowContextModuleExtensions { /// /// Adds support for workflow context providers. diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/DependencyInjectionExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextServiceCollectionExtensions.cs similarity index 92% rename from src/modules/Elsa.WorkflowContexts/Extensions/DependencyInjectionExtensions.cs rename to src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextServiceCollectionExtensions.cs index 968ba7c5c1..42a829690d 100644 --- a/src/modules/Elsa.WorkflowContexts/Extensions/DependencyInjectionExtensions.cs +++ b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextServiceCollectionExtensions.cs @@ -7,7 +7,7 @@ namespace Elsa.Extensions; /// /// Extension methods for to add workflow context providers. /// -public static class DependencyInjectionExtensions +public static class WorkflowContextServiceCollectionExtensions { /// /// Adds a workflow context provider. diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextWorkflowDefinitionExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextWorkflowDefinitionExtensions.cs deleted file mode 100644 index fc8279df02..0000000000 --- a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextWorkflowDefinitionExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Elsa.WorkflowContexts; -using Elsa.Workflows.Management.Entities; - -// ReSharper disable once CheckNamespace -namespace Elsa.Extensions; - -/// Adds extension methods to . -public static class WorkflowContextWorkflowDefinitionExtensions -{ - /// - /// Gets the workflow context provider types that are installed on the workflow definition. - /// - /// The workflow definition to get the provider types from. - /// The workflow context provider types. - public static IEnumerable GetWorkflowContextProviderTypes(this WorkflowDefinition workflowDefinition) - { - return workflowDefinition.PropertyBag.GetOrAdd(Constants.WorkflowContextProviderTypesKey, () => new List()); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextWorkflowExtensions.cs similarity index 55% rename from src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExtensions.cs rename to src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextWorkflowExtensions.cs index 1ebba29a04..b3281e64cd 100644 --- a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExtensions.cs +++ b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowContextWorkflowExtensions.cs @@ -7,29 +7,18 @@ namespace Elsa.Extensions; /// /// Adds extension methods to . /// -public static class WorkflowExtensions +public static class WorkflowContextWorkflowExtensions { /// /// Gets the workflow context provider types that are installed on the workflow. /// /// The workflow to get the provider types from. /// The workflow context provider types. - public static IEnumerable GetWorkflowContextProviderTypes(this Workflow workflow) - { - var contextProviderTypes = workflow.PropertyBag.GetOrAdd(Constants.WorkflowContextProviderTypesKey, () => new List()); - - var result = new List(); - - foreach (var type in contextProviderTypes) - { - var targetType = Type.GetType(type); - - if (targetType != null) - { - result.Add(targetType); - } - } - - return result; + public static IEnumerable GetWorkflowContextProviderTypes(this Workflow workflow) + { + var contextProviderTypes = workflow.CustomProperties.GetOrAdd(Constants.WorkflowContextProviderTypesKey, () => new List()); + var providerTypes = contextProviderTypes.Select(x => Type.GetType(x.ToString()!)).Where(x => x != null).Select(x => x!).ToList(); + + return providerTypes; } } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExecutionContextExtensions.cs b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExecutionContextExtensions.cs index d6184a4469..57a2bebe9b 100644 --- a/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExecutionContextExtensions.cs +++ b/src/modules/Elsa.WorkflowContexts/Extensions/WorkflowExecutionContextExtensions.cs @@ -1,159 +1,28 @@ -using Elsa.Expressions.Models; + + using Elsa.WorkflowContexts.Contracts; +using Microsoft.Extensions.DependencyInjection; +// ReSharper disable once CheckNamespace using Elsa.Workflows; -using JetBrains.Annotations; -// ReSharper disable once CheckNamespace namespace Elsa.Extensions; -/// -/// Adds extension methods to . -/// -[PublicAPI] public static class WorkflowExecutionContextExtensions { - private static readonly object WorkflowContextsKey = new(); - - /// - /// Sets a workflow context provider parameter. - /// - /// The workflow execution context. - /// The type of the workflow context provider. - /// The value to set. - public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, Type providerType, object? value) => SetWorkflowContextParameter(context, providerType, null, value); - - /// - /// Sets a workflow context provider parameter. - /// - /// The workflow execution context. - /// The value to set. - /// The type of the workflow context provider. - public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, object? value) where T : IWorkflowContextProvider => SetWorkflowContextParameter(context, typeof(T), null, value); - - /// - /// Sets a workflow context provider parameter. - /// - /// The workflow execution context. - /// The type of the workflow context provider. - /// The name of the parameter. - /// The value to set. - public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, Type providerType, string? parameterName, object? value) - { - var scopedParameterName = providerType.GetScopedParameterName(parameterName); - context.SetProperty(scopedParameterName, value); - } - - /// - /// Sets a workflow context provider parameter. - /// - /// The workflow execution context. - /// The name of the parameter. - /// The value to set. - /// The type of the workflow context provider. - public static void SetWorkflowContextParameter(this WorkflowExecutionContext context, string? parameterName, object? value) => SetWorkflowContextParameter(context, typeof(T), parameterName, value); - - /// - /// Gets a workflow context provider parameter. - /// - /// The workflow execution context. - /// The type of the workflow context provider. - /// The name of the parameter. - /// The type of the parameter. - /// The parameter value. - public static T? GetWorkflowContextParameter(this WorkflowExecutionContext context, Type providerType, string? parameterName = default) - { - var scopedParameterName = providerType.GetScopedParameterName(parameterName); - return context.GetProperty(scopedParameterName); - } - - /// - /// Gets a workflow context provider parameter. - /// - /// The workflow execution context. - /// The name of the parameter. - /// The type of the workflow context provider. - /// The type of the parameter. - /// The parameter value. - public static TParameter? GetWorkflowContextParameter(this WorkflowExecutionContext context, string? parameterName = default) where TProvider : IWorkflowContextProvider - => GetWorkflowContextParameter(context, typeof(TProvider), parameterName); - - /// - /// Sets the specified workflow context value. - /// - /// The workflow execution context. - /// The type of the workflow context provider. - /// The value to set. - public static void SetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, Type providerType, object value) => workflowExecutionContext.TransientProperties.SetWorkflowContext(providerType, value); - - /// - /// Sets the specified workflow context value. - /// - /// The expression execution context. - /// The type of the workflow context provider. - /// The value to set. - public static void SetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, Type providerType, object value) => expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.SetWorkflowContext(providerType, value); - - /// - /// Gets the workflow context value. - /// - /// The workflow execution context. - /// The type of the workflow context value. - /// The type of the workflow context provider. - /// The workflow context value. - public static T? GetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext) => (T?)workflowExecutionContext.TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider)); - - /// - /// Gets the workflow context value. - /// - /// The expression execution context. - /// The type of the workflow context value. - /// The type of the workflow context provider. - /// The workflow context value. - public static T GetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext) => (T)expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider))!; - - /// - /// Gets the workflow context value. - /// - /// The workflow execution context. - /// The type of the workflow context provider. - /// The workflow context value. - public static object GetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, Type providerType) => workflowExecutionContext.TransientProperties.GetWorkflowContext(providerType); - - /// - /// Gets the workflow context value. - /// - /// The expression execution context. - /// The type of the workflow context provider. - /// The workflow context value. - public static object? GetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, Type providerType) => expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContext(providerType); - - private static void SetWorkflowContext(this IDictionary transientProperties, Type providerType, object value) + public static async Task LoadWorkflowContextAsync(this WorkflowExecutionContext workflowExecutionContext, Type providerType) { - var contextDictionary = GetWorkflowContextDictionary(transientProperties); - contextDictionary[providerType] = value; - } + // Load the context. + var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(workflowExecutionContext.ServiceProvider, providerType); + var value = await provider.LoadAsync(workflowExecutionContext); - private static object GetWorkflowContext(this IDictionary transientProperties, Type providerType) - { - var contextDictionary = transientProperties.GetWorkflowContextDictionary(); - return contextDictionary[providerType]; + // Store the loaded value into the workflow execution context. + workflowExecutionContext.SetWorkflowContext(providerType, value!); } - - private static object? GetWorkflowContextByProviderType(this IDictionary transientProperties, Type providerType) => - transientProperties.FindWorkflowContext(x => x == providerType); - - private static object? FindWorkflowContext(this IDictionary transientProperties, Func filter) + + public static async Task SaveWorkflowContextAsync(this WorkflowExecutionContext workflowExecutionContext, Type providerType) { - var contextDictionary = transientProperties.GetWorkflowContextDictionary(); - - var query = - from entry in contextDictionary - where filter(entry.Key) - select entry.Value; - - return query.FirstOrDefault(); + var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(workflowExecutionContext.ServiceProvider, providerType); + var value = workflowExecutionContext.GetWorkflowContext(providerType); + await provider.SaveAsync(workflowExecutionContext, value); } - - private static IDictionary GetWorkflowContextDictionary(this IDictionary transientProperties) => - transientProperties.GetOrAdd(WorkflowContextsKey, () => new Dictionary()); } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextActivityExecutionMiddleware.cs b/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextActivityExecutionMiddleware.cs index 7b1cda1bc3..24e8a5e717 100644 --- a/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextActivityExecutionMiddleware.cs +++ b/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextActivityExecutionMiddleware.cs @@ -1,40 +1,26 @@ -using System.Text.Json; -using Elsa.Expressions.Contracts; using Elsa.Extensions; -using Elsa.WorkflowContexts.Contracts; using Elsa.Workflows; using Elsa.Workflows.Contracts; using Elsa.Workflows.Pipelines.ActivityExecution; -using Elsa.Workflows.Serialization.Converters; using JetBrains.Annotations; -using Microsoft.Extensions.DependencyInjection; namespace Elsa.WorkflowContexts.Middleware; /// Middleware that loads and save workflow context into the currently executing workflow using installed workflow context providers. [UsedImplicitly] -public class WorkflowContextActivityExecutionMiddleware(ActivityMiddlewareDelegate next, IServiceScopeFactory serviceScopeFactory, IWellKnownTypeRegistry wellKnownTypeRegistry) : IActivityExecutionMiddleware -{ - private readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }.WithConverters(new TypeJsonConverter(wellKnownTypeRegistry)); - +public class WorkflowContextActivityExecutionMiddleware(ActivityMiddlewareDelegate next) : IActivityExecutionMiddleware +{ /// public async ValueTask InvokeAsync(ActivityExecutionContext context) { // Check if the workflow contains any workflow context providers. - if (!context.WorkflowExecutionContext.Workflow.PropertyBag.TryGetValue>(Constants.WorkflowContextProviderTypesKey, out var providerTypes, _jsonSerializerOptions)) - { - await next(context); - return; - } - - if (providerTypes.Count == 0) + if (!context.WorkflowExecutionContext.Workflow.CustomProperties.TryGetValue>(Constants.WorkflowContextProviderTypesKey, out var providerTypeNodes)) { await next(context); return; } + + var providerTypes = providerTypeNodes.Select(x => Type.GetType(x.ToString()!)).Where(x => x != null).ToList(); // Check if this is a background execution. var isBackgroundExecution = context.GetIsBackgroundExecution(); @@ -42,36 +28,26 @@ public async ValueTask InvokeAsync(ActivityExecutionContext context) // Is the activity configured to load the context? foreach (var providerType in providerTypes) { - // Is the activity configured to load the context, or is this a background execution? + // Is the activity configured to load the context or is this a background execution? var load = isBackgroundExecution || context.Activity.GetActivityWorkflowContextSettings(providerType).Load; if (!load) continue; // Load the context. - using var scope = serviceScopeFactory.CreateScope(); - var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType); - var value = await provider.LoadAsync(context.WorkflowExecutionContext); - - // Store the loaded value into the workflow execution context. - context.WorkflowExecutionContext.SetWorkflowContext(providerType, value!); + await context.WorkflowExecutionContext.LoadWorkflowContextAsync(providerType); } // Invoke the next middleware. await next(context); - // Invoke each workflow context provider to persists the context. + // Invoke each workflow context provider to persist the context. foreach (var providerType in providerTypes) { - // Is the activity configured to save the context or is this a background execution? + // Is the activity configured to save the context, or is this a background execution? var save = isBackgroundExecution || context.Activity.GetActivityWorkflowContextSettings(providerType).Load; if (!save) continue; - // Get the loaded value from the workflow execution context. - using var scope = serviceScopeFactory.CreateScope(); - var value = context.WorkflowExecutionContext.GetWorkflowContext(providerType); - // Save the context. - var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType); - await provider.SaveAsync(context.WorkflowExecutionContext, value); + await context.WorkflowExecutionContext.SaveWorkflowContextAsync(providerType); } } } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextWorkflowExecutionMiddleware.cs b/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextWorkflowExecutionMiddleware.cs index 5bb6c8e492..8dd423aa2b 100644 --- a/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextWorkflowExecutionMiddleware.cs +++ b/src/modules/Elsa.WorkflowContexts/Middleware/WorkflowContextWorkflowExecutionMiddleware.cs @@ -1,62 +1,37 @@ -using System.Text.Json; -using Elsa.Expressions.Contracts; using Elsa.Extensions; -using Elsa.WorkflowContexts.Contracts; using Elsa.Workflows; using Elsa.Workflows.Pipelines.WorkflowExecution; -using Elsa.Workflows.Serialization.Converters; -using Microsoft.Extensions.DependencyInjection; namespace Elsa.WorkflowContexts.Middleware; -/// /// Middleware that loads and save workflow context into the currently executing workflow using installed workflow context providers. -/// -/// -public class WorkflowContextWorkflowExecutionMiddleware(WorkflowMiddlewareDelegate next, IServiceScopeFactory serviceScopeFactory, IWellKnownTypeRegistry wellKnownTypeRegistry) : WorkflowExecutionMiddleware(next) -{ - private readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions +public class WorkflowContextWorkflowExecutionMiddleware : WorkflowExecutionMiddleware +{ + /// + public WorkflowContextWorkflowExecutionMiddleware(WorkflowMiddlewareDelegate next) : base(next) { - PropertyNameCaseInsensitive = true - }.WithConverters(new TypeJsonConverter(wellKnownTypeRegistry)); - + } /// public override async ValueTask InvokeAsync(WorkflowExecutionContext context) { // Check if the workflow contains any workflow context providers. - if (!context.Workflow.PropertyBag.TryGetValue>(Constants.WorkflowContextProviderTypesKey, out var providerTypes, _jsonSerializerOptions)) + if (!context.Workflow.CustomProperties.TryGetValue>(Constants.WorkflowContextProviderTypesKey, out var providerTypeObjects)) { await Next(context); return; } - // Invoke each workflow context provider. - using (var scope = serviceScopeFactory.CreateScope()) - { - foreach (var providerType in providerTypes) - { - var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType); - var value = await provider.LoadAsync(context); + var providerTypes = providerTypeObjects.Select(x => Type.GetType(x.ToString()!)).Where(x => x != null).Select(x => x!).ToList(); - // Store the loaded value into the workflow execution context. - context.SetWorkflowContext(providerType, value!); - } - } + // Invoke each workflow context provider. + foreach (var providerType in providerTypes) + await context.LoadWorkflowContextAsync(providerType); // Invoke the next middleware. await Next(context); - // Invoke each workflow context provider to persists the context. - using (var scope = serviceScopeFactory.CreateScope()) - { - foreach (var providerType in providerTypes) - { - // Get the loaded value from the workflow execution context. - var value = context.GetWorkflowContext(providerType); - - var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType); - await provider.SaveAsync(context, value); - } - } + // Invoke each workflow context provider to persist the context. + foreach (var providerType in providerTypes) + await context.SaveWorkflowContextAsync(providerType); } } \ No newline at end of file diff --git a/src/modules/Elsa.WorkflowContexts/Scripting/JavaScript/ConfigureJavaScriptEngine.cs b/src/modules/Elsa.WorkflowContexts/Scripting/JavaScript/ConfigureJavaScriptEngine.cs index 250de1463a..4ad44a9ee3 100644 --- a/src/modules/Elsa.WorkflowContexts/Scripting/JavaScript/ConfigureJavaScriptEngine.cs +++ b/src/modules/Elsa.WorkflowContexts/Scripting/JavaScript/ConfigureJavaScriptEngine.cs @@ -14,20 +14,8 @@ namespace Elsa.WorkflowContexts.Scripting.JavaScript; /// /// Configures the JavaScript engine with functions that allow access to workflow contexts. /// -public class ConfigureJavaScriptEngine : INotificationHandler, IFunctionDefinitionProvider, ITypeDefinitionProvider +public class ConfigureJavaScriptEngine(ITypeAliasRegistry typeAliasRegistry, ITypeDescriber typeDescriber) : INotificationHandler, IFunctionDefinitionProvider, ITypeDefinitionProvider { - private readonly ITypeAliasRegistry _typeAliasRegistry; - private readonly ITypeDescriber _typeDescriber; - - /// - /// Initializes a new instance of the class. - /// - public ConfigureJavaScriptEngine(ITypeAliasRegistry typeAliasRegistry, ITypeDescriber typeDescriber) - { - _typeAliasRegistry = typeAliasRegistry; - _typeDescriber = typeDescriber; - } - /// public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken) { @@ -52,7 +40,7 @@ public ValueTask> GetTypeDefinitionsAsync(TypeDefini { var providerTypes = GetProviderTypes(context.Workflow); var contextTypes = providerTypes.Select(x => x.GetWorkflowContextType()); - var typeDefinitions = contextTypes.Select(x => _typeDescriber.DescribeType(x)); + var typeDefinitions = contextTypes.Select(x => typeDescriber.DescribeType(x)); return new(typeDefinitions); } @@ -72,7 +60,7 @@ private IEnumerable BuildFunctionDefinitions(IEnumerable(); - draft.PropertyBag = model.PropertyBag ?? new PropertyBag(); + draft.CustomProperties = model.CustomProperties ?? new Dictionary(); draft.Variables = variables; draft.Inputs = inputs; draft.Outputs = outputs; diff --git a/src/modules/Elsa.Workflows.Api/Services/StaticWorkflowDefinitionLinker.cs b/src/modules/Elsa.Workflows.Api/Services/StaticWorkflowDefinitionLinker.cs index d065b58184..da2a3351ef 100644 --- a/src/modules/Elsa.Workflows.Api/Services/StaticWorkflowDefinitionLinker.cs +++ b/src/modules/Elsa.Workflows.Api/Services/StaticWorkflowDefinitionLinker.cs @@ -32,7 +32,6 @@ public async Task MapAsync(WorkflowDefinition def Outputs = workflowDefinitionModel.Outputs, Outcomes = workflowDefinitionModel.Outcomes, CustomProperties = workflowDefinitionModel.CustomProperties, - PropertyBag = workflowDefinitionModel.PropertyBag, IsReadonly = workflowDefinitionModel.IsReadonly, IsSystem = workflowDefinitionModel.IsSystem, IsLatest = workflowDefinitionModel.IsLatest, @@ -100,7 +99,6 @@ public async Task> MapAsync(List outputs, ICollection outcomes, IDictionary customProperties, - PropertyBag propertyBag, bool isReadonly, bool isSystem) { @@ -40,7 +39,6 @@ public Workflow( Inputs = inputs; Outputs = outputs; Outcomes = outcomes; - PropertyBag = propertyBag; WorkflowMetadata = workflowMetadata; Options = options; Variables = variables; @@ -99,11 +97,6 @@ public Workflow() /// Gets or sets options for the workflow. /// public WorkflowOptions Options { get; set; } = new(); - - /// - /// A bag of properties that can be used by applications and modules to store information that can be shared with tooling. - /// - public PropertyBag PropertyBag { get; set; } = new(); /// /// Make workflow definition readonly. diff --git a/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs b/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs index 246ee7bad2..878de48b85 100644 --- a/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs +++ b/src/modules/Elsa.Workflows.Core/Builders/WorkflowBuilder.cs @@ -1,4 +1,3 @@ -using Elsa.Common.Models; using Elsa.Extensions; using Elsa.Workflows.Activities; using Elsa.Workflows.Contracts; @@ -53,9 +52,6 @@ public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphSer /// public IDictionary CustomProperties { get; set; } = new Dictionary(); - /// - public PropertyBag PropertyBag { get; set; } = new(); - /// public WorkflowOptions WorkflowOptions { get; } = new(); @@ -211,7 +207,7 @@ public async Task BuildWorkflowAsync(CancellationToken cancellationTok var publication = WorkflowPublication.LatestAndPublished; var name = string.IsNullOrEmpty(Name) ? definitionId : Name; var workflowMetadata = new WorkflowMetadata(name, Description); - var workflow = new Workflow(identity, publication, workflowMetadata, WorkflowOptions, root, Variables, Inputs, Outputs, Outcomes, CustomProperties, PropertyBag, IsReadonly, IsSystem); + var workflow = new Workflow(identity, publication, workflowMetadata, WorkflowOptions, root, Variables, Inputs, Outputs, Outcomes, CustomProperties, IsReadonly, IsSystem); // If a Result variable is defined, install it into the workflow, so we can capture the output into it. if (Result != null) diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilder.cs b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilder.cs index 57bf044a38..73dc2fd927 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilder.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowBuilder.cs @@ -1,4 +1,3 @@ -using Elsa.Common.Models; using Elsa.Workflows.Activities; using Elsa.Workflows.Memory; using Elsa.Workflows.Models; @@ -86,11 +85,6 @@ public interface IWorkflowBuilder [Obsolete("Use PropertyBag instead")] IDictionary CustomProperties { get; } - /// - /// A set of properties that can be used for storing application-specific information about the workflow being built. - /// - PropertyBag PropertyBag { get; set; } - /// /// A fluent method for setting the property. /// diff --git a/src/modules/Elsa.Workflows.Management/Entities/WorkflowDefinition.cs b/src/modules/Elsa.Workflows.Management/Entities/WorkflowDefinition.cs index 9405a4dc81..9bffa04991 100644 --- a/src/modules/Elsa.Workflows.Management/Entities/WorkflowDefinition.cs +++ b/src/modules/Elsa.Workflows.Management/Entities/WorkflowDefinition.cs @@ -58,9 +58,6 @@ public class WorkflowDefinition : VersionedEntity /// Stores custom information about the workflow. Can be used to store application-specific properties to associate with the workflow. public IDictionary CustomProperties { get; set; } = new Dictionary(); - /// Stores custom information about the workflow. Can be used to store application-specific properties to associate with the workflow. - public PropertyBag PropertyBag { get; set; } = new(); - /// /// The name of the workflow provider that created this workflow, if any. /// diff --git a/src/modules/Elsa.Workflows.Management/Mappers/WorkflowDefinitionMapper.cs b/src/modules/Elsa.Workflows.Management/Mappers/WorkflowDefinitionMapper.cs index 9f6ac512a0..a090db733e 100644 --- a/src/modules/Elsa.Workflows.Management/Mappers/WorkflowDefinitionMapper.cs +++ b/src/modules/Elsa.Workflows.Management/Mappers/WorkflowDefinitionMapper.cs @@ -46,7 +46,6 @@ public Workflow Map(WorkflowDefinition source) source.Outputs, source.Outcomes, source.CustomProperties, - source.PropertyBag, source.IsReadonly, source.IsSystem); } @@ -79,7 +78,6 @@ public Workflow Map(WorkflowDefinitionModel source) source.Outputs ?? new List(), source.Outcomes ?? new List(), source.CustomProperties ?? new Dictionary(), - source.PropertyBag ?? new(), source.IsReadonly, source.IsSystem); } @@ -118,7 +116,6 @@ public async Task MapAsync(WorkflowDefinition workflowD workflowDefinition.Outputs, workflowDefinition.Outcomes, workflowDefinition.CustomProperties, - workflowDefinition.PropertyBag, workflowDefinition.IsReadonly, workflowDefinition.IsSystem, workflowDefinition.IsLatest, @@ -150,7 +147,6 @@ public WorkflowDefinitionModel Map(Workflow workflow) workflow.Outputs, workflow.Outcomes, workflow.CustomProperties, - workflow.PropertyBag, workflow.IsReadonly, workflow.IsSystem, workflow.Publication.IsLatest, diff --git a/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs b/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs index 5f03324868..02e276980a 100644 --- a/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs +++ b/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs @@ -19,9 +19,7 @@ public record WorkflowDefinitionModel( ICollection? Inputs, ICollection? Outputs, ICollection? Outcomes, - [property: Obsolete("Use PropertyBag instead")] IDictionary? CustomProperties, - PropertyBag? PropertyBag, bool IsReadonly, bool IsSystem, bool IsLatest, @@ -46,7 +44,6 @@ public WorkflowDefinitionModel() : this( default!, default!, default, - default, default!, default!, default!, diff --git a/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionImporter.cs b/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionImporter.cs index 47df456372..f09a4ef7b4 100644 --- a/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionImporter.cs +++ b/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionImporter.cs @@ -63,8 +63,7 @@ public async Task ImportAsync(SaveWorkflowDefinitionReques draft.MaterializerName = JsonWorkflowMaterializer.MaterializerName; draft.Name = model.Name?.Trim(); draft.Description = model.Description?.Trim(); - draft.CustomProperties = model.CustomProperties ?? new Dictionary(); - draft.PropertyBag = model.PropertyBag ?? new PropertyBag(); + draft.CustomProperties = model.CustomProperties ?? new Dictionary(); draft.Variables = variables; draft.Inputs = model.Inputs ?? new List(); draft.Outputs = model.Outputs ?? new List();