diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml
index 1a24c9b44..1cab3083a 100644
--- a/.github/workflows/packages.yml
+++ b/.github/workflows/packages.yml
@@ -31,12 +31,8 @@ jobs:
else
echo "VERSION=3.1.0-preview.${{github.run_number}}" >> $GITHUB_ENV
fi
- - name: Build
- run: dotnet build --configuration Release /p:Version=${VERSION}
- - name: Test
- run: dotnet test --configuration Release /p:Version=${VERSION} --no-build
- - name: Pack
- run: dotnet pack --configuration Release /p:Version=${VERSION} /p:PackageOutputPath=$(pwd)/packages
+ - name: Compile+Test+Pack
+ run: ./build.sh Compile+Test+Pack --version ${VERSION}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
new file mode 100644
index 000000000..6d7547a43
--- /dev/null
+++ b/.github/workflows/pr.yml
@@ -0,0 +1,44 @@
+# ------------------------------------------------------------------------------
+#
+#
+# This code was generated.
+#
+# - To turn off auto-generation set:
+#
+# [CustomGitHubActions (AutoGenerate = false)]
+#
+# - To trigger manual generation invoke:
+#
+# nuke --generate-configuration GitHubActions_pr --host GitHubActions
+#
+#
+# ------------------------------------------------------------------------------
+
+name: pr
+
+on:
+ pull_request:
+ branches:
+ - main
+ - 'v3*'
+ paths:
+ - '**/*'
+ - '!docs/**/*'
+ - '!package.json'
+ - '!package-lock.json'
+ - '!readme.md'
+
+jobs:
+ ubuntu-latest:
+ name: ubuntu-latest
+ runs-on: ubuntu-latest
+ steps:
+ - if: ${{ runner.os == 'Windows' }}
+ name: 'Use GNU tar'
+ shell: cmd
+ run: |
+ echo "Adding GNU tar to PATH"
+ echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%"
+ - uses: actions/checkout@v3
+ - name: 'Run: Compile, Test, Pack'
+ run: ./build.cmd Compile Test Pack
diff --git a/.gitignore b/.gitignore
index 68b95e154..f772d8ea0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,9 +51,6 @@ node_modules/
.stylelintrc.yml
.eslintrc.yml
-#github
-.github/
-
#volatile
App_Data/
*.db
@@ -76,3 +73,6 @@ src/designer/elsa-workflows-designer/loader
src/modules/Elsa.Workflows.Designer/package-lock.json
unlist.sh
+
+# build artifacts
+/artifacts
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
new file mode 100644
index 000000000..3f9224ea7
--- /dev/null
+++ b/.nuke/build.schema.json
@@ -0,0 +1,120 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "$ref": "#/definitions/build",
+ "title": "Build Schema",
+ "definitions": {
+ "build": {
+ "type": "object",
+ "properties": {
+ "Configuration": {
+ "type": "string",
+ "enum": [
+ "Debug",
+ "Release"
+ ]
+ },
+ "Continue": {
+ "type": "boolean",
+ "description": "Indicates to continue a previously failed build attempt"
+ },
+ "Help": {
+ "type": "boolean",
+ "description": "Shows the help text for this build assembly"
+ },
+ "Host": {
+ "type": "string",
+ "description": "Host for execution. Default is 'automatic'",
+ "enum": [
+ "AppVeyor",
+ "AzurePipelines",
+ "Bamboo",
+ "Bitbucket",
+ "Bitrise",
+ "GitHubActions",
+ "GitLab",
+ "Jenkins",
+ "Rider",
+ "SpaceAutomation",
+ "TeamCity",
+ "Terminal",
+ "TravisCI",
+ "VisualStudio",
+ "VSCode"
+ ]
+ },
+ "IgnoreFailedSources": {
+ "type": "boolean",
+ "description": "Ignore unreachable sources during Restore"
+ },
+ "NoLogo": {
+ "type": "boolean",
+ "description": "Disables displaying the NUKE logo"
+ },
+ "Partition": {
+ "type": "string",
+ "description": "Partition to use on CI"
+ },
+ "Plan": {
+ "type": "boolean",
+ "description": "Shows the execution plan (HTML)"
+ },
+ "Profile": {
+ "type": "array",
+ "description": "Defines the profiles to load",
+ "items": {
+ "type": "string"
+ }
+ },
+ "Root": {
+ "type": "string",
+ "description": "Root directory during build execution"
+ },
+ "Skip": {
+ "type": "array",
+ "description": "List of targets to be skipped. Empty list skips all dependencies",
+ "items": {
+ "type": "string",
+ "enum": [
+ "Clean",
+ "Compile",
+ "Pack",
+ "Restore",
+ "Test"
+ ]
+ }
+ },
+ "Solution": {
+ "type": "string",
+ "description": "Path to a solution file that is automatically loaded"
+ },
+ "Target": {
+ "type": "array",
+ "description": "List of targets to be invoked. Default is '{default_target}'",
+ "items": {
+ "type": "string",
+ "enum": [
+ "Clean",
+ "Compile",
+ "Pack",
+ "Restore",
+ "Test"
+ ]
+ }
+ },
+ "Verbosity": {
+ "type": "string",
+ "description": "Logging verbosity during build execution. Default is 'Normal'",
+ "enum": [
+ "Minimal",
+ "Normal",
+ "Quiet",
+ "Verbose"
+ ]
+ },
+ "Version": {
+ "type": "string"
+ }
+ }
+ }
+ }
+}
diff --git a/.nuke/parameters.json b/.nuke/parameters.json
new file mode 100644
index 000000000..8535901f9
--- /dev/null
+++ b/.nuke/parameters.json
@@ -0,0 +1,4 @@
+{
+ "$schema": "./build.schema.json",
+ "Solution": "Elsa.sln"
+}
diff --git a/Elsa.sln b/Elsa.sln
index f873a4d89..f70ca412d 100644
--- a/Elsa.sln
+++ b/Elsa.sln
@@ -1,3 +1,4 @@
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34003.232
@@ -16,12 +17,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{7D
common.props = common.props
configureawait.props = configureawait.props
docker-compose.yml = docker-compose.yml
+ frameworks.props = frameworks.props
icon.png = icon.png
NuGet.Config = NuGet.Config
packages.props = packages.props
README.md = README.md
update-migrations.sh = update-migrations.sh
- frameworks.props = frameworks.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{0354F050-3992-4DD4-B0EE-5FBA04AC72B6}"
@@ -254,51 +255,52 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.EntityFrameworkCore.My
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.EntityFrameworkCore.PostgreSql", "src\modules\Elsa.EntityFrameworkCore.PostgreSql\Elsa.EntityFrameworkCore.PostgreSql.csproj", "{84AB9951-3DBF-43A4-8F5D-AEED1102CE88}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Alterations.MassTransit", "src\modules\Elsa.Alterations.MassTransit\Elsa.Alterations.MassTransit.csproj", "{1F621382-08FB-45EA-B94C-96A7FECB9489}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Alterations.MassTransit", "src\modules\Elsa.Alterations.MassTransit\Elsa.Alterations.MassTransit.csproj", "{1F621382-08FB-45EA-B94C-96A7FECB9489}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.UnitTests", "test\unit\Elsa.Activities.UnitTests\Elsa.Activities.UnitTests.csproj", "{E6562B0F-AF64-472A-B009-BF6D40DDE99B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.UnitTests", "test\unit\Elsa.Activities.UnitTests\Elsa.Activities.UnitTests.csproj", "{E6562B0F-AF64-472A-B009-BF6D40DDE99B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.ServiceBus.IntegrationTests", "test\integration\Elsa.ServiceBus.IntegrationTests\Elsa.ServiceBus.IntegrationTests.csproj", "{9504E3F3-F77F-437A-8644-D23D7F5FCF8B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElsaStudioWebAssembly", "src\bundles\ElsaStudioWebAssembly\ElsaStudioWebAssembly.csproj", "{E12A1BDF-5D65-493B-835D-AFBC480A5650}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElsaStudioWebAssembly", "src\bundles\ElsaStudioWebAssembly\ElsaStudioWebAssembly.csproj", "{E12A1BDF-5D65-493B-835D-AFBC480A5650}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.EntityFrameworkCore.Common", "src\modules\Elsa.EntityFrameworkCore.Common\Elsa.EntityFrameworkCore.Common.csproj", "{FBA14F8A-9F14-4364-ABDB-B8AE81A0D755}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.EntityFrameworkCore.Common", "src\modules\Elsa.EntityFrameworkCore.Common\Elsa.EntityFrameworkCore.Common.csproj", "{FBA14F8A-9F14-4364-ABDB-B8AE81A0D755}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Quartz.EntityFrameworkCore.Sqlite", "src\modules\Elsa.Quartz.EntityFrameworkCore.Sqlite\Elsa.Quartz.EntityFrameworkCore.Sqlite.csproj", "{A71557F2-D5FB-4772-9391-F7D18A3B6C44}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Quartz.EntityFrameworkCore.Sqlite", "src\modules\Elsa.Quartz.EntityFrameworkCore.Sqlite\Elsa.Quartz.EntityFrameworkCore.Sqlite.csproj", "{A71557F2-D5FB-4772-9391-F7D18A3B6C44}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Quartz.EntityFrameworkCore.SqlServer", "src\modules\Elsa.Quartz.EntityFrameworkCore.SqlServer\Elsa.Quartz.EntityFrameworkCore.SqlServer.csproj", "{05F3B23E-CF28-467B-AD3C-595EA4ED6B96}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Quartz.EntityFrameworkCore.SqlServer", "src\modules\Elsa.Quartz.EntityFrameworkCore.SqlServer\Elsa.Quartz.EntityFrameworkCore.SqlServer.csproj", "{05F3B23E-CF28-467B-AD3C-595EA4ED6B96}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Quartz.EntityFrameworkCore.MySql", "src\modules\Elsa.Quartz.EntityFrameworkCore.MySql\Elsa.Quartz.EntityFrameworkCore.MySql.csproj", "{74ACD9D0-8B4C-42FA-A582-E93BF0075023}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Quartz.EntityFrameworkCore.MySql", "src\modules\Elsa.Quartz.EntityFrameworkCore.MySql\Elsa.Quartz.EntityFrameworkCore.MySql.csproj", "{74ACD9D0-8B4C-42FA-A582-E93BF0075023}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Quartz.EntityFrameworkCore.PostgreSql", "src\modules\Elsa.Quartz.EntityFrameworkCore.PostgreSql\Elsa.Quartz.EntityFrameworkCore.PostgreSql.csproj", "{CCCCEF8C-7D96-4BEA-B9D0-E91EDF08E65D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Quartz.EntityFrameworkCore.PostgreSql", "src\modules\Elsa.Quartz.EntityFrameworkCore.PostgreSql\Elsa.Quartz.EntityFrameworkCore.PostgreSql.csproj", "{CCCCEF8C-7D96-4BEA-B9D0-E91EDF08E65D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.FileStorage", "src\modules\Elsa.FileStorage\Elsa.FileStorage.csproj", "{732BF088-6AD7-4C4D-9A48-8074253596D4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.FileStorage", "src\modules\Elsa.FileStorage\Elsa.FileStorage.csproj", "{732BF088-6AD7-4C4D-9A48-8074253596D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "storage", "storage", "{B818988E-639C-4E6E-85C1-B231BCAD9DAB}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.CSharp", "src\modules\Elsa.CSharp\Elsa.CSharp.csproj", "{24331E82-D7AF-45B1-ACF0-CA6C3B0B77DC}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.CSharp", "src\modules\Elsa.CSharp\Elsa.CSharp.csproj", "{24331E82-D7AF-45B1-ACF0-CA6C3B0B77DC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Python", "src\modules\Elsa.Python\Elsa.Python.csproj", "{790E94F2-5393-47DF-AC52-D9247F5B243A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Python", "src\modules\Elsa.Python\Elsa.Python.csproj", "{790E94F2-5393-47DF-AC52-D9247F5B243A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MassTransit.RabbitMq", "src\modules\Elsa.MassTransit.RabbitMq\Elsa.MassTransit.RabbitMq.csproj", "{169BEA3D-2A81-47EE-A6C1-3F8719EEC1F6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.MassTransit.RabbitMq", "src\modules\Elsa.MassTransit.RabbitMq\Elsa.MassTransit.RabbitMq.csproj", "{169BEA3D-2A81-47EE-A6C1-3F8719EEC1F6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MassTransit.AzureServiceBus", "src\modules\Elsa.MassTransit.AzureServiceBus\Elsa.MassTransit.AzureServiceBus.csproj", "{5B1AF00E-1030-4BBA-9C1A-1DC5AEFDD44A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.MassTransit.AzureServiceBus", "src\modules\Elsa.MassTransit.AzureServiceBus\Elsa.MassTransit.AzureServiceBus.csproj", "{5B1AF00E-1030-4BBA-9C1A-1DC5AEFDD44A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.Heartbeats", "src\samples\aspnet\Elsa.Samples.AspNet.Heartbeats\Elsa.Samples.AspNet.Heartbeats.csproj", "{26888832-DBEA-4B23-8DC2-84478A702CC4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.AspNet.Heartbeats", "src\samples\aspnet\Elsa.Samples.AspNet.Heartbeats\Elsa.Samples.AspNet.Heartbeats.csproj", "{26888832-DBEA-4B23-8DC2-84478A702CC4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipelines", "pipelines", "{B789B743-0FBE-4BBC-9F45-84C20C8D4814}"
ProjectSection(SolutionItems) = preProject
.github\workflows\elsa-server-and-studio.yml = .github\workflows\elsa-server-and-studio.yml
.github\workflows\elsa-server.yml = .github\workflows\elsa-server.yml
- .github\workflows\packages.yml = .github\workflows\packages.yml
.github\workflows\elsa-studio.yml = .github\workflows\elsa-studio.yml
+ .github\workflows\packages.yml = .github\workflows\packages.yml
+ .github\workflows\pr.yml = .github\workflows\pr.yml
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Studio.Web", "src\bundles\Elsa.Studio.Web\Elsa.Studio.Web.csproj", "{D5C149EE-276C-4C59-98F9-37F0EA2A7866}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Studio.Web", "src\bundles\Elsa.Studio.Web\Elsa.Studio.Web.csproj", "{D5C149EE-276C-4C59-98F9-37F0EA2A7866}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.AspNet.CustomUIHandler", "src\samples\aspnet\Elsa.Samples.AspNet.CustomUIHandler\Elsa.Samples.AspNet.CustomUIHandler.csproj", "{832D6FF5-16D3-41D1-8FDD-D9BEC26BDA6A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MassTransit.RabbitMq", "src\modules\Elsa.MassTransit.RabbitMq\Elsa.MassTransit.RabbitMq.csproj", "{169BEA3D-2A81-47EE-A6C1-3F8719EEC1F6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{99F2B1DA-2F69-4D70-A2A3-AC985AD91EC4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MassTransit.AzureServiceBus", "src\modules\Elsa.MassTransit.AzureServiceBus\Elsa.MassTransit.AzureServiceBus.csproj", "{5B1AF00E-1030-4BBA-9C1A-1DC5AEFDD44A}"
EndProject
@@ -881,8 +883,8 @@ Global
{05F3B23E-CF28-467B-AD3C-595EA4ED6B96} = {AB797AF0-C12C-46DE-A157-7E25625C6200}
{74ACD9D0-8B4C-42FA-A582-E93BF0075023} = {AB797AF0-C12C-46DE-A157-7E25625C6200}
{CCCCEF8C-7D96-4BEA-B9D0-E91EDF08E65D} = {AB797AF0-C12C-46DE-A157-7E25625C6200}
- {B818988E-639C-4E6E-85C1-B231BCAD9DAB} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
{732BF088-6AD7-4C4D-9A48-8074253596D4} = {B818988E-639C-4E6E-85C1-B231BCAD9DAB}
+ {B818988E-639C-4E6E-85C1-B231BCAD9DAB} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
{24331E82-D7AF-45B1-ACF0-CA6C3B0B77DC} = {6EF07978-A6D2-40EB-891D-7D70C5F37E76}
{790E94F2-5393-47DF-AC52-D9247F5B243A} = {6EF07978-A6D2-40EB-891D-7D70C5F37E76}
{169BEA3D-2A81-47EE-A6C1-3F8719EEC1F6} = {DD089B8B-DA73-492A-9010-F772D1C178DA}
diff --git a/build.cmd b/build.cmd
new file mode 100755
index 000000000..b08cc590f
--- /dev/null
+++ b/build.cmd
@@ -0,0 +1,7 @@
+:; set -eo pipefail
+:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
+:; ${SCRIPT_DIR}/build.sh "$@"
+:; exit $?
+
+@ECHO OFF
+powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*
diff --git a/build.ps1 b/build.ps1
new file mode 100644
index 000000000..4634dc03e
--- /dev/null
+++ b/build.ps1
@@ -0,0 +1,74 @@
+[CmdletBinding()]
+Param(
+ [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
+ [string[]]$BuildArguments
+)
+
+Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
+
+Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
+$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
+
+###########################################################################
+# CONFIGURATION
+###########################################################################
+
+$BuildProjectFile = "$PSScriptRoot\build\_build.csproj"
+$TempDirectory = "$PSScriptRoot\\.nuke\temp"
+
+$DotNetGlobalFile = "$PSScriptRoot\\global.json"
+$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
+$DotNetChannel = "STS"
+
+$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
+$env:DOTNET_NOLOGO = 1
+
+###########################################################################
+# EXECUTION
+###########################################################################
+
+function ExecSafe([scriptblock] $cmd) {
+ & $cmd
+ if ($LASTEXITCODE) { exit $LASTEXITCODE }
+}
+
+# If dotnet CLI is installed globally and it matches requested version, use for execution
+if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
+ $(dotnet --version) -and $LASTEXITCODE -eq 0) {
+ $env:DOTNET_EXE = (Get-Command "dotnet").Path
+}
+else {
+ # Download install script
+ $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
+ New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
+
+ # If global.json exists, load expected version
+ if (Test-Path $DotNetGlobalFile) {
+ $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
+ if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
+ $DotNetVersion = $DotNetGlobal.sdk.version
+ }
+ }
+
+ # Install by channel or version
+ $DotNetDirectory = "$TempDirectory\dotnet-win"
+ if (!(Test-Path variable:DotNetVersion)) {
+ ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
+ } else {
+ ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
+ }
+ $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
+ $env:PATH = "$DotNetDirectory;$env:PATH"
+}
+
+Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
+
+if (Test-Path env:NUKE_ENTERPRISE_TOKEN) {
+ & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null
+ & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null
+}
+
+ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
+ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
diff --git a/build.sh b/build.sh
new file mode 100755
index 000000000..fdff0c623
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+
+bash --version 2>&1 | head -n 1
+
+set -eo pipefail
+SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
+
+###########################################################################
+# CONFIGURATION
+###########################################################################
+
+BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj"
+TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
+
+DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
+DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
+DOTNET_CHANNEL="STS"
+
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+export DOTNET_NOLOGO=1
+
+###########################################################################
+# EXECUTION
+###########################################################################
+
+function FirstJsonValue {
+ perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
+}
+
+# If dotnet CLI is installed globally and it matches requested version, use for execution
+if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
+ export DOTNET_EXE="$(command -v dotnet)"
+else
+ # Download install script
+ DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
+ mkdir -p "$TEMP_DIRECTORY"
+ curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
+ chmod +x "$DOTNET_INSTALL_FILE"
+
+ # If global.json exists, load expected version
+ if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
+ DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
+ if [[ "$DOTNET_VERSION" == "" ]]; then
+ unset DOTNET_VERSION
+ fi
+ fi
+
+ # Install by channel or version
+ DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
+ if [[ -z ${DOTNET_VERSION+x} ]]; then
+ "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
+ else
+ "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
+ fi
+ export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
+ export PATH="$DOTNET_DIRECTORY:$PATH"
+fi
+
+echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
+
+if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then
+ "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true
+ "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true
+fi
+
+"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
+"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
diff --git a/build/.editorconfig b/build/.editorconfig
new file mode 100644
index 000000000..31e43dcd8
--- /dev/null
+++ b/build/.editorconfig
@@ -0,0 +1,11 @@
+[*.cs]
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_property = false:warning
+dotnet_style_qualification_for_method = false:warning
+dotnet_style_qualification_for_event = false:warning
+dotnet_style_require_accessibility_modifiers = never:warning
+
+csharp_style_expression_bodied_methods = true:silent
+csharp_style_expression_bodied_properties = true:warning
+csharp_style_expression_bodied_indexers = true:warning
+csharp_style_expression_bodied_accessors = true:warning
diff --git a/build/Build.CI.GitHubActions.cs b/build/Build.CI.GitHubActions.cs
new file mode 100644
index 000000000..a6e559699
--- /dev/null
+++ b/build/Build.CI.GitHubActions.cs
@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+using Nuke.Common.CI.GitHubActions;
+using Nuke.Common.CI.GitHubActions.Configuration;
+using Nuke.Common.Execution;
+using Nuke.Common.Utilities;
+using Nuke.Components;
+
+[CustomGitHubActions(
+ "pr",
+ GitHubActionsImage.UbuntuLatest,
+ OnPullRequestBranches = ["main"],
+ OnPullRequestIncludePaths = ["**/*"],
+ OnPullRequestExcludePaths = ["docs/**/*", "package.json", "package-lock.json", "readme.md"],
+ PublishArtifacts = false,
+ InvokedTargets = [nameof(ICompile.Compile), nameof(ITest.Test), nameof(IPack.Pack)],
+ CacheKeyFiles = []
+ )
+]
+public partial class Build;
+
+class CustomGitHubActionsAttribute : GitHubActionsAttribute
+{
+ public CustomGitHubActionsAttribute(string name, GitHubActionsImage image, params GitHubActionsImage[] images) : base(name, image, images)
+ {
+ }
+
+ protected override GitHubActionsJob GetJobs(GitHubActionsImage image, IReadOnlyCollection relevantTargets)
+ {
+ var job = base.GetJobs(image, relevantTargets);
+
+ var newSteps = new List(job.Steps);
+ newSteps.Insert(0, new GitHubActionsUseGnuTarStep());
+
+ job.Steps = newSteps.ToArray();
+ return job;
+ }
+}
+
+class GitHubActionsUseGnuTarStep : GitHubActionsStep
+{
+ public override void Write(CustomFileWriter writer)
+ {
+ writer.WriteLine("- if: ${{ runner.os == 'Windows' }}");
+ using (writer.Indent())
+ {
+ writer.WriteLine("name: 'Use GNU tar'");
+ writer.WriteLine("shell: cmd");
+ writer.WriteLine("run: |");
+ using (writer.Indent())
+ {
+ writer.WriteLine("echo \"Adding GNU tar to PATH\"");
+ writer.WriteLine("echo C:\\Program Files\\Git\\usr\\bin>>\"%GITHUB_PATH%\"");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build/Build.cs b/build/Build.cs
new file mode 100644
index 000000000..c3f644925
--- /dev/null
+++ b/build/Build.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Nuke.Common;
+using Nuke.Common.CI;
+using Nuke.Common.Git;
+using Nuke.Common.IO;
+using Nuke.Common.ProjectModel;
+using Nuke.Common.Tooling;
+using Nuke.Common.Tools.DotNet;
+using Nuke.Common.Utilities.Collections;
+using Nuke.Components;
+using Serilog;
+
+[ShutdownDotNetAfterServerBuild]
+partial class Build : NukeBuild, ITest, IPack
+{
+ public static int Main() => Execute(x => ((ICompile) x).Compile);
+
+ [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
+
+ [GitRepository] readonly GitRepository GitRepository;
+
+ AbsolutePath SourceDirectory => RootDirectory / "src";
+
+ public AbsolutePath PackagesDirectory => RootDirectory / "packages";
+
+ string TagVersion => GitRepository.Tags.SingleOrDefault(x => "v".StartsWith(x))?[1..];
+ bool IsTaggedBuild => !string.IsNullOrWhiteSpace(TagVersion);
+
+ string VersionSuffix;
+
+ [Parameter]
+ string Version;
+
+ protected override void OnBuildInitialized()
+ {
+ VersionSuffix = !IsTaggedBuild
+ ? $"preview-{DateTime.UtcNow:yyyyMMdd-HHmm}"
+ : "";
+
+ if (IsLocalBuild)
+ {
+ VersionSuffix = $"dev-{DateTime.UtcNow:yyyyMMdd-HHmm}";
+ }
+
+ Log.Information("BUILD SETUP");
+ Log.Information("Configuration:\t{Configuration}", Configuration);
+ Log.Information("Version suffix:\t{VersionSuffix}", VersionSuffix);
+ Log.Information("Version:\t\t{Version}", Version);
+ Log.Information("Tagged build:\t{IsTaggedBuild}", IsTaggedBuild);
+ }
+
+ Target Clean => _ => _
+ .Before(x => x.Restore)
+ .Executes(() =>
+ {
+ SourceDirectory.GlobDirectories("**/bin", "**/obj").ForEach(x => x.DeleteDirectory());
+ ((IHazArtifacts) this).ArtifactsDirectory.CreateOrCleanDirectory();
+ });
+
+ public Configure CompileSettings => _ => _
+ // ensure we don't generate too much output in CI run
+ // 0 Turns off emission of all warning messages
+ // 1 Displays severe warning messages
+ .SetWarningLevel(IsServerBuild ? 0 : 1);
+
+ public IEnumerable TestProjects => ((IHazSolution) this).Solution.AllProjects.Where(x => x.Name.EndsWith("Tests"));
+}
\ No newline at end of file
diff --git a/build/Configuration.cs b/build/Configuration.cs
new file mode 100644
index 000000000..9c08b1ae9
--- /dev/null
+++ b/build/Configuration.cs
@@ -0,0 +1,16 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using Nuke.Common.Tooling;
+
+[TypeConverter(typeof(TypeConverter))]
+public class Configuration : Enumeration
+{
+ public static Configuration Debug = new Configuration { Value = nameof(Debug) };
+ public static Configuration Release = new Configuration { Value = nameof(Release) };
+
+ public static implicit operator string(Configuration configuration)
+ {
+ return configuration.Value;
+ }
+}
diff --git a/build/Directory.Build.props b/build/Directory.Build.props
new file mode 100644
index 000000000..61fd9f44b
--- /dev/null
+++ b/build/Directory.Build.props
@@ -0,0 +1,7 @@
+
+
+
+ false
+
+
+
\ No newline at end of file
diff --git a/build/Directory.Build.targets b/build/Directory.Build.targets
new file mode 100644
index 000000000..253260956
--- /dev/null
+++ b/build/Directory.Build.targets
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/build/_build.csproj b/build/_build.csproj
new file mode 100644
index 000000000..cdd7e0336
--- /dev/null
+++ b/build/_build.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net8.0
+
+ CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006
+ ..
+ ..
+ 1
+ true
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+
diff --git a/build/_build.csproj.DotSettings b/build/_build.csproj.DotSettings
new file mode 100644
index 000000000..eb3f4c27c
--- /dev/null
+++ b/build/_build.csproj.DotSettings
@@ -0,0 +1,28 @@
+
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ DO_NOT_SHOW
+ Implicit
+ Implicit
+ ExpressionBody
+ 0
+ NEXT_LINE
+ True
+ False
+ 120
+ IF_OWNER_IS_SINGLE_LINE
+ WRAP_IF_LONG
+ False
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+ True
diff --git a/src/bundles/Elsa.Server.Web/Program.cs b/src/bundles/Elsa.Server.Web/Program.cs
index 28631b6a1..bb2fc19ad 100644
--- a/src/bundles/Elsa.Server.Web/Program.cs
+++ b/src/bundles/Elsa.Server.Web/Program.cs
@@ -10,7 +10,6 @@ using Elsa.EntityFrameworkCore.Modules.Identity;
using Elsa.EntityFrameworkCore.Modules.Management;
using Elsa.EntityFrameworkCore.Modules.Runtime;
using Elsa.Extensions;
-using Elsa.Http.Handlers;
using Elsa.Http.Options;
using Elsa.MongoDb.Extensions;
using Elsa.MongoDb.Modules.Identity;
diff --git a/src/bundles/Elsa.Server.Web/appsettings.json b/src/bundles/Elsa.Server.Web/appsettings.json
index 9859fc4f8..131ccbe59 100644
--- a/src/bundles/Elsa.Server.Web/appsettings.json
+++ b/src/bundles/Elsa.Server.Web/appsettings.json
@@ -17,7 +17,7 @@
"Sqlite": "Data Source=App_Data/elsa.sqlite.db;Cache=Shared;",
"MongoDb": "mongodb://localhost:27017/elsa-workflows",
"AzureServiceBus": "",
- "RabbitMq": "amqp://guest:guest@localhost:5672/elsa"
+ "RabbitMq": "amqp://guest:guest@localhost:5672"
},
"Smtp": {
"Host": "localhost",
diff --git a/src/bundles/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj b/src/bundles/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
index 8fa4d53b5..d58697184 100644
--- a/src/bundles/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
+++ b/src/bundles/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
@@ -18,6 +18,7 @@
+
@@ -34,8 +35,8 @@
-
-
+
+
\ No newline at end of file
diff --git a/src/bundles/Elsa.ServerAndStudio.Web/Program.cs b/src/bundles/Elsa.ServerAndStudio.Web/Program.cs
index eb19d40ac..a83d2cf6a 100644
--- a/src/bundles/Elsa.ServerAndStudio.Web/Program.cs
+++ b/src/bundles/Elsa.ServerAndStudio.Web/Program.cs
@@ -3,9 +3,10 @@ using Elsa.EntityFrameworkCore.Extensions;
using Elsa.EntityFrameworkCore.Modules.Management;
using Elsa.EntityFrameworkCore.Modules.Runtime;
using Elsa.Extensions;
-using Elsa.Webhooks.Extensions;
using Microsoft.AspNetCore.Mvc;
+const bool useMassTransit = true;
+
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseStaticWebAssets();
var services = builder.Services;
@@ -16,32 +17,39 @@ var identityTokenSection = identitySection.GetSection("Tokens");
// Add Elsa services.
services
- .AddElsa(elsa => elsa
- .UseSasTokens()
- .UseIdentity(identity =>
+ .AddElsa(elsa =>
+ {
+ elsa
+ .UseSasTokens()
+ .UseIdentity(identity =>
+ {
+ identity.IdentityOptions = options => identitySection.Bind(options);
+ identity.TokenOptions = options => identityTokenSection.Bind(options);
+ identity.UseConfigurationBasedUserProvider(options => identitySection.Bind(options));
+ identity.UseConfigurationBasedApplicationProvider(options => identitySection.Bind(options));
+ identity.UseConfigurationBasedRoleProvider(options => identitySection.Bind(options));
+ })
+ .UseDefaultAuthentication()
+ .UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)))
+ .UseWorkflowRuntime(runtime => runtime.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)))
+ .UseScheduling()
+ .UseJavaScript(options => options.AllowClrAccess = true)
+ .UseLiquid()
+ .UseCSharp()
+ .UsePython()
+ .UseHttp(http => http.ConfigureHttpOptions = options => configuration.GetSection("Http").Bind(options))
+ .UseEmail(email => email.ConfigureOptions = options => configuration.GetSection("Smtp").Bind(options))
+ .UseWebhooks(webhooks => webhooks.WebhookOptions = options => builder.Configuration.GetSection("Webhooks").Bind(options))
+ .UseWorkflowsApi()
+ .UseRealTimeWorkflows()
+ .AddActivitiesFrom()
+ .AddWorkflowsFrom();
+
+ if (useMassTransit)
{
- identity.IdentityOptions = options => identitySection.Bind(options);
- identity.TokenOptions = options => identityTokenSection.Bind(options);
- identity.UseConfigurationBasedUserProvider(options => identitySection.Bind(options));
- identity.UseConfigurationBasedApplicationProvider(options => identitySection.Bind(options));
- identity.UseConfigurationBasedRoleProvider(options => identitySection.Bind(options));
- })
- .UseDefaultAuthentication()
- .UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)))
- .UseWorkflowRuntime(runtime => runtime.UseEntityFrameworkCore(ef => ef.UseSqlite(sqliteConnectionString)))
- .UseScheduling()
- .UseJavaScript(options => options.AllowClrAccess = true)
- .UseLiquid()
- .UseCSharp()
- .UsePython()
- .UseHttp(http => http.ConfigureHttpOptions = options => configuration.GetSection("Http").Bind(options))
- .UseEmail(email => email.ConfigureOptions = options => configuration.GetSection("Smtp").Bind(options))
- .UseWebhooks(webhooks => webhooks.WebhookOptions = options => builder.Configuration.GetSection("Webhooks").Bind(options))
- .UseWorkflowsApi()
- .UseRealTimeWorkflows()
- .AddActivitiesFrom()
- .AddWorkflowsFrom()
- );
+ elsa.UseMassTransit();
+ }
+ });
services.AddHealthChecks();
diff --git a/src/bundles/Elsa.ServerAndStudio.Web/appsettings.json b/src/bundles/Elsa.ServerAndStudio.Web/appsettings.json
index 6a427b4da..4f0c9d1bc 100644
--- a/src/bundles/Elsa.ServerAndStudio.Web/appsettings.json
+++ b/src/bundles/Elsa.ServerAndStudio.Web/appsettings.json
@@ -13,7 +13,8 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
- "Sqlite": "Data Source=elsa.sqlite.db;Cache=Shared;"
+ "Sqlite": "Data Source=elsa.sqlite.db;Cache=Shared;",
+ "RabbitMq": "rabbitmq://guest:guest@localhost:5672"
},
"Hosting": {
"BasePath": ""
diff --git a/src/bundles/Elsa.Studio.Web/Elsa.Studio.Web.csproj b/src/bundles/Elsa.Studio.Web/Elsa.Studio.Web.csproj
index 3799baa6f..3964f9121 100644
--- a/src/bundles/Elsa.Studio.Web/Elsa.Studio.Web.csproj
+++ b/src/bundles/Elsa.Studio.Web/Elsa.Studio.Web.csproj
@@ -21,8 +21,8 @@
-
-
+
+
diff --git a/src/bundles/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj b/src/bundles/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj
index f58d34aae..2da3d44eb 100644
--- a/src/bundles/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj
+++ b/src/bundles/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj
@@ -19,9 +19,9 @@
-
-
-
+
+
+
diff --git a/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs b/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs
index 2663488ad..6ae48eab8 100644
--- a/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs
+++ b/src/clients/Elsa.Api.Client/Extensions/ActivityExtensions.cs
@@ -145,11 +145,26 @@ public static class ActivityExtensions
/// Sets the root activity in the specified activity.
///
public static void SetRoot(this JsonObject container, JsonObject root) => container.SetProperty(root, "root");
-
+
///
/// Gets the root activity in the specified activity.
///
- public static string? GetWorkflowDefinitionId(this JsonObject activity) => activity.GetProperty("workflowDefinitionId");
+ public static string? GetWorkflowDefinitionId(this JsonObject activity)
+ {
+ // Determine if this activity represents a workflow definition activity based on the presence of the following properties.
+ var workflowDefinitionIdNode = activity.GetProperty("workflowDefinitionId");
+ var workflowDefinitionVersionId = activity.GetProperty("workflowDefinitionVersionId");
+ var latestAvailablePublishedVersion = activity.GetProperty("latestAvailablePublishedVersion");
+ var latestAvailablePublishedVersionId = activity.GetProperty("latestAvailablePublishedVersionId");
+
+ if (workflowDefinitionIdNode == null || workflowDefinitionVersionId == null || latestAvailablePublishedVersion == null || latestAvailablePublishedVersionId == null)
+ return null; // Not a workflow definition activity.
+
+ if (workflowDefinitionIdNode is JsonValue value)
+ return value.ToString();
+
+ return null; // Not a workflow definition activity.
+ }
///
/// Determines whether the given activity is a workflow definition activity.
@@ -157,7 +172,7 @@ public static class ActivityExtensions
/// The JsonObject representing the activity.
/// Returns true if the activity is a workflow definition activity; otherwise, false.
public static bool GetIsWorkflowDefinitionActivity(this JsonObject activity) => activity.ContainsKey("workflowDefinitionId") && activity.ContainsKey("workflowDefinitionVersionId");
-
+
///
/// Gets a value indicating whether the specified activity can trigger the workflow.
///
diff --git a/src/modules/Elsa.Alterations/AlterationHandlers/ScheduleActivityHandler.cs b/src/modules/Elsa.Alterations/AlterationHandlers/ScheduleActivityHandler.cs
index 43a05acb1..727267988 100644
--- a/src/modules/Elsa.Alterations/AlterationHandlers/ScheduleActivityHandler.cs
+++ b/src/modules/Elsa.Alterations/AlterationHandlers/ScheduleActivityHandler.cs
@@ -28,7 +28,7 @@ public class ScheduleActivityHandler : AlterationHandlerBase
{
// If the activity is in a faulted state, reset it to Running.
if (existingActivityExecutionContext.Status == ActivityStatus.Faulted)
- existingActivityExecutionContext.Status = ActivityStatus.Running;
+ existingActivityExecutionContext.TransitionTo(ActivityStatus.Running);
// Schedule the activity execution context.
var parentContext = existingActivityExecutionContext.ParentActivityExecutionContext;
diff --git a/src/modules/Elsa.Dapper/Elsa.Dapper.csproj b/src/modules/Elsa.Dapper/Elsa.Dapper.csproj
index 6f25c445b..714945f04 100644
--- a/src/modules/Elsa.Dapper/Elsa.Dapper.csproj
+++ b/src/modules/Elsa.Dapper/Elsa.Dapper.csproj
@@ -32,7 +32,7 @@
-
+
diff --git a/src/modules/Elsa.Http/Activities/HttpEndpoint.cs b/src/modules/Elsa.Http/Activities/HttpEndpoint.cs
index 1fdd7b0a1..6630d693b 100644
--- a/src/modules/Elsa.Http/Activities/HttpEndpoint.cs
+++ b/src/modules/Elsa.Http/Activities/HttpEndpoint.cs
@@ -211,8 +211,8 @@ public class HttpEndpoint : Trigger
var routeData = GetRouteData(httpContext, path);
var routeDictionary = routeData.Values.ToDictionary(route => route.Key, route => route.Value!);
- var queryStringDictionary = httpContext.Request.Query.ToDictionary, string, object>(queryString => queryString.Key, queryString => queryString.Value[0]!);
- var headersDictionary = httpContext.Request.Headers.ToDictionary, string, object>(header => header.Key, header => header.Value[0]!);
+ var queryStringDictionary = httpContext.Request.Query.ToObjectDictionary();
+ var headersDictionary = httpContext.Request.Headers.ToObjectDictionary();
context.Set(RouteData, routeDictionary);
context.Set(QueryStringData, queryStringDictionary);
@@ -225,48 +225,60 @@ public class HttpEndpoint : Trigger
return;
}
- // Read content, if any.
- try
+ // Handle Form Fields
+ if (request.HasFormContentType)
{
- var content = await ParseContentAsync(context, request);
- ParsedContent.Set(context, content);
+
+ var formFields = request.Form.ToObjectDictionary();
+
+ ParsedContent.Set(context, formFields);
+
+ // Read files, if any.
+ var files = ReadFilesAsync(context, request);
+
+ if (files.Any())
+ {
+ if (!ValidateFileSizes(context, httpContext, files))
+ {
+ await HandleFileSizeTooLargeAsync(context, httpContext);
+ return;
+ }
+
+ if (!ValidateFileExtensionWhitelist(context, httpContext, files))
+ {
+ await HandleInvalidFileExtensionWhitelistAsync(context, httpContext);
+ return;
+ }
+
+ if (!ValidateFileExtensionBlacklist(context, httpContext, files))
+ {
+ await HandleInvalidFileExtensionBlacklistAsync(context, httpContext);
+ return;
+ }
+
+ if (!ValidateFileMimeTypes(context, httpContext, files))
+ {
+ await HandleInvalidFileMimeTypesAsync(context, httpContext);
+ return;
+ }
+
+ Files.Set(context, files.ToArray());
+ }
}
- catch (JsonException e)
+ else
{
- await HandleInvalidJsonPayloadAsync(context, httpContext, e);
- throw;
- }
-
- // Read files, if any.
- var files = ReadFilesAsync(context, request);
-
- if (files.Any())
- {
- if (!ValidateFileSizes(context, httpContext, files))
+ // Parse Non-Form content.
+ try
{
- await HandleFileSizeTooLargeAsync(context, httpContext);
- return;
+ var content = await ParseContentAsync(context, request);
+ ParsedContent.Set(context, content);
+ }
+ catch (JsonException e)
+ {
+ await HandleInvalidJsonPayloadAsync(context, httpContext, e);
+ throw;
}
- if (!ValidateFileExtensionWhitelist(context, httpContext, files))
- {
- await HandleInvalidFileExtensionWhitelistAsync(context, httpContext);
- return;
- }
-
- if (!ValidateFileExtensionBlacklist(context, httpContext, files))
- {
- await HandleInvalidFileExtensionBlacklistAsync(context, httpContext);
- return;
- }
-
- if (!ValidateFileMimeTypes(context, httpContext, files))
- {
- await HandleInvalidFileMimeTypesAsync(context, httpContext);
- return;
- }
-
- Files.Set(context, files.ToArray());
}
// Complete.
diff --git a/src/modules/Elsa.Http/Extensions/StringValueExtensions.cs b/src/modules/Elsa.Http/Extensions/StringValueExtensions.cs
new file mode 100644
index 000000000..3b7948c1e
--- /dev/null
+++ b/src/modules/Elsa.Http/Extensions/StringValueExtensions.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.Primitives;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Elsa.Extensions;
+
+///
+/// Contains extension methods for the Enumerable dictonaries.
+///
+public static class StringValueExtensions
+{
+ ///
+ /// Convert the collection to the desired dictionary type.
+ ///
+ ///
+ ///
+ public static Dictionary ToObjectDictionary(this IEnumerable> collection)
+ {
+ return collection.ToDictionary, string, object>(
+ item => item.Key,
+ item => item.Value.Count <= 1 ?
+ item.Value[0]!
+ : item.Value.ToArray());
+ }
+}
diff --git a/src/modules/Elsa.Http/Features/HttpFeature.cs b/src/modules/Elsa.Http/Features/HttpFeature.cs
index 796eddc66..ece6c375c 100644
--- a/src/modules/Elsa.Http/Features/HttpFeature.cs
+++ b/src/modules/Elsa.Http/Features/HttpFeature.cs
@@ -158,12 +158,10 @@ public class HttpFeature : FeatureBase
.AddRequestHandler()
.AddNotificationHandler()
- // Content parsers.
- .AddScoped()
- .AddScoped()
- .AddScoped()
- .AddScoped()
-
+ // Content parsers.
+ .AddSingleton()
+ .AddSingleton()
+
// HTTP content factories.
.AddScoped()
.AddScoped()
diff --git a/src/modules/Elsa.Http/Parsers/FormHttpContentParser.cs b/src/modules/Elsa.Http/Parsers/FormHttpContentParser.cs
deleted file mode 100644
index 315ccc01b..000000000
--- a/src/modules/Elsa.Http/Parsers/FormHttpContentParser.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Xml.Serialization;
-using Elsa.Extensions;
-using Elsa.Http.Contracts;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.WebUtilities;
-using Microsoft.Extensions.Primitives;
-
-namespace Elsa.Http.Parsers;
-
-///
-/// Reads application/xml and text/xml content type streams.
-///
-public class FormHttpContentParser : IHttpContentParser
-{
- ///
- public int Priority => 0;
-
- ///
- public bool GetSupportsContentType(string contentType) => contentType.StartsWith("application/x-www-form-urlencoded", StringComparison.InvariantCultureIgnoreCase);
-
- ///
- public async Task