From 6ff6cc6826acdac58e68aaae81b2c87e27b278bf Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Sun, 10 Dec 2023 21:43:24 +0100 Subject: [PATCH] Refactor expression descriptors and remove unnecessary async calls This commit refactors how expression descriptors are created and retrieved across Elsa project. The asynchronous methods have been simplified to synchronous ones removing unnecessary `ValueTask` returns. Additionally, `IExpressionDescriptorRegistryPopulator` has been removed resulting in less complexity and better performance. --- README.md | 2 +- .../CSharpExpressionDescriptorProvider.cs | 20 +++---- .../IExpressionDescriptorProvider.cs | 2 +- .../IExpressionDescriptorRegistryPopulator.cs | 26 ++++----- .../JavaScriptExpressionSyntaxProvider.cs | 21 +++---- .../LiquidExpressionSyntaxProvider.cs | 27 +++------ .../PythonExpressionSyntaxProvider.cs | 22 +++---- .../Features/WorkflowManagementFeature.cs | 1 - .../DefaultExpressionDescriptorProvider.cs | 14 ++--- .../Services/ExpressionDescriptorRegistry.cs | 10 ++++ .../ExpressionDescriptorRegistryPopulator.cs | 58 +++++++++---------- .../Services/DefaultRegistriesPopulator.cs | 10 +--- 12 files changed, 94 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index b7d8d2365..8119c830b 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Open Program.cs and replace its contents with the following code: ```csharp using Elsa.Extensions; using Elsa.Workflows.Core.Activities; -using Elsa.Workflows.Core.Services; +using Elsa.Workflows.Core.Contracts; using Microsoft.Extensions.DependencyInjection; // Set up the service container. diff --git a/src/modules/Elsa.CSharp/Providers/CSharpExpressionDescriptorProvider.cs b/src/modules/Elsa.CSharp/Providers/CSharpExpressionDescriptorProvider.cs index 0d8f95c2f..051f2f127 100644 --- a/src/modules/Elsa.CSharp/Providers/CSharpExpressionDescriptorProvider.cs +++ b/src/modules/Elsa.CSharp/Providers/CSharpExpressionDescriptorProvider.cs @@ -10,18 +10,14 @@ internal class CSharpExpressionDescriptorProvider : IExpressionDescriptorProvide { private const string TypeName = "CSharp"; - public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) + public IEnumerable GetDescriptors() { - var descriptor = CreateCSharpDescriptor(); - - return ValueTask.FromResult>(new[] { descriptor }); + yield return new() + { + Type = TypeName, + DisplayName = "C#", + Properties = new { MonacoLanguage = "csharp" }.ToDictionary(), + HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance + }; } - - private static ExpressionDescriptor CreateCSharpDescriptor() => new() - { - Type = TypeName, - DisplayName = "C#", - Properties = new { MonacoLanguage = "csharp" }.ToDictionary(), - HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance - }; } \ No newline at end of file diff --git a/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorProvider.cs b/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorProvider.cs index 293a3a5d9..c5cdf6447 100644 --- a/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorProvider.cs +++ b/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorProvider.cs @@ -10,5 +10,5 @@ public interface IExpressionDescriptorProvider /// /// Gets the descriptors for the expression syntaxes supported by this provider. /// - ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default); + IEnumerable GetDescriptors(); } \ No newline at end of file diff --git a/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorRegistryPopulator.cs b/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorRegistryPopulator.cs index 450acbd72..407de0189 100644 --- a/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorRegistryPopulator.cs +++ b/src/modules/Elsa.Expressions/Contracts/IExpressionDescriptorRegistryPopulator.cs @@ -1,13 +1,13 @@ -namespace Elsa.Expressions.Contracts; - -/// -/// Populates the expression descriptor registry. -/// -public interface IExpressionDescriptorRegistryPopulator -{ - /// - /// Populates the expression descriptor registry. - /// - /// The cancellation token. - ValueTask PopulateRegistryAsync(CancellationToken cancellationToken = default); -} \ No newline at end of file +// namespace Elsa.Expressions.Contracts; +// +// /// +// /// Populates the expression descriptor registry. +// /// +// public interface IExpressionDescriptorRegistryPopulator +// { +// /// +// /// Populates the expression descriptor registry. +// /// +// /// The cancellation token. +// ValueTask PopulateRegistryAsync(CancellationToken cancellationToken = default); +// } \ No newline at end of file diff --git a/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs b/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs index 2a83a888b..bddfdd997 100644 --- a/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs +++ b/src/modules/Elsa.JavaScript/Providers/JavaScriptExpressionSyntaxProvider.cs @@ -2,7 +2,6 @@ using Elsa.Expressions.Contracts; using Elsa.Expressions.Models; using Elsa.Extensions; using Elsa.JavaScript.Expressions; -using Elsa.Workflows.Core.Contracts; using Microsoft.Extensions.DependencyInjection; namespace Elsa.JavaScript.Providers; @@ -11,18 +10,14 @@ internal class JavaScriptExpressionDescriptorProvider : IExpressionDescriptorPro { private const string TypeName = "JavaScript"; - public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) + public IEnumerable GetDescriptors() { - var javaScript = CreateJavaScriptDescriptor(); - - return ValueTask.FromResult>(new[] { javaScript }); + yield return new() + { + Type = TypeName, + DisplayName = "JavaScript", + Properties = new { MonacoLanguage = "javascript" }.ToDictionary(), + HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance + }; } - - private static ExpressionDescriptor CreateJavaScriptDescriptor() => new() - { - Type = TypeName, - DisplayName = "JavaScript", - Properties = new { MonacoLanguage = "javascript" }.ToDictionary(), - HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance - }; } \ No newline at end of file diff --git a/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs b/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs index 0a0770c7f..3ccb6766c 100644 --- a/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs +++ b/src/modules/Elsa.Liquid/Providers/LiquidExpressionSyntaxProvider.cs @@ -2,7 +2,6 @@ using Elsa.Expressions.Contracts; using Elsa.Expressions.Models; using Elsa.Extensions; using Elsa.Liquid.Expressions; -using Elsa.Workflows.Core.Contracts; using Microsoft.Extensions.DependencyInjection; namespace Elsa.Liquid.Providers; @@ -16,26 +15,16 @@ public class LiquidExpressionDescriptorProvider : IExpressionDescriptorProvider /// Gets the name of the expression type. /// public const string TypeName = "Liquid"; - private readonly IIdentityGenerator _identityGenerator; - - /// - /// Initializes a new instance of the class. - /// - public LiquidExpressionDescriptorProvider(IIdentityGenerator identityGenerator) => _identityGenerator = identityGenerator; /// - public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) + public IEnumerable GetDescriptors() { - var liquidDescriptor = CreateLiquidDescriptor(); - - return ValueTask.FromResult>(new[] { liquidDescriptor }); + yield return new() + { + Type = TypeName, + DisplayName = "Liquid", + Properties = new { MonacoLanguage = "liquid" }.ToDictionary(), + HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance + }; } - - private ExpressionDescriptor CreateLiquidDescriptor() => new() - { - Type = TypeName, - DisplayName = "Liquid", - Properties = new { MonacoLanguage = "liquid" }.ToDictionary(), - HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance - }; } \ No newline at end of file diff --git a/src/modules/Elsa.Python/Providers/PythonExpressionSyntaxProvider.cs b/src/modules/Elsa.Python/Providers/PythonExpressionSyntaxProvider.cs index 9d3ef494d..6355c9fbe 100644 --- a/src/modules/Elsa.Python/Providers/PythonExpressionSyntaxProvider.cs +++ b/src/modules/Elsa.Python/Providers/PythonExpressionSyntaxProvider.cs @@ -9,19 +9,15 @@ namespace Elsa.Python.Providers; internal class PythonExpressionDescriptorProvider : IExpressionDescriptorProvider { private const string TypeName = "Python"; - - public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) - { - var javaScript = CreatePythonDescriptor(); - return ValueTask.FromResult>(new[] { javaScript }); + public IEnumerable GetDescriptors() + { + yield return new() + { + Type = TypeName, + DisplayName = "Python", + Properties = new { MonacoLanguage = "python" }.ToDictionary(), + HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance + }; } - - private ExpressionDescriptor CreatePythonDescriptor() => new() - { - Type = TypeName, - DisplayName = "Python", - Properties = new { MonacoLanguage = "python" }.ToDictionary(), - HandlerFactory = ActivatorUtilities.GetServiceOrCreateInstance - }; } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs b/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs index 7cb2f8190..7bc1511ba 100644 --- a/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs +++ b/src/modules/Elsa.Workflows.Management/Features/WorkflowManagementFeature.cs @@ -166,7 +166,6 @@ public class WorkflowManagementFeature : FeatureBase .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/modules/Elsa.Workflows.Management/Providers/DefaultExpressionDescriptorProvider.cs b/src/modules/Elsa.Workflows.Management/Providers/DefaultExpressionDescriptorProvider.cs index d89470b97..345cacc4d 100644 --- a/src/modules/Elsa.Workflows.Management/Providers/DefaultExpressionDescriptorProvider.cs +++ b/src/modules/Elsa.Workflows.Management/Providers/DefaultExpressionDescriptorProvider.cs @@ -12,15 +12,13 @@ namespace Elsa.Workflows.Management.Providers; public class DefaultExpressionDescriptorProvider : IExpressionDescriptorProvider { /// - public ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) + public IEnumerable GetDescriptors() { - var literal = CreateLiteralDescriptor(); - var @object = CreateObjectDescriptor(); - var json = CreateJsonDescriptor(); - var @delegate = CreateDelegateDescriptor(); - var variable = CreateVariableDescriptor(); - - return ValueTask.FromResult>(new[] { literal, @object, json, @delegate, variable }); + yield return CreateLiteralDescriptor(); + yield return CreateObjectDescriptor(); + yield return CreateJsonDescriptor(); + yield return CreateDelegateDescriptor(); + yield return CreateVariableDescriptor(); } private ExpressionDescriptor CreateLiteralDescriptor() => CreateDescriptor("Literal", "Literal", isBrowsable: false); diff --git a/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistry.cs b/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistry.cs index 819bebf3c..ff181ff10 100644 --- a/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistry.cs +++ b/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistry.cs @@ -7,6 +7,16 @@ namespace Elsa.Workflows.Management.Services; public class ExpressionDescriptorRegistry : IExpressionDescriptorRegistry { private readonly IDictionary _expressionSyntaxDescriptors = new Dictionary(); + + /// Represents a registry of expression descriptors. + public ExpressionDescriptorRegistry(IEnumerable providers) + { + foreach (var provider in providers) + { + var descriptors = provider.GetDescriptors(); + AddRange(descriptors); + } + } /// public void Add(ExpressionDescriptor descriptor) => _expressionSyntaxDescriptors[descriptor.Type] = descriptor; diff --git a/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistryPopulator.cs b/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistryPopulator.cs index 10d61305c..6957ef42f 100644 --- a/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistryPopulator.cs +++ b/src/modules/Elsa.Workflows.Management/Services/ExpressionDescriptorRegistryPopulator.cs @@ -1,29 +1,29 @@ -using Elsa.Expressions.Contracts; - -namespace Elsa.Workflows.Management.Services; - -/// -public class ExpressionDescriptorRegistryPopulator : IExpressionDescriptorRegistryPopulator -{ - private readonly IEnumerable _providers; - private readonly IExpressionDescriptorRegistry _registry; - - /// - /// Initializes a new instance of the class. - /// - public ExpressionDescriptorRegistryPopulator(IEnumerable providers, IExpressionDescriptorRegistry registry) - { - _providers = providers; - _registry = registry; - } - - /// - public async ValueTask PopulateRegistryAsync(CancellationToken cancellationToken) - { - foreach (var provider in _providers) - { - var descriptors = await provider.GetDescriptorsAsync(cancellationToken); - _registry.AddRange(descriptors); - } - } -} \ No newline at end of file +// using Elsa.Expressions.Contracts; +// +// namespace Elsa.Workflows.Management.Services; +// +// /// +// public class ExpressionDescriptorRegistryPopulator : IExpressionDescriptorRegistryPopulator +// { +// private readonly IEnumerable _providers; +// private readonly IExpressionDescriptorRegistry _registry; +// +// /// +// /// Initializes a new instance of the class. +// /// +// public ExpressionDescriptorRegistryPopulator(IEnumerable providers, IExpressionDescriptorRegistry registry) +// { +// _providers = providers; +// _registry = registry; +// } +// +// /// +// public async ValueTask PopulateRegistryAsync(CancellationToken cancellationToken) +// { +// foreach (var provider in _providers) +// { +// var descriptors = await provider.GetDescriptorsAsync(cancellationToken); +// _registry.AddRange(descriptors); +// } +// } +// } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Services/DefaultRegistriesPopulator.cs b/src/modules/Elsa.Workflows.Runtime/Services/DefaultRegistriesPopulator.cs index b27b7f2ba..6d92cd417 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/DefaultRegistriesPopulator.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/DefaultRegistriesPopulator.cs @@ -10,27 +10,19 @@ public class DefaultRegistriesPopulator : IRegistriesPopulator { private readonly IWorkflowDefinitionStorePopulator _workflowDefinitionStorePopulator; private readonly IActivityRegistryPopulator _activityRegistryPopulator; - private readonly IExpressionDescriptorRegistryPopulator _expressionDescriptorRegistryPopulator; /// /// Initializes a new instance of the class. /// - public DefaultRegistriesPopulator( - IWorkflowDefinitionStorePopulator workflowDefinitionStorePopulator, - IActivityRegistryPopulator activityRegistryPopulator, - IExpressionDescriptorRegistryPopulator expressionDescriptorRegistryPopulator) + public DefaultRegistriesPopulator(IWorkflowDefinitionStorePopulator workflowDefinitionStorePopulator, IActivityRegistryPopulator activityRegistryPopulator) { _workflowDefinitionStorePopulator = workflowDefinitionStorePopulator; _activityRegistryPopulator = activityRegistryPopulator; - _expressionDescriptorRegistryPopulator = expressionDescriptorRegistryPopulator; } /// public async Task PopulateAsync(CancellationToken cancellationToken = default) { - // Stage 0: Populate the expression syntax registry. - await _expressionDescriptorRegistryPopulator.PopulateRegistryAsync(cancellationToken); - // Stage 1: Populate the activity registry. // Because workflow definitions can be used as activities, we need to make sure that the activity registry is populated before we populate the workflow definition store. await _activityRegistryPopulator.PopulateRegistryAsync(cancellationToken);