diff --git a/.editorconfig b/.editorconfig
index 593f45591..5cc8f95ea 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,3 +10,6 @@ indent_size=4
resharper_csharp_max_line_length=240
resharper_keep_user_linebreaks=true
+# Microsoft .NET properties
+csharp_new_line_before_members_in_object_initializers=false
+
diff --git a/Elsa.sln b/Elsa.sln
index 2bf1d48d7..ded392a58 100644
--- a/Elsa.sln
+++ b/Elsa.sln
@@ -52,9 +52,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Core", "src\ser
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.UnitTests", "test\unit\Elsa.Core.UnitTests\Elsa.Core.UnitTests.csproj", "{475EEB95-ED27-4366-88EA-97C5000AC8E8}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}"
EndProject
@@ -72,6 +70,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "locking", "locking", "{7CD5
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.YesSql.Provider.Sqlite.InMemory", "src\core\Elsa.YesSql.Provider.Sqlite.InMemory\Elsa.YesSql.Provider.Sqlite.InMemory.csproj", "{E2D63391-1986-45C8-A18F-4D58F3D71057}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Core.IntegrationTests", "test\integration\Elsa.Core.IntegrationTests\Elsa.Core.IntegrationTests.csproj", "{3C43CC9B-E64F-4481-9B27-3E868AD95CE9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -130,10 +130,6 @@ Global
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.Build.0 = Release|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.Build.0 = Release|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -159,6 +155,10 @@ Global
{E2D63391-1986-45C8-A18F-4D58F3D71057}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2D63391-1986-45C8-A18F-4D58F3D71057}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2D63391-1986-45C8-A18F-4D58F3D71057}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C43CC9B-E64F-4481-9B27-3E868AD95CE9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -182,7 +182,6 @@ Global
{468E498C-59DB-4541-8D8A-0D89DE9083AB} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
- {475EEB95-ED27-4366-88EA-97C5000AC8E8} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}
{12D29DDC-A885-4CAA-908C-106D845B10C0} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
@@ -191,6 +190,7 @@ Global
{EBD49CCA-5400-4C36-B5DF-7B28190AA323} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
{150EF356-E8BC-4922-91C2-362017479409} = {7CD5C8D5-EC78-4A99-A514-F01CA7197AC8}
{E2D63391-1986-45C8-A18F-4D58F3D71057} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
+ {3C43CC9B-E64F-4481-9B27-3E868AD95CE9} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
diff --git a/Samples.sln b/Samples.sln
index ffd9941c7..30ed6028f 100644
--- a/Samples.sln
+++ b/Samples.sln
@@ -56,9 +56,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Host", "src\ser
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit", "unit", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Core.UnitTests", "test\unit\Elsa.Core.UnitTests\Elsa.Core.UnitTests.csproj", "{475EEB95-ED27-4366-88EA-97C5000AC8E8}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "integration", "integration", "{0A3C36AB-2ACF-4175-A512-66B4C3DB9371}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}"
EndProject
@@ -68,8 +66,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Timers", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.DistributedLocking.SqlServer", "src\providers\Elsa.DistributedLocking.SqlServer\Elsa.DistributedLocking.SqlServer.csproj", "{150EF356-E8BC-4922-91C2-362017479409}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.GraphQL", "src\server\Elsa.Server.GraphQL\Elsa.Server.GraphQL.csproj", "{12D29DDC-A885-4CAA-908C-106D845B10C0}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.Serialization", "src\samples\Elsa.Samples.Serialization\Elsa.Samples.Serialization.csproj", "{DF47517F-9029-44DF-A29F-F2DE15041473}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HelloWorldConsole", "src\samples\Elsa.Samples.HelloWorldConsole\Elsa.Samples.HelloWorldConsole.csproj", "{E224F8CF-F9F5-4E99-B405-758F3C02C47A}"
@@ -94,6 +90,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.ReadLineEchoCo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.YesSql.Provider.Sqlite.InMemory", "src\core\Elsa.YesSql.Provider.Sqlite.InMemory\Elsa.YesSql.Provider.Sqlite.InMemory.csproj", "{D0364288-3072-44F4-877C-7721C20BC27F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Core.IntegrationTests", "test\integration\Elsa.Core.IntegrationTests\Elsa.Core.IntegrationTests.csproj", "{4CB34AB3-01C9-4911-8914-EABAA744EAD3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "component", "component", "{FC47A50F-03B2-47D8-AAFB-075314FBA186}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.ComponentTests", "test\component\Elsa.ComponentTests\Elsa.ComponentTests.csproj", "{BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Server.Api", "src\server\Elsa.Server.Api\Elsa.Server.Api.csproj", "{44E0B699-A140-4551-A0E9-9FD9F171A9C2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -156,10 +160,6 @@ Global
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.Build.0 = Release|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {475EEB95-ED27-4366-88EA-97C5000AC8E8}.Release|Any CPU.Build.0 = Release|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7C689EB-5AD6-4E91-A007-6116EEA702FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -172,10 +172,6 @@ Global
{150EF356-E8BC-4922-91C2-362017479409}.Debug|Any CPU.Build.0 = Debug|Any CPU
{150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.ActiveCfg = Release|Any CPU
{150EF356-E8BC-4922-91C2-362017479409}.Release|Any CPU.Build.0 = Release|Any CPU
- {12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {12D29DDC-A885-4CAA-908C-106D845B10C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {12D29DDC-A885-4CAA-908C-106D845B10C0}.Release|Any CPU.Build.0 = Release|Any CPU
{DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF47517F-9029-44DF-A29F-F2DE15041473}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF47517F-9029-44DF-A29F-F2DE15041473}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -221,6 +217,18 @@ Global
{D0364288-3072-44F4-877C-7721C20BC27F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0364288-3072-44F4-877C-7721C20BC27F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0364288-3072-44F4-877C-7721C20BC27F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CB34AB3-01C9-4911-8914-EABAA744EAD3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44E0B699-A140-4551-A0E9-9FD9F171A9C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -246,11 +254,9 @@ Global
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
- {475EEB95-ED27-4366-88EA-97C5000AC8E8} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
{E7C689EB-5AD6-4E91-A007-6116EEA702FC} = {0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D}
{071DD6EC-D00C-4513-82B6-3FE8438061E3} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
- {12D29DDC-A885-4CAA-908C-106D845B10C0} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
{DF47517F-9029-44DF-A29F-F2DE15041473} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{E224F8CF-F9F5-4E99-B405-758F3C02C47A} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{A11D79AE-F4C9-4595-9B73-0E0AB221B90D} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
@@ -264,6 +270,10 @@ Global
{F755FB1F-72FB-4F7B-8270-F5F40F4D6952} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{867CB845-B803-4D40-9360-3D11ADBD9CE9} = {5E5E1E84-DDBC-40D6-B891-0D563A15A44A}
{D0364288-3072-44F4-877C-7721C20BC27F} = {35F44BE9-13D0-417C-A01A-F0787BEE6DC3}
+ {4CB34AB3-01C9-4911-8914-EABAA744EAD3} = {0A3C36AB-2ACF-4175-A512-66B4C3DB9371}
+ {FC47A50F-03B2-47D8-AAFB-075314FBA186} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
+ {BB5819C7-434A-4AC5-8B0E-6C4FA672EBD5} = {FC47A50F-03B2-47D8-AAFB-075314FBA186}
+ {44E0B699-A140-4551-A0E9-9FD9F171A9C2} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
diff --git a/Samples.sln.DotSettings b/Samples.sln.DotSettings
index 1e636e30a..ba2138f0c 100644
--- a/Samples.sln.DotSettings
+++ b/Samples.sln.DotSettings
@@ -8,4 +8,5 @@
True
True
True
- True
\ No newline at end of file
+ True
+ True
\ No newline at end of file
diff --git a/src/activities/Elsa.Activities.Console/Activities/ReadLine/ReadLine.cs b/src/activities/Elsa.Activities.Console/Activities/ReadLine/ReadLine.cs
index 8ca4ef24d..8a02f5e26 100644
--- a/src/activities/Elsa.Activities.Console/Activities/ReadLine/ReadLine.cs
+++ b/src/activities/Elsa.Activities.Console/Activities/ReadLine/ReadLine.cs
@@ -22,7 +22,7 @@ namespace Elsa.Activities.Console
)]
public class ReadLine : Activity
{
- private readonly TextReader _input;
+ private readonly TextReader? _input;
public ReadLine()
{
@@ -46,7 +46,7 @@ namespace Elsa.Activities.Console
protected override IActivityExecutionResult OnResume(ActivityExecutionContext context)
{
- var receivedInput = (string)context.Input;
+ var receivedInput = (string)context.Input!;
return Execute(receivedInput);
}
diff --git a/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLine.cs b/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLine.cs
index 911de62ab..681a8c530 100644
--- a/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLine.cs
+++ b/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLine.cs
@@ -30,7 +30,7 @@ namespace Elsa.Activities.Console
}
[ActivityProperty(Hint = "The text to write.")]
- public string Text { get; set; }
+ public string? Text { get; set; }
private readonly TextWriter _output;
diff --git a/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLineExtensions.cs b/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLineExtensions.cs
new file mode 100644
index 000000000..2ea67a0a3
--- /dev/null
+++ b/src/activities/Elsa.Activities.Console/Activities/WriteLine/WriteLineExtensions.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Threading.Tasks;
+using Elsa.Builders;
+using Elsa.Services.Models;
+
+// ReSharper disable once CheckNamespace
+namespace Elsa.Activities.Console
+{
+ public static class WriteLineExtensions
+ {
+ public static ISetupActivity WithText(this ISetupActivity writeLine, Func> text) => writeLine.Set(x => x.Text, text);
+ public static ISetupActivity WithText(this ISetupActivity writeLine, Func text) => writeLine.Set(x => x.Text, text);
+ public static ISetupActivity WithText(this ISetupActivity writeLine, Func> text) => writeLine.Set(x => x.Text, text);
+ public static ISetupActivity WithText(this ISetupActivity writeLine, Func text) => writeLine.Set(x => x.Text, text);
+ public static ISetupActivity WithText(this ISetupActivity writeLine, string? text) => writeLine.Set(x => x.Text, text);
+ }
+}
\ No newline at end of file
diff --git a/src/activities/Elsa.Activities.Console/Elsa.Activities.Console.csproj b/src/activities/Elsa.Activities.Console/Elsa.Activities.Console.csproj
index b6b7bc286..0e5c0b10d 100644
--- a/src/activities/Elsa.Activities.Console/Elsa.Activities.Console.csproj
+++ b/src/activities/Elsa.Activities.Console/Elsa.Activities.Console.csproj
@@ -18,6 +18,7 @@
GitHub
elsa, workflows
icon.png
+ enable
diff --git a/src/activities/Elsa.Activities.Console/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.Console/Extensions/ServiceCollectionExtensions.cs
index 03b8941af..a2621f4d6 100644
--- a/src/activities/Elsa.Activities.Console/Extensions/ServiceCollectionExtensions.cs
+++ b/src/activities/Elsa.Activities.Console/Extensions/ServiceCollectionExtensions.cs
@@ -7,10 +7,11 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
- public static IServiceCollection AddConsoleActivities(this IServiceCollection services, TextReader standardIn = default)
+ public static IServiceCollection AddConsoleActivities(this IServiceCollection services, TextReader? standardIn = default, TextWriter? standardOut = default)
{
return services
.AddSingleton(standardIn ?? Console.In)
+ .AddSingleton(standardOut ?? Console.Out)
.AddActivity()
.AddActivity();
}
diff --git a/src/activities/Elsa.Activities.Dropbox/Elsa.Activities.Dropbox.csproj b/src/activities/Elsa.Activities.Dropbox/Elsa.Activities.Dropbox.csproj
index 59b8d8ee9..67939b731 100644
--- a/src/activities/Elsa.Activities.Dropbox/Elsa.Activities.Dropbox.csproj
+++ b/src/activities/Elsa.Activities.Dropbox/Elsa.Activities.Dropbox.csproj
@@ -33,7 +33,7 @@
-
+
diff --git a/src/activities/Elsa.Activities.UserTask/Activities/UserTask.cs b/src/activities/Elsa.Activities.UserTask/Activities/UserTask.cs
index bf362d92b..7530c9e03 100644
--- a/src/activities/Elsa.Activities.UserTask/Activities/UserTask.cs
+++ b/src/activities/Elsa.Activities.UserTask/Activities/UserTask.cs
@@ -20,7 +20,7 @@ namespace Elsa.Activities.UserTask.Activities
)]
public class UserTask : Activity
{
- private readonly IJsonSerializer _serializer;
+ private readonly IContentSerializer _serializer;
[ActivityProperty(
Type = ActivityPropertyTypes.List,
@@ -28,7 +28,7 @@ namespace Elsa.Activities.UserTask.Activities
)]
public ICollection Actions { get; set; } = new List();
- public UserTask(IJsonSerializer serializer)
+ public UserTask(IContentSerializer serializer)
{
_serializer = serializer;
}
diff --git a/src/core/Elsa.Abstractions/Elsa.Abstractions.csproj b/src/core/Elsa.Abstractions/Elsa.Abstractions.csproj
index b5f5d9ac7..3fd2078ab 100644
--- a/src/core/Elsa.Abstractions/Elsa.Abstractions.csproj
+++ b/src/core/Elsa.Abstractions/Elsa.Abstractions.csproj
@@ -32,7 +32,7 @@
-
+
diff --git a/src/core/Elsa.Abstractions/Extensions/VariablesExtensions.cs b/src/core/Elsa.Abstractions/Extensions/VariablesExtensions.cs
index 7fb412348..dbf4b80f5 100644
--- a/src/core/Elsa.Abstractions/Extensions/VariablesExtensions.cs
+++ b/src/core/Elsa.Abstractions/Extensions/VariablesExtensions.cs
@@ -5,7 +5,7 @@ namespace Elsa
{
public static class VariablesExtensions
{
- public static T Get(this Variables variables, string name, IJsonSerializer serializer)
+ public static T Get(this Variables variables, string name, IContentSerializer serializer)
{
var value = variables.Get(name);
return value != null ? serializer.Deserialize(value) : default!;
diff --git a/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs b/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs
index e05c26d88..fad658632 100644
--- a/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs
+++ b/src/core/Elsa.Abstractions/Models/ActivityDefinitionPropertyValue.cs
@@ -4,6 +4,21 @@ namespace Elsa.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!;
diff --git a/src/core/Elsa.Abstractions/Serialization/IJsonSerializer.cs b/src/core/Elsa.Abstractions/Serialization/IContentSerializer.cs
similarity index 82%
rename from src/core/Elsa.Abstractions/Serialization/IJsonSerializer.cs
rename to src/core/Elsa.Abstractions/Serialization/IContentSerializer.cs
index 0f30a168b..851168e75 100644
--- a/src/core/Elsa.Abstractions/Serialization/IJsonSerializer.cs
+++ b/src/core/Elsa.Abstractions/Serialization/IContentSerializer.cs
@@ -2,7 +2,7 @@
namespace Elsa.Serialization
{
- public interface IJsonSerializer
+ public interface IContentSerializer
{
JObject Serialize(T value);
T Deserialize(JToken token);
diff --git a/src/core/Elsa.Abstractions/Services/IWorkflowHost.cs b/src/core/Elsa.Abstractions/Services/IWorkflowHost.cs
index cd8245aa2..7fbcf1d64 100644
--- a/src/core/Elsa.Abstractions/Services/IWorkflowHost.cs
+++ b/src/core/Elsa.Abstractions/Services/IWorkflowHost.cs
@@ -13,7 +13,7 @@ namespace Elsa.Services
string? activityId = default,
object? input = default,
CancellationToken cancellationToken = default);
-
+
ValueTask RunWorkflowAsync(
IWorkflowBlueprint workflowDefinition,
WorkflowInstance workflowInstance,
@@ -27,17 +27,32 @@ namespace Elsa.Services
object? input = default,
string? correlationId = default,
CancellationToken cancellationToken = default);
-
+
ValueTask RunWorkflowAsync(
string? activityId = default,
object? input = default,
string? correlationId = default,
- CancellationToken cancellationToken = default) where T:IWorkflow;
-
+ CancellationToken cancellationToken = default) where T : IWorkflow;
+
ValueTask RunWorkflowAsync(
WorkflowInstance workflowInstance,
string? activityId = default,
object? input = default,
- CancellationToken cancellationToken = default) where T:IWorkflow;
+ CancellationToken cancellationToken = default) where T : IWorkflow;
+
+ ValueTask RunWorkflowAsync(
+ IWorkflow workflow,
+ string? activityId = default,
+ object? input = default,
+ string? correlationId = default,
+ CancellationToken cancellationToken = default);
+
+ ValueTask RunWorkflowAsync(
+ IWorkflow workflow,
+ WorkflowInstance workflowInstance,
+ string? activityId = default,
+ object? input = default,
+ string? correlationId = default,
+ CancellationToken cancellationToken = default);
}
}
\ No newline at end of file
diff --git a/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs b/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs
index 57d9215c0..2be947aca 100644
--- a/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs
+++ b/src/core/Elsa.Abstractions/Services/Models/WorkflowExecutionContext.cs
@@ -18,7 +18,6 @@ namespace Elsa.Services.Models
ServiceProvider = serviceProvider;
WorkflowBlueprint = workflowBlueprint;
WorkflowInstance = workflowInstance;
- ExecutionLog = new List(workflowInstance.ExecutionLog);
IsFirstPass = true;
}
@@ -47,7 +46,7 @@ namespace Elsa.Services.Models
public ScheduledActivity PeekScheduledActivity() => WorkflowInstance.ScheduledActivities.Peek();
public string? CorrelationId { get; set; }
public bool DeleteCompletedInstances { get; set; }
- public ICollection ExecutionLog { get; }
+ public ICollection ExecutionLog => WorkflowInstance.ExecutionLog;
public WorkflowStatus Status => WorkflowInstance.Status;
public void SetVariable(string name, object? value) => WorkflowInstance.Variables.Set(name, JToken.FromObject(value!));
diff --git a/src/core/Elsa.Core/Builders/WorkflowBuilder.cs b/src/core/Elsa.Core/Builders/WorkflowBuilder.cs
index 87ea6c1ca..182512049 100644
--- a/src/core/Elsa.Core/Builders/WorkflowBuilder.cs
+++ b/src/core/Elsa.Core/Builders/WorkflowBuilder.cs
@@ -93,11 +93,9 @@ namespace Elsa.Builders
public IActivityBuilder New(
Type activityType,
- Action? branch = default,
IDictionary? propertyValueProviders = default)
{
var activityBuilder = new ActivityBuilder(activityType, this, propertyValueProviders);
- branch?.Invoke(activityBuilder);
return activityBuilder;
}
@@ -105,7 +103,7 @@ namespace Elsa.Builders
Action? branch = default,
IDictionary? propertyValueProviders = default)
where T : class, IActivity =>
- New(typeof(T), branch, propertyValueProviders);
+ New(typeof(T), propertyValueProviders);
public IActivityBuilder New(
Action>? setup = default,
diff --git a/src/core/Elsa.Core/Messaging/Distributed/Handlers/RunWorkflowHandler.cs b/src/core/Elsa.Core/Consumers/RunWorkflowConsumer.cs
similarity index 80%
rename from src/core/Elsa.Core/Messaging/Distributed/Handlers/RunWorkflowHandler.cs
rename to src/core/Elsa.Core/Consumers/RunWorkflowConsumer.cs
index 6c62e0b00..309c4cf61 100644
--- a/src/core/Elsa.Core/Messaging/Distributed/Handlers/RunWorkflowHandler.cs
+++ b/src/core/Elsa.Core/Consumers/RunWorkflowConsumer.cs
@@ -5,14 +5,14 @@ using Elsa.Queries;
using Elsa.Services;
using Rebus.Handlers;
-namespace Elsa.Messaging.Distributed.Handlers
+namespace Elsa.Consumers
{
- public class RunWorkflowHandler : IHandleMessages
+ public class RunWorkflowConsumer : IHandleMessages
{
private readonly IWorkflowHost _workflowHost;
private readonly IWorkflowInstanceManager _workflowInstanceManager;
- public RunWorkflowHandler(IWorkflowHost workflowHost, IWorkflowInstanceManager workflowInstanceManager)
+ public RunWorkflowConsumer(IWorkflowHost workflowHost, IWorkflowInstanceManager workflowInstanceManager)
{
_workflowHost = workflowHost;
_workflowInstanceManager = workflowInstanceManager;
diff --git a/src/core/Elsa.Core/Elsa.Core.csproj b/src/core/Elsa.Core/Elsa.Core.csproj
index ad94b2aa5..fd98a0a81 100644
--- a/src/core/Elsa.Core/Elsa.Core.csproj
+++ b/src/core/Elsa.Core/Elsa.Core.csproj
@@ -46,7 +46,7 @@
-
+
@@ -69,7 +69,6 @@
-
\ No newline at end of file
diff --git a/src/core/Elsa.Core/ElsaOptions.cs b/src/core/Elsa.Core/ElsaOptions.cs
index 33dfa4319..7549faef2 100644
--- a/src/core/Elsa.Core/ElsaOptions.cs
+++ b/src/core/Elsa.Core/ElsaOptions.cs
@@ -29,7 +29,7 @@ namespace Elsa
CreateJsonSerializer = sp =>
{
- var serializer = DefaultJsonSerializer.CreateDefaultJsonSerializer();
+ var serializer = ContentSerializer.CreateDefaultJsonSerializer();
JsonSerializerConfigurer(sp, serializer);
return serializer;
};
diff --git a/src/core/Elsa.Core/Extensions/ActivityCollectionExtensions.cs b/src/core/Elsa.Core/Extensions/ActivityCollectionExtensions.cs
deleted file mode 100644
index f3028b28b..000000000
--- a/src/core/Elsa.Core/Extensions/ActivityCollectionExtensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Elsa.Services;
-
-namespace Elsa.Extensions
-{
- public static class ActivityCollectionExtensions
- {
- public static IEnumerable Find(this IEnumerable collection, IEnumerable ids)
- {
- var idList = ids?.ToList();
- return idList != null ? collection.Where(x => idList.Contains(x.Id)) : default;
- }
- }
-}
\ No newline at end of file
diff --git a/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs b/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs
index bac7236a4..2c869f5c7 100644
--- a/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs
+++ b/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs
@@ -1,22 +1,26 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Elsa;
using Elsa.Activities.ControlFlow;
using Elsa.Activities.Primitives;
using Elsa.Activities.Signaling;
using Elsa.Builders;
+using Elsa.Consumers;
using Elsa.Converters;
using Elsa.Data;
using Elsa.Data.Extensions;
+using Elsa.Events;
using Elsa.Expressions;
+using Elsa.Extensions;
+using Elsa.Handlers;
using Elsa.Indexes;
using Elsa.Messages;
-using Elsa.Messaging;
-using Elsa.Messaging.Distributed.Handlers;
using Elsa.Metadata;
using Elsa.Metadata.Handlers;
using Elsa.Runtime;
using Elsa.Serialization;
+using Elsa.ServiceBus;
using Elsa.Services;
using Elsa.StartupTasks;
using Elsa.Triggers;
@@ -67,13 +71,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
public static IServiceCollection AddConsumer(this IServiceCollection services) where TConsumer : class, IHandleMessages => services.AddTransient, TConsumer>();
-
- private static IServiceCollection AddMediatR(this ElsaOptions options)
- {
- return options.Services.AddMediatR(
- mediatr => mediatr.AsScoped(),
- typeof(ElsaServiceCollectionExtensions));
- }
+ private static IServiceCollection AddMediatR(this ElsaOptions options) => options.Services.AddMediatR(mediatr => mediatr.AsScoped(), typeof(IActivity));
private static ElsaOptions AddWorkflowsCore(this ElsaOptions configuration)
{
@@ -87,7 +85,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddTransient>>(sp => sp.GetServices)
.AddSingleton()
.AddSingleton(sp => sp.GetRequiredService().CreateJsonSerializer(sp))
- .AddSingleton()
+ .AddSingleton()
.AddSingleton()
.AddSingleton()
.TryAddProvider(ServiceLifetime.Singleton)
@@ -99,7 +97,7 @@ namespace Microsoft.Extensions.DependencyInjection
.AddScoped()
.AddSingleton()
.AddSingleton()
- .AddSingleton()
+ .AddScoped()
.AddScoped()
.AddScoped()
.AddIndexProvider()
@@ -109,8 +107,9 @@ namespace Microsoft.Extensions.DependencyInjection
.AddWorkflowProvider()
.AddTransient()
.AddTransient>(sp => sp.GetRequiredService)
+ .AddNotificationHandlers(typeof(ElsaServiceCollectionExtensions))
.AddStartupTask()
- .AddConsumer()
+ .AddConsumer()
.AddMetadataHandlers()
.AddPrimitiveActivities();
diff --git a/src/core/Elsa.Core/Messaging/Domain/Handlers/WorkflowExecutionLogEventHandler.cs b/src/core/Elsa.Core/Handlers/AppendExecutionLog.cs
similarity index 69%
rename from src/core/Elsa.Core/Messaging/Domain/Handlers/WorkflowExecutionLogEventHandler.cs
rename to src/core/Elsa.Core/Handlers/AppendExecutionLog.cs
index 4b338900b..dd4e31417 100644
--- a/src/core/Elsa.Core/Messaging/Domain/Handlers/WorkflowExecutionLogEventHandler.cs
+++ b/src/core/Elsa.Core/Handlers/AppendExecutionLog.cs
@@ -5,12 +5,12 @@ using Elsa.Models;
using MediatR;
using NodaTime;
-namespace Elsa.Messaging.Domain.Handlers
+namespace Elsa.Handlers
{
- public class WorkflowExecutionLogEventHandler : INotificationHandler
+ public class AppendExecutionLog : INotificationHandler
{
private readonly IClock _clock;
- public WorkflowExecutionLogEventHandler(IClock clock) => _clock = clock;
+ public AppendExecutionLog(IClock clock) => _clock = clock;
public Task Handle(ActivityExecuted notification, CancellationToken cancellationToken)
{
diff --git a/src/core/Elsa.Core/Messaging/Domain/Handlers/PersistenceWorkflowEventHandler.cs b/src/core/Elsa.Core/Handlers/PersistWorkflow.cs
similarity index 93%
rename from src/core/Elsa.Core/Messaging/Domain/Handlers/PersistenceWorkflowEventHandler.cs
rename to src/core/Elsa.Core/Handlers/PersistWorkflow.cs
index 718b3230a..969234281 100644
--- a/src/core/Elsa.Core/Messaging/Domain/Handlers/PersistenceWorkflowEventHandler.cs
+++ b/src/core/Elsa.Core/Handlers/PersistWorkflow.cs
@@ -7,9 +7,9 @@ using Elsa.Services.Models;
using MediatR;
using Microsoft.Extensions.Logging;
-namespace Elsa.Messaging.Domain.Handlers
+namespace Elsa.Handlers
{
- public class PersistenceWorkflowEventHandler :
+ public class PersistWorkflow :
INotificationHandler,
INotificationHandler,
INotificationHandler,
@@ -18,9 +18,9 @@ namespace Elsa.Messaging.Domain.Handlers
private readonly IWorkflowInstanceManager _workflowInstanceManager;
private readonly ILogger _logger;
- public PersistenceWorkflowEventHandler(
+ public PersistWorkflow(
IWorkflowInstanceManager workflowInstanceManager,
- ILogger logger)
+ ILogger logger)
{
_workflowInstanceManager = workflowInstanceManager;
_logger = logger;
diff --git a/src/core/Elsa.Core/Serialization/ActivitySerializer.cs b/src/core/Elsa.Core/Serialization/ActivitySerializer.cs
index 1363c2098..ff6df1c00 100644
--- a/src/core/Elsa.Core/Serialization/ActivitySerializer.cs
+++ b/src/core/Elsa.Core/Serialization/ActivitySerializer.cs
@@ -5,8 +5,8 @@ namespace Elsa.Serialization
{
public class ActivitySerializer : IActivitySerializer
{
- private readonly IJsonSerializer _ijSerializer;
- public ActivitySerializer(IJsonSerializer ijSerializer) => _ijSerializer = ijSerializer;
+ private readonly IContentSerializer _ijSerializer;
+ public ActivitySerializer(IContentSerializer ijSerializer) => _ijSerializer = ijSerializer;
public JObject Serialize(T activity) where T : IActivity => _ijSerializer.Serialize(activity);
public T Deserialize(JObject data) where T : IActivity => _ijSerializer.Deserialize(data);
}
diff --git a/src/core/Elsa.Core/Serialization/DefaultJsonSerializer.cs b/src/core/Elsa.Core/Serialization/ContentSerializer.cs
similarity index 87%
rename from src/core/Elsa.Core/Serialization/DefaultJsonSerializer.cs
rename to src/core/Elsa.Core/Serialization/ContentSerializer.cs
index 16cdc1e8d..104c895d9 100644
--- a/src/core/Elsa.Core/Serialization/DefaultJsonSerializer.cs
+++ b/src/core/Elsa.Core/Serialization/ContentSerializer.cs
@@ -7,9 +7,9 @@ using NodaTime.Serialization.JsonNet;
namespace Elsa.Serialization
{
- public class DefaultJsonSerializer : IJsonSerializer
+ public class ContentSerializer : IContentSerializer
{
- public DefaultJsonSerializer(JsonSerializer serializer)
+ public ContentSerializer(JsonSerializer serializer)
{
Serializer = serializer;
}
@@ -30,9 +30,9 @@ namespace Elsa.Serialization
jsonSerializer.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
jsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
- jsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
+ jsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.All;
jsonSerializer.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;
- jsonSerializer.TypeNameHandling = TypeNameHandling.Objects;
+ jsonSerializer.TypeNameHandling = TypeNameHandling.None;
jsonSerializer.ContractResolver = new CamelCasePropertyNamesContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
diff --git a/src/core/Elsa.Core/Messaging/ServiceCollectionExtensions.cs b/src/core/Elsa.Core/ServiceBus/ServiceCollectionExtensions.cs
similarity index 95%
rename from src/core/Elsa.Core/Messaging/ServiceCollectionExtensions.cs
rename to src/core/Elsa.Core/ServiceBus/ServiceCollectionExtensions.cs
index 620105871..3e7b3badc 100644
--- a/src/core/Elsa.Core/Messaging/ServiceCollectionExtensions.cs
+++ b/src/core/Elsa.Core/ServiceBus/ServiceCollectionExtensions.cs
@@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Rebus.Config;
using Rebus.ServiceProvider;
-namespace Elsa.Messaging
+namespace Elsa.ServiceBus
{
public static class ServiceCollectionExtensions
{
diff --git a/src/core/Elsa.Core/Services/WorkflowHost.cs b/src/core/Elsa.Core/Services/WorkflowHost.cs
index 5c8fcef77..5727d6450 100644
--- a/src/core/Elsa.Core/Services/WorkflowHost.cs
+++ b/src/core/Elsa.Core/Services/WorkflowHost.cs
@@ -27,7 +27,6 @@ namespace Elsa.Services
private readonly IWorkflowBuilder _workflowBuilder;
private readonly IMediator _mediator;
private readonly IServiceProvider _serviceProvider;
- private readonly IEnumerable _triggerProviders;
private readonly ILogger _logger;
public WorkflowHost(
@@ -36,7 +35,6 @@ namespace Elsa.Services
IWorkflowBuilder workflowBuilder,
IMediator mediator,
IServiceProvider serviceProvider,
- IEnumerable triggerProviders,
ILogger logger)
{
_workflowRegistry = workflowRegistry;
@@ -44,7 +42,6 @@ namespace Elsa.Services
_workflowBuilder = workflowBuilder;
_mediator = mediator;
_serviceProvider = serviceProvider;
- _triggerProviders = triggerProviders;
_logger = logger;
}
@@ -79,6 +76,29 @@ namespace Elsa.Services
where T : IWorkflow =>
await RunWorkflowAsync(_workflowBuilder.Build(), workflowInstance, activityId, input, cancellationToken);
+ public async ValueTask RunWorkflowAsync(
+ IWorkflow workflow,
+ string? activityId = default,
+ object? input = default,
+ string? correlationId = default,
+ CancellationToken cancellationToken = default)
+ {
+ var workflowBlueprint = _workflowBuilder.Build(workflow);
+ return await RunWorkflowAsync(workflowBlueprint, activityId, input, correlationId, cancellationToken);
+ }
+
+ public async ValueTask RunWorkflowAsync(
+ IWorkflow workflow,
+ WorkflowInstance workflowInstance,
+ string? activityId = default,
+ object? input = default,
+ string? correlationId = default,
+ CancellationToken cancellationToken = default)
+ {
+ var workflowBlueprint = _workflowBuilder.Build(workflow);
+ return await RunWorkflowAsync(workflowBlueprint, workflowInstance, activityId, input, cancellationToken);
+ }
+
public async ValueTask RunWorkflowAsync(
WorkflowInstance workflowInstance,
string? activityId = default,
diff --git a/src/samples/Elsa.Samples.CustomActivities/Properties/launchSettings.json b/src/samples/Elsa.Samples.CustomActivities/Properties/launchSettings.json
new file mode 100644
index 000000000..86fb7527a
--- /dev/null
+++ b/src/samples/Elsa.Samples.CustomActivities/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:62840/",
+ "sslPort": 44305
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Elsa.Samples.CustomActivities": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:5001;http://localhost:5000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/samples/Elsa.Samples.HelloWorldHttp/Properties/launchSettings.json b/src/samples/Elsa.Samples.HelloWorldHttp/Properties/launchSettings.json
new file mode 100644
index 000000000..e85d33520
--- /dev/null
+++ b/src/samples/Elsa.Samples.HelloWorldHttp/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:62841/",
+ "sslPort": 44336
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Elsa.Samples.HelloWorldHttp": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:5001;http://localhost:5000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/samples/Elsa.Samples.Serialization/Program.cs b/src/samples/Elsa.Samples.Serialization/Program.cs
index 66dc0a6c8..e932a2914 100644
--- a/src/samples/Elsa.Samples.Serialization/Program.cs
+++ b/src/samples/Elsa.Samples.Serialization/Program.cs
@@ -60,7 +60,7 @@ namespace Elsa.Samples.Serialization
};
// Serialize workflow definition to JSON.
- var serializer = services.GetRequiredService();
+ var serializer = services.GetRequiredService();
var json = serializer.Serialize(workflowDefinition);
Console.WriteLine(json);
diff --git a/src/samples/Elsa.Samples.Timers/Elsa.Samples.Timers.csproj b/src/samples/Elsa.Samples.Timers/Elsa.Samples.Timers.csproj
index b34c1de28..f09b26764 100644
--- a/src/samples/Elsa.Samples.Timers/Elsa.Samples.Timers.csproj
+++ b/src/samples/Elsa.Samples.Timers/Elsa.Samples.Timers.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj b/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj
new file mode 100644
index 000000000..59ba1be57
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Elsa.Server.Api.csproj
@@ -0,0 +1,29 @@
+
+
+
+ netcoreapp3.1
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Post.cs
+
+
+
diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs
new file mode 100644
index 000000000..208c36de9
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Get.cs
@@ -0,0 +1,25 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Elsa.Models;
+using Elsa.Queries;
+using Elsa.Services;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
+{
+ [ApiController]
+ [ApiVersion("1")]
+ [Route("v{version:apiVersion}/workflow-definitions/{id}")]
+ public class Get : ControllerBase
+ {
+ private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
+ public Get(IWorkflowDefinitionManager workflowDefinitionManager) => _workflowDefinitionManager = workflowDefinitionManager;
+
+ [HttpGet]
+ public async Task Handle([FromRoute(Name = "id")] string workflowDefinitionId, CancellationToken cancellationToken)
+ {
+ var workflowDefinition = await _workflowDefinitionManager.GetAsync(workflowDefinitionId, VersionOptions.Latest, cancellationToken);
+ return workflowDefinition == null ? (IActionResult)NotFound() : Ok(workflowDefinition);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.Request.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.Request.cs
new file mode 100644
index 000000000..3984c541d
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.Request.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using Elsa.Models;
+
+namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
+{
+ public class CreateWorkflowDefinitionRequest
+ {
+ public string WorkflowDefinitionId { get; set; } = default!;
+ public string? Name { get; set; }
+ public string? Description { get; set; }
+ public Variables? Variables { get; set; }
+ public bool IsSingleton { get; set; }
+ public WorkflowPersistenceBehavior PersistenceBehavior { get; set; }
+ public bool DeleteCompletedInstances { get; set; }
+ public bool Enabled { get; set; }
+ public bool Publish { get; set; }
+ public ICollection Activities { get; set; } = new List();
+ public ICollection Connections { get; set; } = new List();
+ }
+}
\ 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
new file mode 100644
index 000000000..b6c40a2a6
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Post.cs
@@ -0,0 +1,45 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Elsa.Models;
+using Elsa.Services;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
+{
+ [ApiController]
+ [ApiVersion("1")]
+ [Route("v{version:apiVersion}/workflow-definitions")]
+ public class Post : ControllerBase
+ {
+ private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
+
+ public Post(IWorkflowDefinitionManager workflowDefinitionManager)
+ {
+ _workflowDefinitionManager = workflowDefinitionManager;
+ }
+
+ [HttpPost]
+ public async Task Handle(CreateWorkflowDefinitionRequest request, ApiVersion apiVersion, CancellationToken cancellationToken)
+ {
+ var workflowDefinition = new WorkflowDefinition
+ {
+ WorkflowDefinitionId = request.WorkflowDefinitionId.Trim(),
+ Activities = request.Activities,
+ Connections = request.Connections,
+ Description = request.Description?.Trim(),
+ Name = request.Name?.Trim(),
+ Variables = request.Variables,
+ IsEnabled = request.Enabled,
+ IsLatest = true,
+ IsPublished = request.Publish,
+ Version = 1,
+ IsSingleton = request.IsSingleton,
+ PersistenceBehavior = request.PersistenceBehavior,
+ DeleteCompletedInstances = request.DeleteCompletedInstances
+ };
+
+ await _workflowDefinitionManager.SaveAsync(workflowDefinition, cancellationToken);
+ return CreatedAtAction("Handle", "Get", new { version = apiVersion.ToString() }, workflowDefinition);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Api/Extensions/JsonMvcBuilderExtensions.cs b/src/server/Elsa.Server.Api/Extensions/JsonMvcBuilderExtensions.cs
new file mode 100644
index 000000000..f99b465f6
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Extensions/JsonMvcBuilderExtensions.cs
@@ -0,0 +1,18 @@
+using System.Text.Json;
+using Microsoft.Extensions.DependencyInjection;
+using NodaTime;
+using NodaTime.Serialization.SystemTextJson;
+
+namespace Elsa.Server.Api.Extensions
+{
+ public static class JsonMvcBuilderExtensions
+ {
+ public static IMvcBuilder AddJsonSerialization(this IMvcBuilder builder) =>
+ builder.AddJsonOptions(
+ options =>
+ {
+ options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ options.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.Api/Extensions/ServiceCollectionExtensions.cs b/src/server/Elsa.Server.Api/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..4b8639c1a
--- /dev/null
+++ b/src/server/Elsa.Server.Api/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,25 @@
+using Elsa.Server.Api.Extensions;
+using Microsoft.AspNetCore.Mvc;
+
+// ReSharper disable once CheckNamespace
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public static class ServiceCollectionExtensions
+ {
+ public static IServiceCollection AddElsaApiEndpoints(this IServiceCollection services)
+ {
+ services.AddControllers().SetCompatibilityVersion(CompatibilityVersion.Latest).AddJsonSerialization();
+ services.AddRouting(options => options.LowercaseUrls = true);
+
+ services.AddApiVersioning(
+ options =>
+ {
+ options.ReportApiVersions = true;
+ options.DefaultApiVersion = ApiVersion.Default;
+ options.AssumeDefaultVersionWhenUnspecified = true;
+ });
+
+ return services;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/server/Elsa.Server.GraphQL/Extensions/ServiceCollectionExtensions.cs b/src/server/Elsa.Server.GraphQL/Extensions/ServiceCollectionExtensions.cs
index 918024986..f841aee7b 100644
--- a/src/server/Elsa.Server.GraphQL/Extensions/ServiceCollectionExtensions.cs
+++ b/src/server/Elsa.Server.GraphQL/Extensions/ServiceCollectionExtensions.cs
@@ -6,7 +6,8 @@ using Elsa.Services;
using HotChocolate;
using Microsoft.Extensions.DependencyInjection;
-namespace Elsa.Server.GraphQL.Extensions
+// ReSharper disable once CheckNamespace
+namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{
diff --git a/src/server/Elsa.Server.GraphQL/Mutation.cs b/src/server/Elsa.Server.GraphQL/Mutation.cs
index ed2be0d71..f028ea004 100644
--- a/src/server/Elsa.Server.GraphQL/Mutation.cs
+++ b/src/server/Elsa.Server.GraphQL/Mutation.cs
@@ -29,7 +29,7 @@ namespace Elsa.Server.GraphQL
WorkflowInput workflowInput,
[Service] IWorkflowDefinitionManager manager,
[Service] IIdGenerator idGenerator,
- [Service] IJsonSerializer serializer,
+ [Service] IContentSerializer serializer,
[Service] IWorkflowPublisher publisher,
CancellationToken cancellationToken)
{
diff --git a/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj b/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj
index d117e9cd8..f53bd35ae 100644
--- a/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj
+++ b/src/server/Elsa.Server.Host/Elsa.Server.Host.csproj
@@ -5,14 +5,11 @@
+
-
-
-
-
diff --git a/src/server/Elsa.Server.Host/Startup.cs b/src/server/Elsa.Server.Host/Startup.cs
index e9bdbce2d..0ccf5e0d6 100644
--- a/src/server/Elsa.Server.Host/Startup.cs
+++ b/src/server/Elsa.Server.Host/Startup.cs
@@ -1,8 +1,5 @@
using Elsa.Runtime;
-using Elsa.Server.GraphQL.Extensions;
using Elsa.StartupTasks;
-using HotChocolate.AspNetCore;
-using HotChocolate.AspNetCore.Voyager;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
@@ -34,7 +31,7 @@ namespace Elsa.Server.Host
services
.AddElsaServer()
- .AddElsaGraphQL()
+ .AddElsaApiEndpoints()
.AddCors(options => options.AddDefaultPolicy(cors => cors
.AllowAnyOrigin()
@@ -57,9 +54,6 @@ namespace Elsa.Server.Host
app
.UseCors()
- .UseGraphQL("/graphql")
- .UsePlayground("/graphql")
- .UseVoyager("/graphql")
.UseHttpActivities();
}
}
diff --git a/test/component/Elsa.ComponentTests/Assets/hello-world-workflow.json b/test/component/Elsa.ComponentTests/Assets/hello-world-workflow.json
new file mode 100644
index 000000000..59672ec5a
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Assets/hello-world-workflow.json
@@ -0,0 +1,37 @@
+{
+ "$id": "1",
+ "workflowDefinitionId": "SampleWorkflow",
+ "workflowDefinitionVersionId": "1",
+ "version": 1,
+ "variables": {
+ "$id": "2",
+ "data": {}
+ },
+ "isEnabled": true,
+ "isPublished": true,
+ "isLatest": true,
+ "activities": {
+ "$id": "3",
+ "$values": [
+ {
+ "$id": "4",
+ "id": "activity-1",
+ "type": "WriteLine",
+ "properties": {
+ "$id": "5",
+ "Text": {
+ "$id": "6",
+ "type": "System.String, mscorlib",
+ "syntax": "Liquid",
+ "expression": "Hello World!"
+ }
+ }
+ }
+ ]
+ },
+ "connections": {
+ "$id": "7",
+ "$values": []
+ }
+ }
+
\ No newline at end of file
diff --git a/test/component/Elsa.ComponentTests/Elsa.ComponentTests.csproj b/test/component/Elsa.ComponentTests/Elsa.ComponentTests.csproj
new file mode 100644
index 000000000..d94d17cf7
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Elsa.ComponentTests.csproj
@@ -0,0 +1,39 @@
+
+
+
+ netcoreapp3.1
+ false
+ enable
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/test/component/Elsa.ComponentTests/Endpoints/WorkflowDefinitions/PostTests.cs b/test/component/Elsa.ComponentTests/Endpoints/WorkflowDefinitions/PostTests.cs
new file mode 100644
index 000000000..d520c617e
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Endpoints/WorkflowDefinitions/PostTests.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using AutoFixture;
+using Elsa.Activities.Console;
+using Elsa.ComponentTests.Helpers;
+using Elsa.Core.IntegrationTests.Helpers;
+using Elsa.Models;
+using Elsa.Server.Api.Endpoints.WorkflowDefinitions;
+using Elsa.Testing.Shared.AutoFixture;
+using Xunit;
+
+namespace Elsa.ComponentTests.Endpoints.WorkflowDefinitions
+{
+ [Collection(ComponentTestsCollection.Name)]
+ public class PostTests : IDisposable
+ {
+ private readonly IFixture _fixture;
+ private readonly TemporaryFolder _tempFolder;
+ private readonly ElsaHostApplicationFactory _hostApplicationFactory;
+ private readonly HttpClient _httpClient;
+
+ public PostTests(ElsaHostApplicationFactory hostApplicationFactory)
+ {
+ _fixture = new Fixture().Customize(new NodaTimeCustomization());
+ _tempFolder = new TemporaryFolder();
+ _hostApplicationFactory = hostApplicationFactory;
+ hostApplicationFactory.SetDbConnectionString($@"Data Source={_tempFolder.Folder}elsa.db;Cache=Shared");
+ _httpClient = hostApplicationFactory.CreateClient();
+ }
+
+ [Fact(DisplayName = "Posting a new workflow definition returns HTTP 201.")]
+ public async Task Post01()
+ {
+ var request = CreateWorkflowDefinitionRequest();
+ var response = await _httpClient.PostJsonAsync("/v1/workflow-definitions", request);
+
+ Assert.Equal(HttpStatusCode.Created, response.StatusCode);
+ }
+
+ private CreateWorkflowDefinitionRequest CreateWorkflowDefinitionRequest()
+ {
+ var writeLine = new ActivityDefinition
+ {
+ Id = _fixture.Create(),
+ Type = nameof(WriteLine),
+ Properties = new ActivityDefinitionProperties
+ {
+ [nameof(WriteLine.Text)] = ActivityDefinitionPropertyValue.Literal("Hello World!")
+ }
+ };
+
+ var readLine = new ActivityDefinition { Id = _fixture.Create(), Type = nameof(ReadLine) };
+ var activities = new[] { writeLine, readLine };
+ var connections = new[] { new ConnectionDefinition(writeLine.Id, readLine.Id, OutcomeNames.Done) };
+
+ return _fixture.Build()
+ .With(x => x.Activities, activities)
+ .With(x => x.Connections, connections)
+ .Create();
+ }
+
+ private string CreateWorkflowDefinitionJson()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Dispose()
+ {
+ _hostApplicationFactory.Dispose();
+ _tempFolder.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/component/Elsa.ComponentTests/Helpers/AssetHelper.cs b/test/component/Elsa.ComponentTests/Helpers/AssetHelper.cs
new file mode 100644
index 000000000..0d42d8687
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/AssetHelper.cs
@@ -0,0 +1,13 @@
+using System.IO;
+using System.Threading.Tasks;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ public static class AssetHelper
+ {
+ private static readonly string AssetsDirectory;
+ static AssetHelper() => AssetsDirectory = Path.Combine(Path.GetDirectoryName(typeof(AssetHelper).Assembly.Location)!, "Assets");
+ public static string GetAssetPath(string filename) => Path.Combine(AssetsDirectory, filename);
+ public static Task ReadAsset(string filename) => File.ReadAllTextAsync(Path.Combine(AssetsDirectory, filename));
+ }
+}
\ No newline at end of file
diff --git a/test/component/Elsa.ComponentTests/Helpers/ComponentTestsCollection.cs b/test/component/Elsa.ComponentTests/Helpers/ComponentTestsCollection.cs
new file mode 100644
index 000000000..c09ea8693
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/ComponentTestsCollection.cs
@@ -0,0 +1,10 @@
+using Xunit;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ [CollectionDefinition(Name)]
+ public class ComponentTestsCollection : ICollectionFixture
+ {
+ public const string Name = "Component Tests";
+ }
+}
diff --git a/test/component/Elsa.ComponentTests/Helpers/ElsaHostApplicationFactory.cs b/test/component/Elsa.ComponentTests/Helpers/ElsaHostApplicationFactory.cs
new file mode 100644
index 000000000..ca12aaaf8
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/ElsaHostApplicationFactory.cs
@@ -0,0 +1,23 @@
+using Elsa.Server.Host;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Microsoft.Extensions.Configuration;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ public class ElsaHostApplicationFactory : WebApplicationFactory
+ {
+ private string _dbConnectionString;
+
+ public void SetDbConnectionString(string connectionString)
+ {
+ _dbConnectionString = connectionString;
+ }
+
+ protected override void ConfigureWebHost(IWebHostBuilder builder)
+ {
+ builder
+ .ConfigureAppConfiguration(config => config.AddInMemoryCollection(FakeConfiguration.Create(_dbConnectionString)));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/component/Elsa.ComponentTests/Helpers/FakeConfiguration.cs b/test/component/Elsa.ComponentTests/Helpers/FakeConfiguration.cs
new file mode 100644
index 000000000..0432ea7b8
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/FakeConfiguration.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ public static class FakeConfiguration
+ {
+ public static IEnumerable> Create(string dbConnectionString)
+ {
+ return new Dictionary
+ {
+ ["ConnectionStrings:Sqlite"] = dbConnectionString,
+ };
+ }
+ }
+}
diff --git a/test/component/Elsa.ComponentTests/Helpers/HttpClientExtensions.cs b/test/component/Elsa.ComponentTests/Helpers/HttpClientExtensions.cs
new file mode 100644
index 000000000..5137c401d
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/HttpClientExtensions.cs
@@ -0,0 +1,18 @@
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ public static class HttpClientExtensions
+ {
+ public static async Task GetJsonAsync(this HttpClient httpClient, string requestUri)
+ {
+ using var response = await httpClient.GetAsync(requestUri);
+ response.EnsureSuccessStatusCode();
+
+ return await response.Content.ReadJsonAsync();
+ }
+
+ public static async Task PostJsonAsync(this HttpClient httpClient, string requestUri, T value) => await httpClient.PostAsync(requestUri, new JsonContent(value!));
+ }
+}
\ No newline at end of file
diff --git a/test/component/Elsa.ComponentTests/Helpers/HttpContentExtensions.cs b/test/component/Elsa.ComponentTests/Helpers/HttpContentExtensions.cs
new file mode 100644
index 000000000..5524f1d71
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/HttpContentExtensions.cs
@@ -0,0 +1,15 @@
+using System.Net.Http;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ public static class HttpContentExtensions
+ {
+ public static async Task ReadJsonAsync(this HttpContent content)
+ {
+ var json = await content.ReadAsStringAsync();
+ return JsonConvert.DeserializeObject(json, JsonContent.SerializerSettings)!;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/component/Elsa.ComponentTests/Helpers/JsonContent.cs b/test/component/Elsa.ComponentTests/Helpers/JsonContent.cs
new file mode 100644
index 000000000..afabf756f
--- /dev/null
+++ b/test/component/Elsa.ComponentTests/Helpers/JsonContent.cs
@@ -0,0 +1,29 @@
+using System.Net.Http;
+using System.Text;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Serialization;
+using NodaTime;
+using NodaTime.Serialization.JsonNet;
+
+namespace Elsa.ComponentTests.Helpers
+{
+ public class JsonContent : StringContent
+ {
+ public static readonly JsonSerializerSettings SerializerSettings;
+
+ static JsonContent()
+ {
+ SerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
+ SerializerSettings.Converters.Add(new StringEnumConverter());
+ }
+
+ public JsonContent(string content) : base(content, Encoding.UTF8, "application/json")
+ {
+ }
+
+ public JsonContent(object content) : this(JsonConvert.SerializeObject(content, SerializerSettings))
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/integration/Elsa.Core.IntegrationTests/BasicWorkflowUnitTests.cs b/test/integration/Elsa.Core.IntegrationTests/BasicWorkflowUnitTests.cs
new file mode 100644
index 000000000..b88392c84
--- /dev/null
+++ b/test/integration/Elsa.Core.IntegrationTests/BasicWorkflowUnitTests.cs
@@ -0,0 +1,25 @@
+using System.Threading.Tasks;
+using Elsa.Core.IntegrationTests.Helpers;
+using Elsa.Core.IntegrationTests.Workflows;
+using Elsa.Models;
+using Elsa.Testing.Shared.Helpers;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Elsa.Core.IntegrationTests
+{
+ public class BasicWorkflowUnitTests : WorkflowsUnitTestBase
+ {
+ public BasicWorkflowUnitTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
+ {
+ }
+
+ [Fact(DisplayName = "Runs simple workflow.")]
+ public async Task Test01()
+ {
+ var workflowInstance = await WorkflowHost.RunWorkflowAsync();
+
+ Assert.Equal(WorkflowStatus.Completed, workflowInstance.Status);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/unit/Elsa.Core.UnitTests/Elsa.Core.UnitTests.csproj b/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj
similarity index 91%
rename from test/unit/Elsa.Core.UnitTests/Elsa.Core.UnitTests.csproj
rename to test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj
index 01220f479..87bea58a8 100644
--- a/test/unit/Elsa.Core.UnitTests/Elsa.Core.UnitTests.csproj
+++ b/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.csproj
@@ -2,9 +2,7 @@
netcoreapp3.1
-
false
-
enable
@@ -33,8 +31,12 @@
-
+
+
+
+
+
diff --git a/test/unit/Elsa.Core.UnitTests/Elsa.Core.UnitTests.xunit.runner.json b/test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.xunit.runner.json
similarity index 100%
rename from test/unit/Elsa.Core.UnitTests/Elsa.Core.UnitTests.xunit.runner.json
rename to test/integration/Elsa.Core.IntegrationTests/Elsa.Core.IntegrationTests.xunit.runner.json
diff --git a/test/integration/Elsa.Core.IntegrationTests/ForLoopWorkflowUnitTests.cs b/test/integration/Elsa.Core.IntegrationTests/ForLoopWorkflowUnitTests.cs
new file mode 100644
index 000000000..186bf40e8
--- /dev/null
+++ b/test/integration/Elsa.Core.IntegrationTests/ForLoopWorkflowUnitTests.cs
@@ -0,0 +1,28 @@
+using System.Linq;
+using System.Threading.Tasks;
+using Elsa.Core.IntegrationTests.Helpers;
+using Elsa.Core.IntegrationTests.Workflows;
+using Elsa.Testing.Shared.Helpers;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Elsa.Core.IntegrationTests
+{
+ public class ForLoopWorkflowUnitTests : WorkflowsUnitTestBase
+ {
+ public ForLoopWorkflowUnitTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper)
+ {
+ }
+
+ [Fact(DisplayName = "Runs For loop workflow.")]
+ public async Task Test01()
+ {
+ const int loopCount = 10;
+ var workflow = new ForLoopWorkflow(loopCount);
+ var workflowInstance = await WorkflowHost.RunWorkflowAsync(workflow);
+ var iterationLogs = workflowInstance.ExecutionLog.Where(x => x.ActivityId == "WriteLine").ToList();
+
+ Assert.Equal(loopCount, iterationLogs.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/integration/Elsa.Core.IntegrationTests/Workflows/BasicWorkflow.cs b/test/integration/Elsa.Core.IntegrationTests/Workflows/BasicWorkflow.cs
new file mode 100644
index 000000000..ad10171ea
--- /dev/null
+++ b/test/integration/Elsa.Core.IntegrationTests/Workflows/BasicWorkflow.cs
@@ -0,0 +1,13 @@
+using Elsa.Activities.Console;
+using Elsa.Builders;
+
+namespace Elsa.Core.IntegrationTests.Workflows
+{
+ public class BasicWorkflow : IWorkflow
+ {
+ public void Build(IWorkflowBuilder builder)
+ {
+ builder.WriteLine("Hello xUnit!");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/integration/Elsa.Core.IntegrationTests/Workflows/ForLoopWorkflow.cs b/test/integration/Elsa.Core.IntegrationTests/Workflows/ForLoopWorkflow.cs
new file mode 100644
index 000000000..a7157843e
--- /dev/null
+++ b/test/integration/Elsa.Core.IntegrationTests/Workflows/ForLoopWorkflow.cs
@@ -0,0 +1,26 @@
+using Elsa.Activities.Console;
+using Elsa.Activities.ControlFlow;
+using Elsa.Builders;
+
+namespace Elsa.Core.IntegrationTests.Workflows
+{
+ public class ForLoopWorkflow : IWorkflow
+ {
+ private readonly int _loopCount;
+
+ public ForLoopWorkflow(int loopCount)
+ {
+ _loopCount = loopCount;
+ }
+
+ public void Build(IWorkflowBuilder builder)
+ {
+ builder.For(
+ 0,
+ _loopCount,
+ iterate => iterate
+ .Then(activity => activity.Set(x => x.Text, context => $"Iteration {context.Input}"))
+ .WithId("WriteLine"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/shared/Elsa.Testing.Shared/Autofixture/Abstractions/SpecimenBuilderBase.cs b/test/shared/Elsa.Testing.Shared/AutoFixture/Abstractions/SpecimenBuilderBase.cs
similarity index 90%
rename from test/shared/Elsa.Testing.Shared/Autofixture/Abstractions/SpecimenBuilderBase.cs
rename to test/shared/Elsa.Testing.Shared/AutoFixture/Abstractions/SpecimenBuilderBase.cs
index c74526c0a..41ad09993 100644
--- a/test/shared/Elsa.Testing.Shared/Autofixture/Abstractions/SpecimenBuilderBase.cs
+++ b/test/shared/Elsa.Testing.Shared/AutoFixture/Abstractions/SpecimenBuilderBase.cs
@@ -1,7 +1,7 @@
using System;
using AutoFixture.Kernel;
-namespace Elsa.Testing.Shared.Autofixture.Abstractions
+namespace Elsa.Testing.Shared.AutoFixture.Abstractions
{
public abstract class SpecimenBuilderBase : ISpecimenBuilder
{
diff --git a/test/shared/Elsa.Testing.Shared/Autofixture/NodaTimeCustomization.cs b/test/shared/Elsa.Testing.Shared/AutoFixture/NodaTimeCustomization.cs
similarity index 80%
rename from test/shared/Elsa.Testing.Shared/Autofixture/NodaTimeCustomization.cs
rename to test/shared/Elsa.Testing.Shared/AutoFixture/NodaTimeCustomization.cs
index 753120a0c..c169a3973 100644
--- a/test/shared/Elsa.Testing.Shared/Autofixture/NodaTimeCustomization.cs
+++ b/test/shared/Elsa.Testing.Shared/AutoFixture/NodaTimeCustomization.cs
@@ -1,7 +1,7 @@
using AutoFixture;
-using Elsa.Testing.Shared.Autofixture.SpecimenBuilders;
+using Elsa.Testing.Shared.AutoFixture.SpecimenBuilders;
-namespace Elsa.Testing.Shared.Autofixture
+namespace Elsa.Testing.Shared.AutoFixture
{
public class NodaTimeCustomization : ICustomization
{
diff --git a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/DurationGenerator.cs b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/DurationGenerator.cs
similarity index 73%
rename from test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/DurationGenerator.cs
rename to test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/DurationGenerator.cs
index 5e237f340..d1be8f820 100644
--- a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/DurationGenerator.cs
+++ b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/DurationGenerator.cs
@@ -1,10 +1,10 @@
using System;
using AutoFixture;
using AutoFixture.Kernel;
-using Elsa.Testing.Shared.Autofixture.Abstractions;
+using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
-namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
+namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class DurationGenerator : SpecimenBuilderBase
{
diff --git a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/InstantGenerator.cs b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/InstantGenerator.cs
similarity index 78%
rename from test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/InstantGenerator.cs
rename to test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/InstantGenerator.cs
index dc9db61ee..d2b77ecad 100644
--- a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/InstantGenerator.cs
+++ b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/InstantGenerator.cs
@@ -1,10 +1,10 @@
using System;
using AutoFixture;
using AutoFixture.Kernel;
-using Elsa.Testing.Shared.Autofixture.Abstractions;
+using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
-namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
+namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class InstantGenerator : SpecimenBuilderBase
{
diff --git a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/LocalDateGenerator.cs b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/LocalDateGenerator.cs
similarity index 72%
rename from test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/LocalDateGenerator.cs
rename to test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/LocalDateGenerator.cs
index 635dfcbbf..136c246e9 100644
--- a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/LocalDateGenerator.cs
+++ b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/LocalDateGenerator.cs
@@ -1,9 +1,9 @@
using System;
using AutoFixture.Kernel;
-using Elsa.Testing.Shared.Autofixture.Abstractions;
+using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
-namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
+namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class LocalDateGenerator : SpecimenBuilderBase
{
diff --git a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/PeriodGenerator.cs b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/PeriodGenerator.cs
similarity index 73%
rename from test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/PeriodGenerator.cs
rename to test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/PeriodGenerator.cs
index fa5279160..9a1c2d454 100644
--- a/test/shared/Elsa.Testing.Shared/Autofixture/SpecimenBuilders/PeriodGenerator.cs
+++ b/test/shared/Elsa.Testing.Shared/AutoFixture/SpecimenBuilders/PeriodGenerator.cs
@@ -1,10 +1,10 @@
using System;
using AutoFixture;
using AutoFixture.Kernel;
-using Elsa.Testing.Shared.Autofixture.Abstractions;
+using Elsa.Testing.Shared.AutoFixture.Abstractions;
using NodaTime;
-namespace Elsa.Testing.Shared.Autofixture.SpecimenBuilders
+namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
{
public class PeriodGenerator : SpecimenBuilderBase
{
diff --git a/test/shared/Elsa.Testing.Shared/Elsa.Testing.Shared.csproj b/test/shared/Elsa.Testing.Shared/Elsa.Testing.Shared.csproj
index 67a1408a2..483854b89 100644
--- a/test/shared/Elsa.Testing.Shared/Elsa.Testing.Shared.csproj
+++ b/test/shared/Elsa.Testing.Shared/Elsa.Testing.Shared.csproj
@@ -1,7 +1,7 @@
- netstandard2.0
+ netstandard2.1
latest
1.0.0
Elsa Contributors
@@ -19,7 +19,10 @@
+
+
+
@@ -29,4 +32,8 @@
+
+
+
+
diff --git a/test/unit/Elsa.Core.UnitTests/TemporaryFolder.cs b/test/shared/Elsa.Testing.Shared/Helpers/TemporaryFolder.cs
similarity index 93%
rename from test/unit/Elsa.Core.UnitTests/TemporaryFolder.cs
rename to test/shared/Elsa.Testing.Shared/Helpers/TemporaryFolder.cs
index b93355aa8..513e60145 100644
--- a/test/unit/Elsa.Core.UnitTests/TemporaryFolder.cs
+++ b/test/shared/Elsa.Testing.Shared/Helpers/TemporaryFolder.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
-namespace Elsa.Core.UnitTests
+namespace Elsa.Core.IntegrationTests.Helpers
{
public class TemporaryFolder : IDisposable
{
diff --git a/test/shared/Elsa.Testing.Shared/Helpers/WorkflowsUnitTestBase.cs b/test/shared/Elsa.Testing.Shared/Helpers/WorkflowsUnitTestBase.cs
new file mode 100644
index 000000000..e3bd8494a
--- /dev/null
+++ b/test/shared/Elsa.Testing.Shared/Helpers/WorkflowsUnitTestBase.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Threading.Tasks;
+using Elsa.Core.IntegrationTests.Helpers;
+using Elsa.Services;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+using Xunit.Abstractions;
+using YesSql;
+using YesSql.Provider.Sqlite;
+
+namespace Elsa.Testing.Shared.Helpers
+{
+ public abstract class WorkflowsUnitTestBase : IAsyncLifetime, IDisposable
+ {
+ private readonly TemporaryFolder _tempFolder;
+
+ protected WorkflowsUnitTestBase(ITestOutputHelper testOutputHelper, Action? configureServices = default)
+ {
+ _tempFolder = new TemporaryFolder();
+ TestOutputHelper = testOutputHelper;
+
+ var services = new ServiceCollection()
+ .AddElsa(options => options.UsePersistence(config => ConfigurePersistence(config, _tempFolder.Folder)))
+ .AddConsoleActivities(Console.In, new XunitConsoleForwarder(testOutputHelper));
+
+ configureServices?.Invoke(services);
+ ServiceProvider = services.BuildServiceProvider();
+ WorkflowHost = ServiceProvider.GetRequiredService();
+ }
+
+ protected ITestOutputHelper TestOutputHelper { get; }
+ protected ServiceProvider ServiceProvider { get; }
+ protected IWorkflowHost WorkflowHost { get; }
+ public virtual void Dispose() => _tempFolder.Dispose();
+
+ public virtual async Task InitializeAsync()
+ {
+ var startupRunner = ServiceProvider.GetRequiredService();
+ await startupRunner.StartupAsync();
+ }
+
+ public virtual async Task DisposeAsync()
+ {
+ await ServiceProvider.DisposeAsync();
+ Dispose();
+ }
+
+ private void ConfigurePersistence(IConfiguration configuration, string folder)
+ {
+ var connectionString = $@"Data Source={folder}elsa.db;Cache=Shared";
+ configuration.UseSqLite(connectionString).UseDefaultIdGenerator();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/shared/Elsa.Testing.Shared/Helpers/XunitConsoleForwarder.cs b/test/shared/Elsa.Testing.Shared/Helpers/XunitConsoleForwarder.cs
new file mode 100644
index 000000000..6bf20f966
--- /dev/null
+++ b/test/shared/Elsa.Testing.Shared/Helpers/XunitConsoleForwarder.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Xunit.Abstractions;
+
+namespace Elsa.Core.IntegrationTests.Helpers
+{
+ public class XunitConsoleForwarder : TextWriter
+ {
+ private readonly ITestOutputHelper _output;
+ private IList _line = new List();
+ public XunitConsoleForwarder(ITestOutputHelper output) => _output = output;
+ public override Encoding Encoding => Console.Out.Encoding;
+
+ public override void Write(char value)
+ {
+ if (value == '\n')
+ {
+ FlushLine();
+ _line = new List();
+ return;
+ }
+
+ _line.Add(value);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_line.Count > 0)
+ FlushLine();
+ base.Dispose(disposing);
+ }
+
+ private void FlushLine()
+ {
+ if (_line.Count > 0 && _line.Last() == '\r')
+ _line.RemoveAt(_line.Count - 1);
+
+ _output.WriteLine(new string(_line.ToArray()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/unit/Elsa.Core.UnitTests/WorkflowHostTests.cs b/test/unit/Elsa.Core.UnitTests/WorkflowHostTests.cs
deleted file mode 100644
index 7b981619f..000000000
--- a/test/unit/Elsa.Core.UnitTests/WorkflowHostTests.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-// using System;
-// using System.Threading;
-// using System.Threading.Tasks;
-// using AutoFixture;
-// using Elsa.ActivityResults;
-// using Elsa.Expressions;
-// using Elsa.Models;
-// using Elsa.Services;
-// using Elsa.Services.Models;
-// using Elsa.Testing.Shared.Autofixture;
-// using MediatR;
-// using Microsoft.Extensions.DependencyInjection;
-// using Microsoft.Extensions.Logging.Abstractions;
-// using Moq;
-// using NodaTime;
-// using NodaTime.Testing;
-// using Xunit;
-// using YesSql;
-// using YesSql.Provider.Sqlite;
-//
-// namespace Elsa.Core.UnitTests
-// {
-// public class WorkflowHostTests : IDisposable
-// {
-// private readonly IFixture _fixture;
-// private readonly WorkflowHost _workflowHost;
-// private TemporaryFolder _tempFolder;
-// private ISession _session;
-//
-// public WorkflowHostTests()
-// {
-// _fixture = new Fixture().Customize(new NodaTimeCustomization());
-// _session = CreateSession();
-//
-// var workflowActivatorMock = new Mock();
-// var workflowRegistryMock = new Mock();
-// var workflowInstanceManager = new WorkflowInstanceManager(_session);
-// var workflowExpressionEvaluatorMock = new Mock();
-// var mediatorMock = new Mock();
-// var now = _fixture.Create();
-// var clock = new FakeClock(now);
-// var logger = new NullLogger();
-// var serviceProvider = new ServiceCollection().BuildServiceProvider();
-//
-// workflowActivatorMock
-// .Setup(x => x.InstantiateAsync(It.IsAny(), It.IsAny(), It.IsAny()))
-// .ReturnsAsync((WorkflowBlueprint workflow, string? correlationId, CancellationToken cancellationToken) => new WorkflowInstance());
-//
-// _workflowHost = new WorkflowHost(
-// workflowInstanceManager,
-// workflowRegistryMock.Object,
-// workflowActivatorMock.Object,
-// workflowExpressionEvaluatorMock.Object,
-// clock,
-// mediatorMock.Object,
-// serviceProvider,
-// logger);
-// }
-//
-// public void Dispose() => _session.Dispose();
-//
-// private ISession CreateSession()
-// {
-// _tempFolder = new TemporaryFolder();
-// var connectionString = $@"Data Source={_tempFolder.Folder}elsa.db;Cache=Shared";
-// var config = new Configuration().UseSqLite(connectionString).UseDefaultIdGenerator();
-// var store = StoreFactory.CreateAndInitializeAsync(config).GetAwaiter().GetResult();
-// return store.CreateSession();
-// }
-//
-// [Fact(DisplayName = "Can run simple workflow to completed state.")]
-// public async Task RunAsync01()
-// {
-// var activityExecutionResultMock = new Mock();
-// var activity = CreateActivity(activityExecutionResult: activityExecutionResultMock.Object);
-// var workflow = CreateWorkflow(activity);
-// var executionContext = await _workflowHost.RunWorkflowAsync(workflow);
-//
-// Assert.Equal(WorkflowStatus.Completed, executionContext.UpdateWorkflowInstance().Status);
-// }
-//
-// [Fact(DisplayName = "Invokes returned activity execution result.")]
-// public async Task RunAsync02()
-// {
-// var activityExecutionResultMock = new Mock();
-// var activity = CreateActivity(true, activityExecutionResultMock.Object);
-// var workflow = CreateWorkflow(activity);
-// var executionContext = await _workflowHost.RunWorkflowAsync(workflow);
-//
-// activityExecutionResultMock
-// .Verify(x => x.ExecuteAsync(It.IsAny(), It.IsAny()), Times.Once);
-// }
-//
-// private IActivity CreateActivity(bool canExecute = true, IActivityExecutionResult? activityExecutionResult = null)
-// {
-// var activityMock = new Mock();
-// var activityId = _fixture.Create();
-//
-// activityMock.Setup(x => x.Id).Returns(activityId);
-//
-// activityMock
-// .Setup(x => x.CanExecuteAsync(It.IsAny(), It.IsAny()))
-// .ReturnsAsync(canExecute);
-//
-// if (activityExecutionResult != null)
-// activityMock
-// .Setup(x => x.ExecuteAsync(It.IsAny(), It.IsAny()))
-// .ReturnsAsync(activityExecutionResult);
-//
-// return activityMock.Object;
-// }
-//
-// private WorkflowBlueprint CreateWorkflow(IActivity activity)
-// {
-// var workflow = new WorkflowBlueprint();
-// workflow.Activities.Add(activity);
-// return workflow;
-// }
-// }
-// }
\ No newline at end of file