diff --git a/Samples.sln.DotSettings b/Samples.sln.DotSettings
index 4f264434f..cde7b3f37 100644
--- a/Samples.sln.DotSettings
+++ b/Samples.sln.DotSettings
@@ -10,6 +10,7 @@
True
True
True
+ True
True
True
True
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Class1.cs b/src/clients/Elsa.Client/Class1.cs
deleted file mode 100644
index 0a701b853..000000000
--- a/src/clients/Elsa.Client/Class1.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using System;
-
-namespace Elsa.Client
-{
- public class Class1
- {
- }
-}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Comparers/BlockingActivityEqualityComparer.cs b/src/clients/Elsa.Client/Comparers/BlockingActivityEqualityComparer.cs
new file mode 100644
index 000000000..0d8b443ec
--- /dev/null
+++ b/src/clients/Elsa.Client/Comparers/BlockingActivityEqualityComparer.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using Elsa.Client.Models;
+
+namespace Elsa.Client.Comparers
+{
+ public class BlockingActivityEqualityComparer : IEqualityComparer
+ {
+ public static BlockingActivityEqualityComparer Instance { get; } = new BlockingActivityEqualityComparer();
+
+ public bool Equals(BlockingActivity x, BlockingActivity y) => x.ActivityId.Equals(y.ActivityId);
+ public int GetHashCode(BlockingActivity obj) => obj.ActivityId.GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Elsa.Client.csproj b/src/clients/Elsa.Client/Elsa.Client.csproj
index 27560206d..9e2df3b5f 100644
--- a/src/clients/Elsa.Client/Elsa.Client.csproj
+++ b/src/clients/Elsa.Client/Elsa.Client.csproj
@@ -2,6 +2,26 @@
netstandard2.0
+ latest
+ 1.0.0
+ Elsa Contributors
+
+ Elsa is a set of workflow libraries and tools that enable lean and mean workflowing capabilities in any .NET Core application.
+ This package provides a client using Refit for Elsa's REST API endpoints.
+
+ 2020
+ https://github.com/elsa-workflows/elsa-core
+ https://github.com/elsa-workflows/elsa-core
+ GitHub
+ elsa, workflows, rest, api, client
+ icon.png
+ enable
+
+
+
+
+
+
diff --git a/src/clients/Elsa.Client/ElsaClient.cs b/src/clients/Elsa.Client/ElsaClient.cs
new file mode 100644
index 000000000..497a2ff1c
--- /dev/null
+++ b/src/clients/Elsa.Client/ElsaClient.cs
@@ -0,0 +1,14 @@
+using Elsa.Client.Services;
+
+namespace Elsa.Client
+{
+ internal class ElsaClient : IElsaClient
+ {
+ public ElsaClient(IWorkflowDefinitionsApi workflowDefinitionsApi)
+ {
+ WorkflowDefinitions = workflowDefinitionsApi;
+ }
+
+ public IWorkflowDefinitionsApi WorkflowDefinitions { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/IElsaClient.cs b/src/clients/Elsa.Client/IElsaClient.cs
new file mode 100644
index 000000000..48c0818dc
--- /dev/null
+++ b/src/clients/Elsa.Client/IElsaClient.cs
@@ -0,0 +1,9 @@
+using Elsa.Client.Services;
+
+namespace Elsa.Client
+{
+ public interface IElsaClient
+ {
+ IWorkflowDefinitionsApi WorkflowDefinitions { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ActivityDefinition.cs b/src/clients/Elsa.Client/Models/ActivityDefinition.cs
new file mode 100644
index 000000000..d962bde9c
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ActivityDefinition.cs
@@ -0,0 +1,17 @@
+namespace Elsa.Client.Models
+{
+ public class ActivityDefinition
+ {
+ public string ActivityId { get; set; } = default!;
+ public string Type { get; set; } = default!;
+ public string? Name { get; set; }
+ public string? DisplayName { get; set; }
+ public string? Description { get; set; }
+ public int? Left { get; set; }
+ public int? Top { get; set; }
+ public bool PersistWorkflow { get; set; }
+ public bool LoadWorkflowContext { get; set; }
+ public bool SaveWorkflowContext { get; set; }
+ public ActivityDefinitionProperties Properties { get; set; } = new ActivityDefinitionProperties();
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ActivityDefinitionProperties.cs b/src/clients/Elsa.Client/Models/ActivityDefinitionProperties.cs
new file mode 100644
index 000000000..84f639469
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ActivityDefinitionProperties.cs
@@ -0,0 +1,8 @@
+using System.Collections.Generic;
+
+namespace Elsa.Client.Models
+{
+ public class ActivityDefinitionProperties : Dictionary
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ActivityDefinitionPropertyValue.cs b/src/clients/Elsa.Client/Models/ActivityDefinitionPropertyValue.cs
new file mode 100644
index 000000000..28e6fe179
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ActivityDefinitionPropertyValue.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Elsa.Client.Models
+{
+ public class ActivityDefinitionPropertyValue
+ {
+ public static ActivityDefinitionPropertyValue Literal(T value) => new ActivityDefinitionPropertyValue(value!.ToString(), "Literal", typeof(T));
+ public static ActivityDefinitionPropertyValue Liquid(string expression) => new ActivityDefinitionPropertyValue(expression, "Liquid", typeof(T));
+ public static ActivityDefinitionPropertyValue JavaScript(string expression) => new ActivityDefinitionPropertyValue(expression, "JavaScript", typeof(T));
+
+ public ActivityDefinitionPropertyValue()
+ {
+ }
+
+ public ActivityDefinitionPropertyValue(string expression, string syntax, Type type)
+ {
+ Expression = expression;
+ Syntax = syntax;
+ Type = type;
+ }
+
+ public Type Type { get; set; } = default!;
+ public string Syntax { get; set; } = default!;
+ public string Expression { get; set; } = default!;
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ActivityInstance.cs b/src/clients/Elsa.Client/Models/ActivityInstance.cs
new file mode 100644
index 000000000..5a1ada856
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ActivityInstance.cs
@@ -0,0 +1,24 @@
+using Newtonsoft.Json.Linq;
+
+namespace Elsa.Client.Models
+{
+ public class ActivityInstance
+ {
+ public ActivityInstance()
+ {
+ }
+
+ public ActivityInstance(string id, string type, object? output, JObject data)
+ {
+ Id = id;
+ Type = type;
+ Data = data;
+ Output = output;
+ }
+
+ public string? Id { get; set; }
+ public string? Type { get; set; }
+ public JObject Data { get; set; } = new JObject();
+ public object? Output { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/BlockingActivity.cs b/src/clients/Elsa.Client/Models/BlockingActivity.cs
new file mode 100644
index 000000000..b55524398
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/BlockingActivity.cs
@@ -0,0 +1,19 @@
+namespace Elsa.Client.Models
+{
+ public class BlockingActivity
+ {
+ public BlockingActivity()
+ {
+ }
+
+ public BlockingActivity(string activityId, string activityType)
+ {
+ ActivityId = activityId;
+ ActivityType = activityType;
+ }
+
+ public string ActivityId { get; set; } = default!;
+ public string ActivityType { get; set; }= default!;
+ public string? Tag { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/CompositeActivityDefinition.cs b/src/clients/Elsa.Client/Models/CompositeActivityDefinition.cs
new file mode 100644
index 000000000..2a35a5e4c
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/CompositeActivityDefinition.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace Elsa.Client.Models
+{
+ public class CompositeActivityDefinition : ActivityDefinition
+ {
+ public CompositeActivityDefinition()
+ {
+ Activities = new List();
+ Connections = new List();
+ Type = "CompositeActivity";
+ }
+
+ public ICollection Activities { get; set; }
+ public ICollection Connections { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ConnectionDefinition.cs b/src/clients/Elsa.Client/Models/ConnectionDefinition.cs
new file mode 100644
index 000000000..434faab49
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ConnectionDefinition.cs
@@ -0,0 +1,20 @@
+namespace Elsa.Client.Models
+{
+ public class ConnectionDefinition
+ {
+ public ConnectionDefinition()
+ {
+ }
+
+ public ConnectionDefinition(string sourceActivityId, string targetActivityId, string outcome)
+ {
+ SourceActivityId = sourceActivityId;
+ TargetActivityId = targetActivityId;
+ Outcome = outcome;
+ }
+
+ public string? SourceActivityId { get; set; }
+ public string? TargetActivityId { get; set; }
+ public string? Outcome { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ExecutionLogEntry.cs b/src/clients/Elsa.Client/Models/ExecutionLogEntry.cs
new file mode 100644
index 000000000..053908578
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ExecutionLogEntry.cs
@@ -0,0 +1,20 @@
+using NodaTime;
+
+namespace Elsa.Client.Models
+{
+ public class ExecutionLogEntry
+ {
+ public ExecutionLogEntry()
+ {
+ }
+
+ public ExecutionLogEntry(string activityId, Instant timestamp)
+ {
+ ActivityId = activityId;
+ Timestamp = timestamp;
+ }
+
+ public string ActivityId { get; set; } = default!;
+ public Instant Timestamp { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/ScheduledActivity.cs b/src/clients/Elsa.Client/Models/ScheduledActivity.cs
new file mode 100644
index 000000000..1965c8828
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/ScheduledActivity.cs
@@ -0,0 +1,18 @@
+namespace Elsa.Client.Models
+{
+ public class ScheduledActivity
+ {
+ public ScheduledActivity()
+ {
+ }
+
+ public ScheduledActivity(string activityId, object? input = default)
+ {
+ ActivityId = activityId;
+ Input = input;
+ }
+
+ public string ActivityId { get; set; } = default!;
+ public object? Input { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/Scheduler.cs b/src/clients/Elsa.Client/Models/Scheduler.cs
new file mode 100644
index 000000000..4f859f80a
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/Scheduler.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Elsa.Client.Models
+{
+ public class Scheduler
+ {
+ private readonly Stack _stack = new Stack();
+
+ public bool HasScheduledActivities => _stack.Any();
+
+ public ScheduledActivity Schedule(string activityId, object? input = null)
+ {
+ var scheduledActivity = new ScheduledActivity(activityId, input);
+ _stack.Push(scheduledActivity);
+ return scheduledActivity;
+ }
+
+ public ScheduledActivity Next() => _stack.Pop();
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/Variables.cs b/src/clients/Elsa.Client/Models/Variables.cs
new file mode 100644
index 000000000..6179a0526
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/Variables.cs
@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+
+namespace Elsa.Client.Models
+{
+ public class Variables
+ {
+ public Variables()
+ {
+ Data = new Dictionary();
+ }
+
+ public Variables(Variables other) : this(other.Data)
+ {
+ }
+
+ public Variables(IDictionary data)
+ {
+ Data = data;
+ }
+
+ public IDictionary Data { get; set; }
+
+ public object? Get(string name) => Has(name) ? Data[name] : default;
+
+ public T Get(string name)
+ {
+ if (!Has(name))
+ return default!;
+
+ var value = Get(name);
+
+ if (value == null)
+ return default!;
+
+ return (T)value!;
+ }
+
+ public Variables Set(string name, object? value)
+ {
+ Data[name] = value;
+ return this;
+ }
+
+ public bool Has(string name) => Data.ContainsKey(name);
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/VersionOptions.cs b/src/clients/Elsa.Client/Models/VersionOptions.cs
new file mode 100644
index 000000000..abf854da5
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/VersionOptions.cs
@@ -0,0 +1,42 @@
+namespace Elsa.Client.Models
+{
+ public struct VersionOptions
+ {
+ ///
+ /// Gets the latest version.
+ ///
+ public static readonly VersionOptions Latest = new VersionOptions { IsLatest = true };
+
+ ///
+ /// Gets the published version.
+ ///
+ public static readonly VersionOptions Published = new VersionOptions { IsPublished = true };
+
+ ///
+ /// Gets the latest or published version.
+ ///
+ public static readonly VersionOptions LatestOrPublished = new VersionOptions { IsLatestOrPublished = true };
+
+ ///
+ /// Gets the draft version.
+ ///
+ public static readonly VersionOptions Draft = new VersionOptions { IsDraft = true };
+
+ ///
+ /// Gets all versions.
+ ///
+ public static readonly VersionOptions All = new VersionOptions { AllVersions = true };
+
+ ///
+ /// Gets a specific version.
+ ///
+ public static VersionOptions SpecificVersion(int version) => new VersionOptions { Version = version };
+
+ public bool IsLatest { get; private set; }
+ public bool IsLatestOrPublished { get; private set; }
+ public bool IsPublished { get; private set; }
+ public bool IsDraft { get; private set; }
+ public bool AllVersions { get; private set; }
+ public int Version { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Services/Models/WorkflowContextFidelity.cs b/src/clients/Elsa.Client/Models/WorkflowContextFidelity.cs
similarity index 90%
rename from src/core/Elsa.Abstractions/Services/Models/WorkflowContextFidelity.cs
rename to src/clients/Elsa.Client/Models/WorkflowContextFidelity.cs
index bbf48b70d..fbc9228f2 100644
--- a/src/core/Elsa.Abstractions/Services/Models/WorkflowContextFidelity.cs
+++ b/src/clients/Elsa.Client/Models/WorkflowContextFidelity.cs
@@ -1,4 +1,4 @@
-namespace Elsa.Services.Models
+namespace Elsa.Client.Models
{
public enum WorkflowContextFidelity
{
diff --git a/src/core/Elsa.Abstractions/Services/Models/WorkflowContextOptions.cs b/src/clients/Elsa.Client/Models/WorkflowContextOptions.cs
similarity index 86%
rename from src/core/Elsa.Abstractions/Services/Models/WorkflowContextOptions.cs
rename to src/clients/Elsa.Client/Models/WorkflowContextOptions.cs
index 37eff80dd..3a0b2c037 100644
--- a/src/core/Elsa.Abstractions/Services/Models/WorkflowContextOptions.cs
+++ b/src/clients/Elsa.Client/Models/WorkflowContextOptions.cs
@@ -1,6 +1,6 @@
using System;
-namespace Elsa.Services.Models
+namespace Elsa.Client.Models
{
public class WorkflowContextOptions
{
diff --git a/src/clients/Elsa.Client/Models/WorkflowDefinition.cs b/src/clients/Elsa.Client/Models/WorkflowDefinition.cs
new file mode 100644
index 000000000..416e1fbb5
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/WorkflowDefinition.cs
@@ -0,0 +1,24 @@
+namespace Elsa.Client.Models
+{
+ public class WorkflowDefinition : CompositeActivityDefinition
+ {
+ public WorkflowDefinition()
+ {
+ Variables = new Variables();
+ Type = "Workflow";
+ }
+
+ public int Id { get; set; }
+ public string WorkflowDefinitionId { get; set; } = default!;
+ public string WorkflowDefinitionVersionId { get; set; } = default!;
+ public int Version { get; set; }
+ public Variables? Variables { get; set; }
+ public WorkflowContextOptions? ContextOptions { get; set; }
+ public bool IsSingleton { get; set; }
+ public WorkflowPersistenceBehavior PersistenceBehavior { get; set; }
+ public bool DeleteCompletedInstances { get; set; }
+ public bool IsEnabled { get; set; }
+ public bool IsPublished { get; set; }
+ public bool IsLatest { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/WorkflowExecutionScope.cs b/src/clients/Elsa.Client/Models/WorkflowExecutionScope.cs
new file mode 100644
index 000000000..33297e39a
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/WorkflowExecutionScope.cs
@@ -0,0 +1,17 @@
+namespace Elsa.Client.Models
+{
+ public class WorkflowExecutionScope
+ {
+ public WorkflowExecutionScope()
+ {
+ Variables = new Variables();
+ }
+
+ public WorkflowExecutionScope(Variables variables)
+ {
+ Variables = variables;
+ }
+
+ public Variables Variables { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/WorkflowFault.cs b/src/clients/Elsa.Client/Models/WorkflowFault.cs
new file mode 100644
index 000000000..6822de3f1
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/WorkflowFault.cs
@@ -0,0 +1,8 @@
+namespace Elsa.Client.Models
+{
+ public class WorkflowFault
+ {
+ public string? FaultedActivityId { get; set; }
+ public string? Message { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/WorkflowInstance.cs b/src/clients/Elsa.Client/Models/WorkflowInstance.cs
new file mode 100644
index 000000000..ecad13631
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/WorkflowInstance.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using Elsa.Client.Comparers;
+using NodaTime;
+
+namespace Elsa.Client.Models
+{
+ public class WorkflowInstance
+ {
+ private HashSet _blockingActivities = new HashSet(BlockingActivityEqualityComparer.Instance);
+
+ public WorkflowInstance()
+ {
+ Variables = new Variables();
+ Activities = new List();
+ ExecutionLog = new List();
+ ScheduledActivities = new Stack();
+ PostScheduledActivities = new Stack();
+ }
+
+ public int Id { get; set; }
+ public string WorkflowInstanceId { get; set; } = default!;
+ public string WorkflowDefinitionId { get; set; } = default!;
+ public int Version { get; set; }
+ public WorkflowStatus Status { get; set; }
+ public string? CorrelationId { get; set; }
+ public string? ContextId { get; set; }
+ public Instant CreatedAt { get; set; }
+ public Variables Variables { get; set; }
+ public object? Output { get; set; }
+ public ICollection Activities { get; set; }
+
+ public HashSet BlockingActivities
+ {
+ get => _blockingActivities;
+ set => _blockingActivities = new HashSet(value, BlockingActivityEqualityComparer.Instance);
+ }
+
+ public ICollection ExecutionLog { get; set; }
+ public WorkflowFault? Fault { get; set; }
+ public Stack ScheduledActivities { get; set; }
+ public Stack PostScheduledActivities { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/WorkflowPersistenceBehavior.cs b/src/clients/Elsa.Client/Models/WorkflowPersistenceBehavior.cs
new file mode 100644
index 000000000..1342a47b0
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/WorkflowPersistenceBehavior.cs
@@ -0,0 +1,20 @@
+namespace Elsa.Client.Models
+{
+ public enum WorkflowPersistenceBehavior
+ {
+ ///
+ /// Workflow instances are persisted only when being suspended.
+ ///
+ Suspended,
+
+ ///
+ /// Workflow instances are persisted after the workflow executed scheduled activities.
+ ///
+ WorkflowPassCompleted,
+
+ ///
+ /// Workflow instances are persisted after each activity that executed.
+ ///
+ ActivityExecuted
+ }
+}
\ No newline at end of file
diff --git a/src/clients/Elsa.Client/Models/WorkflowStatus.cs b/src/clients/Elsa.Client/Models/WorkflowStatus.cs
new file mode 100644
index 000000000..695ed7992
--- /dev/null
+++ b/src/clients/Elsa.Client/Models/WorkflowStatus.cs
@@ -0,0 +1,12 @@
+namespace Elsa.Client.Models
+{
+ public enum WorkflowStatus
+ {
+ Idle,
+ Running,
+ Finished,
+ Suspended,
+ Faulted,
+ Cancelled
+ }
+}
diff --git a/src/clients/Elsa.Client/Services/IWorkflowDefinitionsApi.cs b/src/clients/Elsa.Client/Services/IWorkflowDefinitionsApi.cs
new file mode 100644
index 000000000..217cca87f
--- /dev/null
+++ b/src/clients/Elsa.Client/Services/IWorkflowDefinitionsApi.cs
@@ -0,0 +1,16 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Elsa.Client.Models;
+using Refit;
+
+namespace Elsa.Client.Services
+{
+ public interface IWorkflowDefinitionsApi
+ {
+ [Get("/v1/workflow-definitions/{id}/latest")]
+ Task GetLatestAsync([AliasAs("id")] string workflowDefinitionId, CancellationToken cancellationToken = default);
+
+ [Get("/v1/workflow-definitions/{id}/published")]
+ Task GetPublishedAsync([AliasAs("id")] string workflowDefinitionId, CancellationToken cancellationToken = default);
+ }
+}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs b/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs
index 7e1aa0e22..94703e5df 100644
--- a/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs
+++ b/src/core/Elsa.Abstractions/Extensions/WorkflowBlueprintExtensions.cs
@@ -42,19 +42,16 @@ namespace Elsa
}
public static T GetActivityState(
- this IWorkflowBlueprint workflowBlueprint,
- string activityId,
+ this IWorkflowBlueprint workflowBlueprint,
Expression> propertyExpression,
ActivityExecutionContext activityExecutionContext) where TActivity : IActivity
{
var expression = (MemberExpression)propertyExpression.Body;
string propertyName = expression.Member.Name;
- return GetActivityState(workflowBlueprint, activityId, propertyName, activityExecutionContext);
+ return GetActivityState(propertyName, activityExecutionContext);
}
public static T GetActivityState(
- this IWorkflowBlueprint workflowBlueprint,
- string activityId,
string propertyName,
ActivityExecutionContext activityExecutionContext)
{
diff --git a/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs b/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs
index fad658632..20e5edca5 100644
--- a/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs
+++ b/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs
@@ -1,4 +1,6 @@
using System;
+using Elsa.Converters;
+using Newtonsoft.Json;
namespace Elsa.Models
{
@@ -19,7 +21,7 @@ namespace Elsa.Models
Type = type;
}
- public Type Type { get; set; } = default!;
+ [JsonConverter(typeof(TypeConverter))] public Type Type { get; set; } = default!;
public string Syntax { get; set; } = default!;
public string Expression { get; set; } = default!;
}
diff --git a/src/core/Elsa.Abstractions/Models/WorkflowContextFidelity.cs b/src/core/Elsa.Abstractions/Models/WorkflowContextFidelity.cs
new file mode 100644
index 000000000..ae914bbc3
--- /dev/null
+++ b/src/core/Elsa.Abstractions/Models/WorkflowContextFidelity.cs
@@ -0,0 +1,15 @@
+namespace Elsa.Models
+{
+ public enum WorkflowContextFidelity
+ {
+ ///
+ /// The workflow context is loaded only once per burst of execution.
+ ///
+ Burst,
+
+ ///
+ /// The workflow context is loaded before executing an activity.
+ ///
+ Activity
+ }
+}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Models/WorkflowContextOptions.cs b/src/core/Elsa.Abstractions/Models/WorkflowContextOptions.cs
new file mode 100644
index 000000000..60464da40
--- /dev/null
+++ b/src/core/Elsa.Abstractions/Models/WorkflowContextOptions.cs
@@ -0,0 +1,11 @@
+using System;
+using Elsa.Services.Models;
+
+namespace Elsa.Models
+{
+ public class WorkflowContextOptions
+ {
+ public Type ContextType { get; set; } = default!;
+ public WorkflowContextFidelity ContextFidelity { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Services/IWorkflowDefinitionManager.cs b/src/core/Elsa.Abstractions/Services/IWorkflowDefinitionManager.cs
index aa3ecf6df..51e0a7d58 100644
--- a/src/core/Elsa.Abstractions/Services/IWorkflowDefinitionManager.cs
+++ b/src/core/Elsa.Abstractions/Services/IWorkflowDefinitionManager.cs
@@ -11,9 +11,10 @@ namespace Elsa.Services
{
public interface IWorkflowDefinitionManager
{
- ValueTask SaveAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default);
- ValueTask DeleteAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default);
- ValueTask> ListAsync(CancellationToken cancellationToken = default);
+ Task SaveAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default);
+ Task DeleteAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default);
+ Task CountAsync(VersionOptions? version = default, CancellationToken cancellationToken = default);
+ Task> ListAsync(int? skip = default, int? take = default, VersionOptions? version = default, CancellationToken cancellationToken = default);
IQuery Query();
IQuery Query() where TIndex : class, IIndex;
diff --git a/src/core/Elsa.Abstractions/Triggers/ActivityBlueprintWrapper.cs b/src/core/Elsa.Abstractions/Triggers/ActivityBlueprintWrapper.cs
index dbf36223e..907bdcab4 100644
--- a/src/core/Elsa.Abstractions/Triggers/ActivityBlueprintWrapper.cs
+++ b/src/core/Elsa.Abstractions/Triggers/ActivityBlueprintWrapper.cs
@@ -26,8 +26,7 @@ namespace Elsa.Triggers
public T GetState(Expression> propertyExpression)
{
var workflowBlueprint = _activityExecutionContext.WorkflowExecutionContext.WorkflowBlueprint;
- var activityId = _activityExecutionContext.ActivityBlueprint.Id;
- return workflowBlueprint.GetActivityState(activityId, propertyExpression, _activityExecutionContext);
+ return workflowBlueprint.GetActivityState(propertyExpression, _activityExecutionContext);
}
}
}
\ No newline at end of file
diff --git a/src/core/Elsa.Core/Services/WorkflowDefinitionManager.cs b/src/core/Elsa.Core/Services/WorkflowDefinitionManager.cs
index d51832ee0..0a85530fd 100644
--- a/src/core/Elsa.Core/Services/WorkflowDefinitionManager.cs
+++ b/src/core/Elsa.Core/Services/WorkflowDefinitionManager.cs
@@ -4,6 +4,7 @@ using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Data;
+using Elsa.Extensions;
using Elsa.Models;
using YesSql;
using YesSql.Indexes;
@@ -19,19 +20,36 @@ namespace Elsa.Services
_session = session;
}
- public ValueTask SaveAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default)
+ public Task SaveAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default)
{
_session.Save(workflowDefinition, CollectionNames.WorkflowDefinitions);
- return new ValueTask();
+ return Task.CompletedTask;
}
- public ValueTask DeleteAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default)
+ public Task DeleteAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken = default)
{
_session.Delete(workflowDefinition, CollectionNames.WorkflowDefinitions);
- return new ValueTask();
+ return Task.CompletedTask;
+ }
+
+ public async Task CountAsync(VersionOptions? version = default, CancellationToken cancellationToken = default) =>
+ await Query()
+ .WithVersion(version ?? VersionOptions.Published)
+ .CountAsync();
+
+ public async Task> ListAsync(int? skip = default, int? take = default, VersionOptions? version = default, CancellationToken cancellationToken = default)
+ {
+ var query = Query().WithVersion(version ?? VersionOptions.Published);
+
+ if (skip != null)
+ query = query.Skip(skip.Value);
+
+ if (take != null)
+ query = query.Take(take.Value);
+
+ return await query.ListAsync();
}
- public async ValueTask> ListAsync(CancellationToken cancellationToken = default) => await Query().ListAsync();
public IQuery Query() => _session.Query(CollectionNames.WorkflowDefinitions);
public IQuery Query() where TIndex : class, IIndex => _session.Query(CollectionNames.WorkflowDefinitions);
public IQuery Query(Expression> predicate) where TIndex : class, IIndex => _session.Query(predicate, CollectionNames.WorkflowDefinitions);
diff --git a/src/core/Elsa.Core/WorkflowProviders/DatabaseWorkflowProvider.cs b/src/core/Elsa.Core/WorkflowProviders/DatabaseWorkflowProvider.cs
index f28baee9d..c7e8e66c4 100644
--- a/src/core/Elsa.Core/WorkflowProviders/DatabaseWorkflowProvider.cs
+++ b/src/core/Elsa.Core/WorkflowProviders/DatabaseWorkflowProvider.cs
@@ -23,7 +23,7 @@ namespace Elsa.WorkflowProviders
protected override async ValueTask> OnGetWorkflowsAsync(CancellationToken cancellationToken)
{
- var workflowDefinitions = await _workflowDefinitionManager.ListAsync(cancellationToken);
+ var workflowDefinitions = await _workflowDefinitionManager.ListAsync(cancellationToken: cancellationToken);
return workflowDefinitions.Select(_workflowBlueprintMaterializer.CreateWorkflowBlueprint);
}
}
diff --git a/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj b/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj
index 113af2433..9700a14f0 100644
--- a/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj
+++ b/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj
@@ -28,6 +28,7 @@
+
diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs
index 47940db17..e4761b98c 100644
--- a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs
+++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs
@@ -1,32 +1,41 @@
-using System.Threading;
+using System.Net;
+using System.Threading;
using System.Threading.Tasks;
using Elsa.Extensions;
using Elsa.Models;
using Elsa.Serialization;
+using Elsa.Server.Api.Swagger;
using Elsa.Services;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json.Serialization;
+using Swashbuckle.AspNetCore.Filters;
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
{
[ApiController]
[ApiVersion("1")]
- [Route("v{version:apiVersion}/workflow-definitions/{id}")]
+ [Route("v{version:apiVersion}/workflow-definitions/{id:int}")]
+ [Produces("application/json")]
public class Get : Controller
{
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
private readonly IContentSerializer _serializer;
- public Get(IWorkflowDefinitionManager workflowDefinitionManager, IContentSerializer serializer)
+ protected Get(IWorkflowDefinitionManager workflowDefinitionManager, IContentSerializer serializer)
{
- _serializer = serializer;
_workflowDefinitionManager = workflowDefinitionManager;
+ _serializer = serializer;
}
[HttpGet]
- public async Task Handle([FromRoute(Name = "id")] string workflowDefinitionId, CancellationToken cancellationToken)
+ [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WorkflowDefinition))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [SwaggerResponseExample(StatusCodes.Status200OK, typeof(WorkflowDefinitionExample))]
+ public async Task Handle(string workflowDefinitionId, VersionOptions? version = default, CancellationToken cancellationToken = default)
{
- var workflowDefinition = await _workflowDefinitionManager.GetAsync(workflowDefinitionId, VersionOptions.Latest, cancellationToken);
- return workflowDefinition == null ? (IActionResult)NotFound() : Json(workflowDefinition, _serializer.GetSettings());
+ var workflowDefinition = await _workflowDefinitionManager.GetAsync(workflowDefinitionId, version ?? VersionOptions.Latest, cancellationToken);
+ return workflowDefinition == null ? (IActionResult) NotFound() : Json(workflowDefinition, _serializer.GetSettings());
}
}
}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs
new file mode 100644
index 000000000..251d1f973
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs
@@ -0,0 +1,37 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Elsa.Models;
+using Elsa.Serialization;
+using Elsa.Server.Api.Models;
+using Elsa.Services;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
+{
+ [ApiController]
+ [ApiVersion("1")]
+ [Route("v{version:apiVersion}/workflow-definitions")]
+ [Produces("application/json")]
+ public class List : Controller
+ {
+ private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
+ private readonly IContentSerializer _serializer;
+
+ public List(IWorkflowDefinitionManager workflowDefinitionManager, IContentSerializer serializer)
+ {
+ _workflowDefinitionManager = workflowDefinitionManager;
+ _serializer = serializer;
+ }
+
+ [HttpGet]
+ public async Task>> Handle(int page = 0, int pageSize = 50, VersionOptions? version = default, CancellationToken cancellationToken = default)
+ {
+ version ??= VersionOptions.Latest;
+ var totalCount = await _workflowDefinitionManager.CountAsync(version, cancellationToken);
+ var items = await _workflowDefinitionManager.ListAsync(page, pageSize, version, cancellationToken);
+ var pagedList = new PagedList(items, page, pageSize, totalCount);
+
+ return Json(pagedList, _serializer.GetSettings());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.cs
index 45f1923d8..568948e0b 100644
--- a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.cs
+++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.cs
@@ -2,18 +2,18 @@
using System.Threading.Tasks;
using Elsa.Services;
using Microsoft.AspNetCore.Mvc;
-using YesSql;
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
{
[ApiController]
[ApiVersion("1")]
[Route("v{version:apiVersion}/workflow-definitions")]
+ [Produces("application/json")]
public class Post : ControllerBase
{
private readonly IWorkflowPublisher _workflowPublisher;
- public Post(IWorkflowDefinitionManager workflowDefinitionManager, IWorkflowPublisher workflowPublisher, ISession session)
+ public Post(IWorkflowPublisher workflowPublisher)
{
_workflowPublisher = workflowPublisher;
}
diff --git a/src/server/Elsa.Server.Api/Models/PagedList.cs b/src/server/Elsa.Server.Api/Models/PagedList.cs
new file mode 100644
index 000000000..6e4a6a535
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Models/PagedList.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Elsa.Server.Api.Models
+{
+ public class PagedList
+ {
+ public PagedList(IEnumerable items, int page, int pageSize, int totalCount)
+ {
+ Page = page;
+ PageSize = pageSize;
+ TotalCount = totalCount;
+ Items = items.ToList();
+ }
+
+ public ICollection Items { get; }
+ public int Page { get; }
+ public int PageSize { get; }
+ public int TotalCount { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Api/Swagger/WorkflowDefinitionExample.cs b/src/server/Elsa.Server.Api/Swagger/WorkflowDefinitionExample.cs
new file mode 100644
index 000000000..54501dc73
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Swagger/WorkflowDefinitionExample.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using Elsa.Models;
+using Swashbuckle.AspNetCore.Filters;
+
+namespace Elsa.Server.Api.Swagger
+{
+ public class WorkflowDefinitionExample : IExamplesProvider
+ {
+ public WorkflowDefinition GetExamples()
+ {
+ return new WorkflowDefinition
+ {
+ Id = 1,
+ Name = "ProcessOrderWorkflow",
+ DisplayName = "Process Order Workflow",
+ Description = "Process new orders",
+ Version = 1,
+ IsPublished = true,
+ WorkflowDefinitionId = "26bd1dca39954c8f93364a18c2a35528",
+ WorkflowDefinitionVersionId = "c8c57402e68949598a45411c74e463e1",
+ Type = "Workflow",
+ ContextOptions = new WorkflowContextOptions
+ {
+ ContextFidelity = WorkflowContextFidelity.Burst,
+ ContextType = typeof(Order)
+ },
+ Activities = new[]
+ {
+ new ActivityDefinition
+ {
+ ActivityId = "activity-1",
+ }
+ }
+ };
+ }
+ }
+
+ public class Order
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj b/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj
index 8781dc2f2..1044c98a1 100644
--- a/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj
+++ b/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj
@@ -2,6 +2,7 @@
net5.0
+ latest
diff --git a/src/server/Elsa.Server.Host/Properties/launchSettings.json b/src/server/Elsa.Server.Host/Properties/launchSettings.json
index 15a75cfa7..cacd3665c 100644
--- a/src/server/Elsa.Server.Host/Properties/launchSettings.json
+++ b/src/server/Elsa.Server.Host/Properties/launchSettings.json
@@ -1,26 +1,13 @@
{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:11000"
+ "profiles": {
+ "Elsa.Server.Host": {
+ "commandName": "Project",
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:11000",
+ "launchUrl": "http://localhost:11000/swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
}
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": false,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Elsa.Server.Host": {
- "commandName": "Project",
- "launchBrowser": false,
- "applicationUrl": "http://localhost:11000",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- }
- }
}
diff --git a/src/server/Elsa.Server.Host/Startup.cs b/src/server/Elsa.Server.Host/Startup.cs
index 4510027d5..a51b07a94 100644
--- a/src/server/Elsa.Server.Host/Startup.cs
+++ b/src/server/Elsa.Server.Host/Startup.cs
@@ -1,4 +1,5 @@
using Elsa.Runtime;
+using Elsa.Server.Api.Swagger;
using Elsa.StartupTasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -6,6 +7,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.Filters;
using YesSql.Provider.Sqlite;
namespace Elsa.Server.Host
@@ -31,8 +33,12 @@ namespace Elsa.Server.Host
elsa => elsa
.UsePersistence(config => config.UseSqLite(connectionString)));
+ services.AddSingleton();
services
- .AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo {Title = "Elsa", Version = "v1"}); })
+ .AddSwaggerGen(c =>
+ {
+ c.SwaggerDoc("v1", new OpenApiInfo {Title = "Elsa", Version = "v1"});
+ })
.AddElsaApiEndpoints()
.AddCors(
options => options.AddDefaultPolicy(