Cleanup and refactoring WorkflowContext APIs
This commit is contained in:
parent
970d034037
commit
943df3d274
|
|
@ -43,7 +43,6 @@ services
|
|||
);
|
||||
|
||||
services.AddHealthChecks();
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddSingleton<IAuthorizationHandler, LocalHostRequirementHandler>();
|
||||
services.AddAuthorization(options => options.AddPolicy(IdentityPolicyNames.SecurityRoot, policy => policy.AddRequirements(new LocalHostRequirement())));
|
||||
services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
|
||||
|
|
|
|||
|
|
@ -50,10 +50,8 @@ services
|
|||
);
|
||||
|
||||
services.Configure<JintOptions>(options => options.AllowClrAccess = true);
|
||||
services.AddHandlersFrom<Program>();
|
||||
services.AddHealthChecks();
|
||||
services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
// Configure middleware pipeline.
|
||||
var app = builder.Build();
|
||||
|
|
|
|||
|
|
@ -4,11 +4,19 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
|
||||
namespace Elsa.Common.Features;
|
||||
|
||||
/// <summary>
|
||||
/// Configures the MemoryCache.
|
||||
/// </summary>
|
||||
public class MemoryCacheFeature : FeatureBase
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public MemoryCacheFeature(IModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Configure() => Services.AddMemoryCache();
|
||||
/// <inheritdoc />
|
||||
public override void Apply()
|
||||
{
|
||||
Services.AddMemoryCache();
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@ namespace Elsa.EntityFrameworkCore.Modules.Management;
|
|||
/// Configures the <see cref="WorkflowInstancesFeature"/> and <see cref="WorkflowDefinitionsFeature"/> features with an Entity Framework Core persistence provider.
|
||||
/// </summary>
|
||||
[DependsOn(typeof(WorkflowManagementFeature))]
|
||||
[DependsOn(typeof(WorkflowInstancesFeature))]
|
||||
[DependsOn(typeof(WorkflowDefinitionsFeature))]
|
||||
[PublicAPI]
|
||||
public class EFCoreWorkflowManagementPersistenceFeature : PersistenceFeatureBase<ManagementElsaDbContext>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,23 +1,50 @@
|
|||
using Elsa.WorkflowContexts.Contracts;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.WorkflowContexts.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// A base class for workflow context providers.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the workflow context value.</typeparam>
|
||||
[PublicAPI]
|
||||
public abstract class WorkflowContextProvider<T> : IWorkflowContextProvider
|
||||
{
|
||||
async ValueTask<object?> IWorkflowContextProvider.LoadAsync(WorkflowExecutionContext workflowExecutionContext) => await LoadAsync(workflowExecutionContext);
|
||||
|
||||
async ValueTask IWorkflowContextProvider.SaveAsync(WorkflowExecutionContext workflowExecutionContext, object? context) => await SaveAsync(workflowExecutionContext, (T?)context);
|
||||
|
||||
/// <summary>
|
||||
/// Load data that will be available to the workflow.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <returns>The workflow context value.</returns>
|
||||
protected virtual ValueTask<T?> LoadAsync(WorkflowExecutionContext workflowExecutionContext) => new(Load(workflowExecutionContext));
|
||||
|
||||
/// <summary>
|
||||
/// Load data that will be available to the workflow.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <returns>The workflow context value.</returns>
|
||||
protected virtual T? Load(WorkflowExecutionContext workflowExecutionContext) => default;
|
||||
|
||||
/// <summary>
|
||||
/// Save data.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="context">The workflow context value.</param>
|
||||
protected virtual ValueTask SaveAsync(WorkflowExecutionContext workflowExecutionContext, T? context)
|
||||
{
|
||||
Save(workflowExecutionContext, context);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save data.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="context">The workflow context value.</param>
|
||||
protected virtual void Save(WorkflowExecutionContext workflowExecutionContext, T? context)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
6
src/modules/Elsa.WorkflowContexts/Constants.cs
Normal file
6
src/modules/Elsa.WorkflowContexts/Constants.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace Elsa.WorkflowContexts;
|
||||
|
||||
internal class Constants
|
||||
{
|
||||
public const string WorkflowContextProviderTypesKey = "Elsa:WorkflowContexts";
|
||||
}
|
||||
|
|
@ -3,18 +3,17 @@
|
|||
namespace Elsa.WorkflowContexts.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Implement this interface to implement a workflow context provider that loads application-specific objects into the workflow.
|
||||
/// These providers can then be configured on a given workflow.
|
||||
/// Represents a workflow context provider that loads application-specific data and makes it available to the workflow.
|
||||
/// </summary>
|
||||
public interface IWorkflowContextProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Implement this method to load an object into memory that is accessible throughout the lifetime of the workflow's current execution.
|
||||
/// Load data that will be available to the workflow.
|
||||
/// </summary>
|
||||
ValueTask<object?> LoadAsync(WorkflowExecutionContext workflowExecutionContext);
|
||||
|
||||
/// <summary>
|
||||
/// Implement this method to save an object that was loaded previously
|
||||
/// Save data.
|
||||
/// </summary>
|
||||
ValueTask SaveAsync(WorkflowExecutionContext workflowExecutionContext, object? context);
|
||||
}
|
||||
|
|
@ -4,43 +4,78 @@ using Elsa.Workflows.Core.Contracts;
|
|||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IActivity"/>.
|
||||
/// </summary>
|
||||
public static class ActivityExtensions
|
||||
{
|
||||
private const string ActivityWorkflowContextSettingsKey = "ActivityWorkflowContextSettingsKey";
|
||||
|
||||
public static IDictionary<WorkflowContext, ActivityWorkflowContextSettings> GetWorkflowContextSettings(this IActivity activity)
|
||||
/// <summary>
|
||||
/// Gets the workflow context settings for the specified activity.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity to get the settings for.</param>
|
||||
/// <returns>The workflow context settings.</returns>
|
||||
public static IDictionary<Type, ActivityWorkflowContextSettings> GetWorkflowContextSettings(this IActivity activity)
|
||||
{
|
||||
return activity.CustomProperties.GetOrAdd(ActivityWorkflowContextSettingsKey, () => new Dictionary<WorkflowContext, ActivityWorkflowContextSettings>())!;
|
||||
return activity.CustomProperties.GetOrAdd(ActivityWorkflowContextSettingsKey, () => new Dictionary<Type, ActivityWorkflowContextSettings>())!;
|
||||
}
|
||||
|
||||
public static TActivity LoadContext<TActivity>(this TActivity activity, WorkflowContext workflowContext) where TActivity : IActivity
|
||||
/// <summary>
|
||||
/// Configures the activity to load the workflow context before executing.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity to configure.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <typeparam name="TActivity">The type of the activity.</typeparam>
|
||||
/// <returns>The activity.</returns>
|
||||
public static TActivity LoadContext<TActivity>(this TActivity activity, Type providerType) where TActivity : IActivity
|
||||
{
|
||||
var settings = activity.GetActivityWorkflowContextSettings(workflowContext);
|
||||
var settings = activity.GetActivityWorkflowContextSettings(providerType);
|
||||
settings.Load = true;
|
||||
return activity;
|
||||
}
|
||||
|
||||
public static TActivity SaveContext<TActivity>(this TActivity activity, WorkflowContext workflowContext) where TActivity : IActivity
|
||||
/// <summary>
|
||||
/// Configures the activity to save the workflow context after executing.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity to configure.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <typeparam name="TActivity">The type of the activity.</typeparam>
|
||||
/// <returns>The activity.</returns>
|
||||
public static TActivity SaveContext<TActivity>(this TActivity activity, Type providerType) where TActivity : IActivity
|
||||
{
|
||||
var settings = activity.GetActivityWorkflowContextSettings(workflowContext);
|
||||
var settings = activity.GetActivityWorkflowContextSettings(providerType);
|
||||
settings.Save = true;
|
||||
return activity;
|
||||
}
|
||||
|
||||
public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings<TActivity>(this TActivity activity, WorkflowContext workflowContext) where TActivity: IActivity
|
||||
/// <summary>
|
||||
/// Gets the workflow context settings for the specified activity.
|
||||
/// </summary>
|
||||
/// <param name="activity">The activity to get the settings for.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <typeparam name="TActivity">The type of the activity.</typeparam>
|
||||
/// <returns>The workflow context settings.</returns>
|
||||
public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings<TActivity>(this TActivity activity, Type providerType) where TActivity: IActivity
|
||||
{
|
||||
var dictionary = activity.GetWorkflowContextSettings()!;
|
||||
return dictionary.GetActivityWorkflowContextSettings(workflowContext);
|
||||
return dictionary.GetActivityWorkflowContextSettings(providerType);
|
||||
}
|
||||
|
||||
public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings(this IDictionary<WorkflowContext, ActivityWorkflowContextSettings> dictionary, WorkflowContext workflowContext)
|
||||
/// <summary>
|
||||
/// Gets the workflow context settings for the specified activity.
|
||||
/// </summary>
|
||||
/// <param name="dictionary">The dictionary to get the settings from.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <returns>The workflow context settings.</returns>
|
||||
public static ActivityWorkflowContextSettings GetActivityWorkflowContextSettings(this IDictionary<Type, ActivityWorkflowContextSettings> dictionary, Type providerType)
|
||||
{
|
||||
var settings = dictionary.ContainsKey(workflowContext) ? dictionary[workflowContext] : default;
|
||||
var settings = dictionary.ContainsKey(providerType) ? dictionary[providerType] : default;
|
||||
|
||||
if(settings == null)
|
||||
{
|
||||
settings = new ActivityWorkflowContextSettings();
|
||||
dictionary[workflowContext] = settings;
|
||||
dictionary[providerType] = settings;
|
||||
}
|
||||
|
||||
return settings;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
using Elsa.WorkflowContexts.Contracts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IServiceCollection"/> to add workflow context providers.
|
||||
/// </summary>
|
||||
public static class DependencyInjectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a workflow context provider.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection.</param>
|
||||
/// <typeparam name="T">The type of the workflow context provider.</typeparam>
|
||||
/// <returns>The service collection.</returns>
|
||||
public static IServiceCollection AddWorkflowContextProvider<T>(this IServiceCollection services) where T : class, IWorkflowContextProvider
|
||||
{
|
||||
return services.AddSingleton<IWorkflowContextProvider, T>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
using Elsa.WorkflowContexts;
|
||||
using Elsa.WorkflowContexts.Contracts;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
|
@ -7,7 +9,8 @@ namespace Elsa.Extensions;
|
|||
/// <summary>
|
||||
/// Adds extension methods to <see cref="IWorkflowBuilder"/>.
|
||||
/// </summary>
|
||||
public static class WorkflowExtensions
|
||||
[PublicAPI]
|
||||
public static class WorkflowBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs the specified workflow context provider type into the specified workflow.
|
||||
|
|
@ -26,7 +29,7 @@ public static class WorkflowExtensions
|
|||
/// <param name="providerType">The type of the provider to add.</param>
|
||||
public static IWorkflowBuilder AddWorkflowContextProvider(this IWorkflowBuilder workflow, Type providerType)
|
||||
{
|
||||
var providerTypes = workflow.CustomProperties.GetOrAdd("Elsa:WorkflowContexts", () => new List<Type>())!;
|
||||
var providerTypes = workflow.CustomProperties.GetOrAdd(Constants.WorkflowContextProviderTypesKey, () => new List<Type>())!;
|
||||
providerTypes.Add(providerType);
|
||||
return workflow;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ using Elsa.Workflows.Core.Pipelines.WorkflowExecution;
|
|||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IWorkflowExecutionPipelineBuilder"/>.
|
||||
/// </summary>
|
||||
public static class WorkflowExecutionBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -5,31 +5,79 @@ using Elsa.Workflows.Core.Models;
|
|||
// ReSharper disable once CheckNamespace
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Adds extension methods to <see cref="WorkflowExecutionContext"/>.
|
||||
/// </summary>
|
||||
public static class WorkflowExecutionContextExtensions
|
||||
{
|
||||
public static void SetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, WorkflowContext workflowContext, object value) => workflowExecutionContext.TransientProperties.SetWorkflowContext(workflowContext, value);
|
||||
public static void SetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, WorkflowContext workflowContext, object value) => expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.SetWorkflowContext(workflowContext, value);
|
||||
public static T? GetWorkflowContext<T, TProvider>(this WorkflowExecutionContext workflowExecutionContext) => (T?)workflowExecutionContext.TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider));
|
||||
public static T? GetWorkflowContext<T, TProvider>(this ExpressionExecutionContext expressionExecutionContext) => (T?)expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider));
|
||||
public static object? GetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, WorkflowContext workflowContext) => workflowExecutionContext.TransientProperties.GetWorkflowContext(workflowContext);
|
||||
public static object? GetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, WorkflowContext workflowContext) => expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContext(workflowContext);
|
||||
private static readonly object WorkflowContextsKey = new();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the specified workflow context value.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
public static void SetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, Type providerType, object value) => workflowExecutionContext.TransientProperties.SetWorkflowContext(providerType, value);
|
||||
|
||||
private static void SetWorkflowContext(this IDictionary<object, object> transientProperties, WorkflowContext workflowContext, object value)
|
||||
/// <summary>
|
||||
/// Sets the specified workflow context value.
|
||||
/// </summary>
|
||||
/// <param name="expressionExecutionContext">The expression execution context.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
public static void SetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, Type providerType, object value) => expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.SetWorkflowContext(providerType, value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the workflow context value.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <typeparam name="T">The type of the workflow context value.</typeparam>
|
||||
/// <typeparam name="TProvider">The type of the workflow context provider.</typeparam>
|
||||
/// <returns>The workflow context value.</returns>
|
||||
public static T? GetWorkflowContext<T, TProvider>(this WorkflowExecutionContext workflowExecutionContext) => (T?)workflowExecutionContext.TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the workflow context value.
|
||||
/// </summary>
|
||||
/// <param name="expressionExecutionContext">The expression execution context.</param>
|
||||
/// <typeparam name="T">The type of the workflow context value.</typeparam>
|
||||
/// <typeparam name="TProvider">The type of the workflow context provider.</typeparam>
|
||||
/// <returns>The workflow context value.</returns>
|
||||
public static T GetWorkflowContext<TProvider, T>(this ExpressionExecutionContext expressionExecutionContext) => (T)expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContextByProviderType(typeof(TProvider))!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the workflow context value.
|
||||
/// </summary>
|
||||
/// <param name="workflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <returns>The workflow context value.</returns>
|
||||
public static object GetWorkflowContext(this WorkflowExecutionContext workflowExecutionContext, Type providerType) => workflowExecutionContext.TransientProperties.GetWorkflowContext(providerType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the workflow context value.
|
||||
/// </summary>
|
||||
/// <param name="expressionExecutionContext">The expression execution context.</param>
|
||||
/// <param name="providerType">The type of the workflow context provider.</param>
|
||||
/// <returns>The workflow context value.</returns>
|
||||
public static object? GetWorkflowContext(this ExpressionExecutionContext expressionExecutionContext, Type providerType) => expressionExecutionContext.GetWorkflowExecutionContext().TransientProperties.GetWorkflowContext(providerType);
|
||||
|
||||
private static void SetWorkflowContext(this IDictionary<object, object> transientProperties, Type providerType, object value)
|
||||
{
|
||||
var contextDictionary = transientProperties!.GetOrAdd("WorkflowContexts", () => new Dictionary<WorkflowContext, object>())!;
|
||||
contextDictionary[workflowContext] = value;
|
||||
var contextDictionary = GetWorkflowContextDictionary(transientProperties);
|
||||
contextDictionary[providerType] = value;
|
||||
}
|
||||
|
||||
private static object? GetWorkflowContext(this IDictionary<object, object> transientProperties, WorkflowContext workflowContext)
|
||||
private static object GetWorkflowContext(this IDictionary<object, object> transientProperties, Type providerType)
|
||||
{
|
||||
var contextDictionary = transientProperties.GetWorkflowContextDictionary();
|
||||
return contextDictionary[workflowContext];
|
||||
return contextDictionary[providerType];
|
||||
}
|
||||
|
||||
private static object? GetWorkflowContextByProviderType(this IDictionary<object, object> transientProperties, Type providerType) =>
|
||||
transientProperties.FindWorkflowContext(x => x.ProviderType == providerType);
|
||||
transientProperties.FindWorkflowContext(x => x == providerType);
|
||||
|
||||
private static object? FindWorkflowContext(this IDictionary<object, object> transientProperties, Func<WorkflowContext, bool> filter)
|
||||
private static object? FindWorkflowContext(this IDictionary<object, object> transientProperties, Func<Type, bool> filter)
|
||||
{
|
||||
var contextDictionary = transientProperties.GetWorkflowContextDictionary();
|
||||
|
||||
|
|
@ -41,6 +89,6 @@ public static class WorkflowExecutionContextExtensions
|
|||
return query.FirstOrDefault();
|
||||
}
|
||||
|
||||
private static IDictionary<WorkflowContext, object> GetWorkflowContextDictionary(this IDictionary<object, object> transientProperties) =>
|
||||
transientProperties!.GetOrAdd("WorkflowContexts", () => new Dictionary<WorkflowContext, object>())!;
|
||||
private static IDictionary<Type, object> GetWorkflowContextDictionary(this IDictionary<object, object> transientProperties) =>
|
||||
transientProperties.GetOrAdd(WorkflowContextsKey, () => new Dictionary<Type, object>());
|
||||
}
|
||||
|
|
@ -28,44 +28,48 @@ public class WorkflowContextActivityExecutionMiddleware : IActivityExecutionMidd
|
|||
/// <inheritdoc />
|
||||
public async ValueTask InvokeAsync(ActivityExecutionContext context)
|
||||
{
|
||||
// Check if the workflow contains any workflow contexts.
|
||||
if (!context.WorkflowExecutionContext.Workflow.CustomProperties!.TryGetValue<ICollection<WorkflowContext>>("Elsa:WorkflowContexts", out var workflowContexts))
|
||||
// Check if the workflow contains any workflow context providers.
|
||||
if (!context.WorkflowExecutionContext.Workflow.CustomProperties.TryGetValue<ICollection<Type>>(Constants.WorkflowContextProviderTypesKey, out var providerTypes))
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// For each workflow context, invoke its provider.
|
||||
// Invoke each workflow context provider.
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
foreach (var workflowContext in workflowContexts!)
|
||||
foreach (var providerType in providerTypes)
|
||||
{
|
||||
var load = context.Activity.GetActivityWorkflowContextSettings(workflowContext).Load;
|
||||
// Is the activity configured to load the context?
|
||||
var load = context.Activity.GetActivityWorkflowContextSettings(providerType).Load;
|
||||
if (!load) continue;
|
||||
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, workflowContext.ProviderType);
|
||||
// Load the context.
|
||||
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(workflowContext, value!);
|
||||
context.WorkflowExecutionContext.SetWorkflowContext(providerType, value!);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the next middleware.
|
||||
await _next(context);
|
||||
|
||||
// For each workflow context, invoke its provider to update the context.
|
||||
// Invoke each workflow context provider to persists the context.
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
foreach (var workflowContext in workflowContexts!)
|
||||
foreach (var providerType in providerTypes)
|
||||
{
|
||||
var save = context.Activity.GetActivityWorkflowContextSettings(workflowContext).Load;
|
||||
// Is the activity configured to save the context?
|
||||
var save = context.Activity.GetActivityWorkflowContextSettings(providerType).Load;
|
||||
if (!save) continue;
|
||||
|
||||
// Get the loaded value from the workflow execution context.
|
||||
var value = context.WorkflowExecutionContext.GetWorkflowContext(workflowContext);
|
||||
var value = context.WorkflowExecutionContext.GetWorkflowContext(providerType);
|
||||
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, workflowContext.ProviderType);
|
||||
// Save the context.
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType);
|
||||
await provider.SaveAsync(context.WorkflowExecutionContext, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,38 +23,38 @@ public class WorkflowContextWorkflowExecutionMiddleware : WorkflowExecutionMiddl
|
|||
/// <inheritdoc />
|
||||
public override async ValueTask InvokeAsync(WorkflowExecutionContext context)
|
||||
{
|
||||
// Check if the workflow contains any workflow contexts.
|
||||
if (!context.Workflow.CustomProperties!.TryGetValue<ICollection<WorkflowContext>>("Elsa:WorkflowContexts", out var workflowContexts))
|
||||
// Check if the workflow contains any workflow context providers.
|
||||
if (!context.Workflow.CustomProperties!.TryGetValue<ICollection<Type>>(Constants.WorkflowContextProviderTypesKey, out var providerTypes))
|
||||
{
|
||||
await Next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
// For each workflow context, invoke its provider.
|
||||
// Invoke each workflow context provider.
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
foreach (var workflowContext in workflowContexts!)
|
||||
foreach (var providerType in providerTypes)
|
||||
{
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, workflowContext.ProviderType);
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType);
|
||||
var value = await provider.LoadAsync(context);
|
||||
|
||||
// Store the loaded value into the workflow execution context.
|
||||
context.SetWorkflowContext(workflowContext, value!);
|
||||
context.SetWorkflowContext(providerType, value!);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the next middleware.
|
||||
await Next(context);
|
||||
|
||||
// For each workflow context, invoke its provider to update the context.
|
||||
// Invoke each workflow context provider to persists the context.
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
foreach (var workflowContext in workflowContexts!)
|
||||
foreach (var providerType in providerTypes)
|
||||
{
|
||||
// Get the loaded value from the workflow execution context.
|
||||
var value = context.GetWorkflowContext(workflowContext);
|
||||
var value = context.GetWorkflowContext(providerType);
|
||||
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, workflowContext.ProviderType);
|
||||
var provider = (IWorkflowContextProvider)ActivatorUtilities.GetServiceOrCreateInstance(scope.ServiceProvider, providerType);
|
||||
await provider.SaveAsync(context, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,17 @@
|
|||
namespace Elsa.WorkflowContexts.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Provides activity-specific settings for workflow context providers.
|
||||
/// </summary>
|
||||
public class ActivityWorkflowContextSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether to load the context before executing the activity.
|
||||
/// </summary>
|
||||
public bool Load { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to save the context after executing the activity.
|
||||
/// </summary>
|
||||
public bool Save { get; set; }
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.WorkflowContexts.Contracts;
|
||||
|
||||
namespace Elsa.WorkflowContexts.Models;
|
||||
|
||||
public class WorkflowContext
|
||||
{
|
||||
public WorkflowContext(Type providerType)
|
||||
{
|
||||
ProviderType = providerType;
|
||||
}
|
||||
|
||||
public Type ProviderType { get; }
|
||||
}
|
||||
|
||||
public class WorkflowContext<T, TProvider> : WorkflowContext where TProvider:IWorkflowContextProvider
|
||||
{
|
||||
public WorkflowContext() : base(typeof(TProvider))
|
||||
{
|
||||
}
|
||||
|
||||
public T? Get(ExpressionExecutionContext context)
|
||||
{
|
||||
var workflowExecutionContext = context.GetWorkflowExecutionContext();
|
||||
var transientProperties = workflowExecutionContext.TransientProperties;
|
||||
var workflowContexts = (IDictionary<WorkflowContext, object?>)transientProperties["WorkflowContexts"]!;
|
||||
return workflowContexts.TryGetValue(this, out var workflowContext) ? (T?)workflowContext : default;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,10 @@ namespace Elsa.Extensions;
|
|||
|
||||
public static class DictionaryExtensions
|
||||
{
|
||||
public static bool TryGetValue<T>(this IDictionary<string, object> dictionary, string key, out T? value) => dictionary.TryGetValue<string, T>(key, out value);
|
||||
public static bool TryGetValue<T>(this IDictionary<object, object> dictionary, string key, out T? value) => dictionary.TryGetValue<object, T>(key, out value);
|
||||
public static bool TryGetValue<T>(this IDictionary<string, object> dictionary, string key, out T value) => dictionary.TryGetValue<string, T>(key, out value);
|
||||
public static bool TryGetValue<T>(this IDictionary<object, object> dictionary, string key, out T value) => dictionary.TryGetValue<object, T>(key, out value);
|
||||
|
||||
public static bool TryGetValue<TKey, T>(this IDictionary<TKey, object> dictionary, TKey key, out T? value)
|
||||
public static bool TryGetValue<TKey, T>(this IDictionary<TKey, object> dictionary, TKey key, out T value)
|
||||
{
|
||||
if (!dictionary.TryGetValue(key, out var item))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
_nodes = nodes.ToList();
|
||||
_activityExecutionContexts = activityExecutionContexts?.ToList() ?? new List<ActivityExecutionContext>();
|
||||
Scheduler = scheduler;
|
||||
Input = input ?? new Dictionary<string, object>();
|
||||
Input = input != null ? new Dictionary<string, object>(input, StringComparer.OrdinalIgnoreCase) : new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
ExecuteDelegate = executeDelegate;
|
||||
TriggerActivityId = triggerActivityId;
|
||||
CancellationToken = cancellationToken;
|
||||
|
|
@ -114,7 +114,7 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
/// A map between activity IDs and <see cref="ActivityNode"/>s in the workflow graph.
|
||||
/// </summary>
|
||||
public IDictionary<string, ActivityNode> NodeIdLookup { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A map between hashed activity node IDs and <see cref="ActivityNode"/>s in the workflow graph.
|
||||
/// </summary>
|
||||
|
|
@ -276,7 +276,7 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
/// Returns the <see cref="ActivityNode"/> with the specified activity ID from the workflow graph.
|
||||
/// </summary>
|
||||
public ActivityNode FindNodeById(string nodeId) => NodeIdLookup[nodeId];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="ActivityNode"/> with the specified hash of the activity node ID from the workflow graph.
|
||||
/// </summary>
|
||||
|
|
@ -298,7 +298,7 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
/// Returns the <see cref="IActivity"/> with the specified ID from the workflow graph.
|
||||
/// </summary>
|
||||
public IActivity FindActivityByActivityId(string activityId) => FindNodeById(NodeIdLookup.Single(n => n.Key.Contains(activityId)).Value.NodeId).Activity;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="IActivity"/> with the specified hash of the activity node ID from the workflow graph.
|
||||
/// </summary>
|
||||
|
|
@ -393,7 +393,7 @@ public class WorkflowExecutionContext : IExecutionContext
|
|||
{
|
||||
var activityExecutionContext = ActivityExecutionContexts.FirstOrDefault(x => x.Activity == activity);
|
||||
|
||||
if (activityExecutionContext != null)
|
||||
if (activityExecutionContext != null)
|
||||
await activityExecutionContext.CancelActivityAsync();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using Elsa.EntityFrameworkCore.Modules.Labels;
|
|||
using Elsa.EntityFrameworkCore.Modules.Management;
|
||||
using Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.JavaScript.Options;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Proto.Persistence.Sqlite;
|
||||
|
||||
|
|
@ -57,11 +56,8 @@ services
|
|||
.UseHttp()
|
||||
);
|
||||
|
||||
services.Configure<JintOptions>(options => options.AllowClrAccess = true);
|
||||
services.AddHandlersFrom<Program>();
|
||||
services.AddHealthChecks();
|
||||
services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
// Configure middleware pipeline.
|
||||
var app = builder.Build();
|
||||
|
|
|
|||
Loading…
Reference in a new issue