Add dynamic activity provider sample project

This commit is contained in:
Sipke Schoorstra 2023-07-13 16:24:34 +02:00
parent 78f01f267b
commit 94904160a9
16 changed files with 648 additions and 0 deletions

View file

@ -230,6 +230,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.MongoDb
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Workflows.Api.Rpc", "src\modules\Elsa.Workflows.Api.Rpc\Elsa.Workflows.Api.Rpc.csproj", "{0A94D69A-61AC-4654-83AB-B24445628A99}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.AspNet.DynamicActivityProvider", "src\samples\aspnet\Elsa.Samples.AspNet.DynamicActivityProvider\Elsa.Samples.AspNet.DynamicActivityProvider.csproj", "{85E13383-7C39-4719-AAC0-0B357C3A97C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -576,6 +578,10 @@ Global
{0A94D69A-61AC-4654-83AB-B24445628A99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A94D69A-61AC-4654-83AB-B24445628A99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A94D69A-61AC-4654-83AB-B24445628A99}.Release|Any CPU.Build.0 = Release|Any CPU
{85E13383-7C39-4719-AAC0-0B357C3A97C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85E13383-7C39-4719-AAC0-0B357C3A97C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85E13383-7C39-4719-AAC0-0B357C3A97C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85E13383-7C39-4719-AAC0-0B357C3A97C7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{155227F0-A33B-40AA-A4B4-06F813EB921B} = {61017E64-6D00-49CB-9E81-5002DC8F7D5F}
@ -680,5 +686,6 @@ Global
{3A377A6A-F735-4010-9E00-72E8BEB8F1F2} = {9B4F139F-7D26-435C-A561-89E65A67A8E5}
{DAACE93A-866E-428E-B2A9-AFAC79F9C7A4} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5}
{0A94D69A-61AC-4654-83AB-B24445628A99} = {B08B4E00-C2AB-48F3-8389-449F42AEF179}
{85E13383-7C39-4719-AAC0-0B357C3A97C7} = {56C2FFB8-EA54-45B5-A095-4A78142EB4B5}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,161 @@
using System.Text;
using System.Text.Json;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Http;
using Elsa.Samples.AspNet.DynamicActivityProvider.Models;
using Elsa.Workflows.Core;
using Elsa.Workflows.Core.Contracts;
using Elsa.Workflows.Core.Models;
using Elsa.Workflows.Management.Extensions;
using Humanizer;
namespace Elsa.Samples.AspNet.DynamicActivityProvider.ActivityProviders;
/// <summary>
/// Provides activities based on API descriptions (see /Data/apis.json).
/// </summary>
public class ApiActivityProvider : IActivityProvider
{
private readonly IActivityFactory _activityFactory;
private readonly IActivityDescriber _activityDescriber;
public ApiActivityProvider(IActivityFactory activityFactory, IActivityDescriber activityDescriber)
{
_activityFactory = activityFactory;
_activityDescriber = activityDescriber;
}
public async ValueTask<IEnumerable<ActivityDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default)
{
// Read JSON file.
var json = await File.ReadAllTextAsync("Data/apis.json", cancellationToken);
// Parse JSON into a list of API definitions.
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
var apisDefinitions = JsonSerializer.Deserialize<ApiDefinition[]>(json, options)!;
// Create activity descriptors from API definitions.
var activities = ((await Task.WhenAll(apisDefinitions.Select(async x => await CreateActivityDescriptors(x, cancellationToken)))).SelectMany(x => x)).ToList();
// Return activity descriptors.
return activities;
}
/// <summary>
/// Creates activity descriptors from an API definition's endpoints.
/// </summary>
/// <param name="api">The API definition containing the endpoints.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
/// <returns>A list of activity descriptors.</returns>
private async Task<IEnumerable<ActivityDescriptor>> CreateActivityDescriptors(ApiDefinition api, CancellationToken cancellationToken = default)
{
var descriptorTasks = api.Endpoints.Select(async endpoint => await CreateActivityDescriptorFromEndpointAsync(api, endpoint, cancellationToken)).ToList();
return await Task.WhenAll(descriptorTasks);
}
private async Task<ActivityDescriptor> CreateActivityDescriptorFromEndpointAsync(ApiDefinition api, ApiEndpointDefinition endpoint, CancellationToken cancellationToken = default)
{
// Create a fully qualified type name for the activity ("{namespace}.{apiName}.{endpointName}").
var fullTypeName = $"Demo.{api.Name}.{endpoint.Name}";
// ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract
// Justification: the JSON input may not have a parameters property.
var parameters = endpoint.Parameters ?? new List<ApiParameterDefinition>();
// Create inputs from endpoint parameters.
var inputs = parameters.Select(CreateInputDescriptor).ToList();
// Create inputs for the URL and method properties of the SendHttpRequest activity, which will be used as the implementation for executing instances of this activity.
// They are set in the constructor, and should not be visible to the user.
var urlInputDescriptor = await _activityDescriber.DescribeInputPropertyAsync<SendHttpRequest, Input<Uri?>>(x => x.Url, cancellationToken);
var urlInputReferenceId = Guid.NewGuid().ToString();
var methodInputDescriptor = await _activityDescriber.DescribeInputPropertyAsync<SendHttpRequest, Input<string>>(x => x.Method, cancellationToken);
var methodInputReferenceId = Guid.NewGuid().ToString();
urlInputDescriptor.IsBrowsable = false;
urlInputDescriptor.ValueGetter = activity =>
{
var input = new Input<Uri>(context =>
{
// Replace path parameters with input values.
var pathBuilder = new StringBuilder(endpoint.Path);
foreach (var parameter in parameters)
{
var inputDescriptor = inputs.FirstOrDefault(x => x.Name == parameter.Name);
var inputValue = inputDescriptor?.ValueGetter(activity) is Input inputValueInput ? context.Get(inputValueInput.MemoryBlockReference()) : default;
pathBuilder.Replace("{" + parameter.Name + "}", inputValue?.ToString());
}
return new(new Uri(api.BaseUrl, pathBuilder.ToString()));
}, urlInputReferenceId);
return input;
};
methodInputDescriptor.IsBrowsable = false;
methodInputDescriptor.ValueGetter = _ => new Input<string>(endpoint.Method, methodInputReferenceId);
inputs.Add(urlInputDescriptor);
inputs.Add(methodInputDescriptor);
// Create an output descriptor based on the send HTTP request activity's ParsedContent property.
var outputDescriptor = await _activityDescriber.DescribeOutputProperty<SendHttpRequest, Output<object?>>(x => x.ParsedContent, cancellationToken);
return new ActivityDescriptor
{
Kind = ActivityKind.Task,
Category = "Demo",
Description = endpoint.Description,
Name = endpoint.Name,
TypeName = fullTypeName,
Namespace = $"Api.{api.Name}",
DisplayName = endpoint.Name.Humanize(),
Inputs = inputs,
Outputs = new[] { outputDescriptor },
Constructor = context =>
{
// The constructor is called when an activity instance of this type is requested.
// Create the activity instance.
var activity = _activityFactory.Create<SendHttpRequest>(context);
// Customize the activity type name.
activity.Type = fullTypeName;
// Configure the activity's URL and method properties.
activity.Url = new Input<Uri?>(new ReadReference(urlInputReferenceId));
activity.Method = new(new ReadReference(methodInputReferenceId));
return activity;
}
};
}
/// <summary>
/// Creates an input descriptor from an API parameter definition.
/// </summary>
/// <param name="parameter">The API parameter definition.</param>
private static InputDescriptor CreateInputDescriptor(ApiParameterDefinition parameter)
{
var inputDescriptor = new InputDescriptor
{
Description = parameter.Description,
DefaultValue = parameter.DefaultValue,
Type = parameter.Type == "number" ? typeof(int) : typeof(string),
Name = parameter.Name,
DisplayName = parameter.Name.Humanize(),
IsSynthetic = true, // This is a synthetic property, i.e. it is not part of the activity's .NET type.
IsWrapped = true, // This property is wrapped within an Input<T> object.
UIHint = InputUIHints.SingleLine,
ValueGetter = activity => activity.SyntheticProperties.GetValueOrDefault(parameter.Name),
ValueSetter = (activity, value) => activity.SyntheticProperties[parameter.Name] = value!,
};
return inputDescriptor;
}
}

View file

@ -0,0 +1,43 @@
[{
"name": "Reqres",
"baseUrl": "https://reqres.in",
"endpoints": [
{
"name": "GetUsers",
"path": "/api/users",
"method": "GET",
"description": "Get all users"
},
{
"name": "GetUser",
"path": "/api/users/{UserId}",
"method": "GET",
"description": "Get a user",
"params": [
{
"name": "UserId",
"type": "number",
"description": "User id"
}
]
},
{
"name": "CreateUser",
"path": "/api/users",
"method": "POST",
"description": "Create a user",
"params": [
{
"name": "UserName",
"type": "string",
"description": "User name"
},
{
"name": "Job",
"type": "string",
"description": "User job"
}
]
}
]
}]

View file

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\bundles\Elsa\Elsa.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.Http\Elsa.Http.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.Identity\Elsa.Identity.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.JavaScript\Elsa.JavaScript.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.Liquid\Elsa.Liquid.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.EntityFrameworkCore.Sqlite\Elsa.EntityFrameworkCore.Sqlite.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.EntityFrameworkCore\Elsa.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\modules\Elsa.Workflows.Api\Elsa.Workflows.Api.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="Data\apis.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="Workflows\" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,3 @@
namespace Elsa.Samples.AspNet.DynamicActivityProvider.Models;
public record ApiDefinition(string Name, Uri BaseUrl, ICollection<ApiEndpointDefinition> Endpoints);

View file

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace Elsa.Samples.AspNet.DynamicActivityProvider.Models;
public record ApiEndpointDefinition(
string Name,
string Description,
string Path,
string Method,
[property: JsonPropertyName("params")] ICollection<ApiParameterDefinition> Parameters);

View file

@ -0,0 +1,3 @@
namespace Elsa.Samples.AspNet.DynamicActivityProvider.Models;
public record ApiParameterDefinition(string Name, string Type, string Description, string? DefaultValue);

View file

@ -0,0 +1,54 @@
using Elsa.EntityFrameworkCore.Modules.Identity;
using Elsa.EntityFrameworkCore.Modules.Management;
using Elsa.EntityFrameworkCore.Modules.Runtime;
using Elsa.Extensions;
using Elsa.Samples.AspNet.DynamicActivityProvider.ActivityProviders;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
// Add Elsa services.
services.AddElsa(elsa => elsa
// Expose API endpoints.
.UseWorkflowsApi()
.UseWorkflowManagement(management => management.UseEntityFrameworkCore())
.UseWorkflowRuntime(runtime => runtime.UseEntityFrameworkCore())
// Configure identity so that we can create a default admin user.
.UseIdentity(identity =>
{
identity.UseAdminUserProvider();
identity.UseEntityFrameworkCore();
identity.TokenOptions = options =>
{
options.SigningKey = "secret-token-signing-key";
options.AccessTokenLifetime = TimeSpan.FromDays(1);
};
})
// HTTP workflows.
.UseHttp()
// Use default authentication (JWT).
.UseDefaultAuthentication(auth => auth.UseAdminApiKey())
);
// Add custom activity provider.
services.AddActivityProvider<ApiActivityProvider>();
services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
// Configure middleware pipeline.
var app = builder.Build();
if (app.Environment.IsDevelopment())
app.UseDeveloperExceptionPage();
// Configure the HTTP request pipeline.
app.UseAuthentication();
app.UseAuthorization();
app.UseCors();
app.UseWorkflowsApi();
app.UseWorkflows();
app.Run();

View file

@ -0,0 +1,37 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:41572",
"sslPort": 44398
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5015",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7145;http://localhost:5015",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View file

@ -0,0 +1,28 @@
# Dynamic Activity Providers
This sample project demonstrates how to implement a dynamic activity provider.
## Overview
The key to providing activities dynamically to the activity registry is to implement the `IActivityProvider` interface. This interface defines a single method, `GetDescriptorsAsync`, which returns a list of activity descriptors.
In this example, we are loading API endpoint definitions from a JSON file located in the `Data` folder and create an activity descriptor for each endpoint.
The activity descriptor is then used to create an activity type, which is then registered with the activity registry.
This example could be applied to any other data source, such as a database or a web service, Open API specifications, GraphQL, etc.
## Usage
1. Run the sample project.
2. Open the workflow editor.
3. Notice the new activities in the toolbox.
4. Drag one of the new activities onto the canvas.
5. Notice the new activity in the canvas.
6. Run the workflow.
7. Notice the new activity being executed.
## Notes
This project provides sample workflows that you can import into the workflow editor. The workflows are located in the `Workflows` folder.
You can then use the workflow editor to inspect the workflows and see how the activities are used.
When imported, you can invoke the workflows using the sample-request.http file located in the root folder containing this project.

View file

@ -0,0 +1,236 @@
{
"id": "0ad67e344f664e4ba40430933db6383d",
"definitionId": "2a29bd086ba047ad82c296f380b2b21d",
"name": "Create User",
"createdAt": "2023-07-13T14:06:07.932781+00:00",
"version": 9,
"variables": [],
"inputs": [],
"outputs": [],
"outcomes": [],
"customProperties": {},
"isReadonly": false,
"isLatest": true,
"isPublished": true,
"options": {
"autoUpdateConsumingWorkflows": false
},
"root": {
"type": "Elsa.Flowchart",
"version": 1,
"id": "Flowchart1",
"metadata": {},
"customProperties": {
"NotFoundConnectionsKey": [],
"canStartWorkflow": false,
"runAsynchronously": false
},
"start": "HttpEndpoint1",
"activities": [
{
"path": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "/users"
},
"memoryReference": {
"id": "540fb073-7da0-40e4-affd-7d12b83bd41b"
}
},
"supportedMethods": {
"typeName": "String[]",
"expression": {
"type": "Object",
"value": "[\u0022POST\u0022]"
},
"memoryReference": {
"id": "cd84bc03-5395-449b-96eb-27d5ad17ca53"
}
},
"authorize": {
"typeName": "Boolean",
"expression": {
"type": "Literal",
"value": "False"
},
"memoryReference": {
"id": "HttpEndpoint1:input-1"
}
},
"policy": null,
"parsedContent": {
"typeName": "Object",
"memoryReference": {
"id": "0a9e4d85af2149119068e324e3e61e32"
}
},
"routeData": null,
"queryStringData": null,
"headers": null,
"result": null,
"id": "HttpEndpoint1",
"name": null,
"type": "Elsa.HttpEndpoint",
"version": 1,
"customProperties": {
"canStartWorkflow": true,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 120,
"y": 260
}
}
}
},
{
"statusCode": {
"typeName": "System.Net.HttpStatusCode, System.Net.Primitives",
"expression": {
"type": "Literal",
"value": "OK"
},
"memoryReference": {
"id": "WriteHttpResponse1:input-1"
}
},
"content": {
"typeName": "Object",
"expression": {
"type": "JavaScript",
"value": "getParsedContentFromCreateUser1()"
},
"memoryReference": {
"id": "457df76f-3bdd-4e7e-ba8a-10ebed80281d"
}
},
"contentType": {
"typeName": "String",
"expression": {
"type": "Literal",
"value": "application/json"
},
"memoryReference": {
"id": "4673dc8b-e2ee-48c2-8b7a-5c3e2c3a7560"
}
},
"responseHeaders": {
"typeName": "Elsa.Http.Models.HttpResponseHeaders, Elsa.Http",
"expression": {
"type": "Literal",
"value": "{}"
},
"memoryReference": {
"id": "WriteHttpResponse1:input-2"
}
},
"id": "WriteHttpResponse1",
"name": null,
"type": "Elsa.WriteHttpResponse",
"version": 1,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 640,
"y": 260
}
}
}
},
{
"expectedStatusCodes": [],
"unmatchedStatusCode": null,
"url": {
"typeName": "System.Uri, System.Private.Uri",
"memoryReference": {
"id": "44cb8368-b578-4b02-beb7-cbac55359ab6"
}
},
"method": {
"typeName": "String",
"memoryReference": {
"id": "d39ebcb9-8943-4d76-8299-7761aef1f8e3"
}
},
"content": null,
"contentType": null,
"authorization": null,
"requestHeaders": {
"typeName": "Elsa.Http.Models.HttpRequestHeaders, Elsa.Http",
"expression": {
"type": "Literal",
"value": "{}"
},
"memoryReference": {}
},
"parsedContent": null,
"result": null,
"id": "CreateUser1",
"name": null,
"type": "Demo.Reqres.CreateUser",
"version": 0,
"customProperties": {
"canStartWorkflow": false,
"runAsynchronously": false
},
"metadata": {
"designer": {
"position": {
"x": 428,
"y": 255
}
}
},
"userName": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "getParsedContentFromHttpEndpoint1().user;"
},
"memoryReference": {
"id": "14ebd00e-bd1a-4953-a933-d49439ed418c"
}
},
"job": {
"typeName": "String",
"expression": {
"type": "JavaScript",
"value": "getParsedContentFromHttpEndpoint1().job;"
},
"memoryReference": {
"id": "e92af470-3d83-4891-96b4-e83331d0896e"
}
}
}
],
"connections": [
{
"source": {
"activity": "HttpEndpoint1",
"port": "Done"
},
"target": {
"activity": "CreateUser1",
"port": "In"
}
},
{
"source": {
"activity": "CreateUser1",
"port": "Done"
},
"target": {
"activity": "WriteHttpResponse1",
"port": "In"
}
}
]
}
}

View file

@ -0,0 +1 @@
{"id":"906cd28a12454b06b71bb724cd5891d0","definitionId":"4b3bbe91862c42ba921e21f70b429d8e","name":"Get Users","createdAt":"2023-07-13T14:02:19.276895+00:00","version":20,"variables":[{"id":"c4c6fbc0926f40d7a93e61eb7668b40b","name":"Users","typeName":"Object","isArray":true,"storageDriverTypeName":"Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core"}],"inputs":[],"outputs":[],"outcomes":[],"customProperties":{},"isReadonly":false,"isLatest":true,"isPublished":false,"options":{"autoUpdateConsumingWorkflows":false},"root":{"type":"Elsa.Flowchart","version":1,"id":"Flowchart1","metadata":{},"customProperties":{"NotFoundConnectionsKey":[],"canStartWorkflow":false,"runAsynchronously":false},"start":"HttpEndpoint1","activities":[{"path":{"typeName":"String","expression":{"type":"Literal","value":"users/all"},"memoryReference":{"id":"6f30b933-ed1c-47fb-9d13-7b50f425e806"}},"supportedMethods":{"typeName":"String[]","expression":{"type":"Object","value":"[\u0022GET\u0022]"},"memoryReference":{"id":"d7ee590e-02b4-485d-8730-cc8656c55a99"}},"authorize":{"typeName":"Boolean","expression":{"type":"Literal","value":"False"},"memoryReference":{"id":"HttpEndpoint1:input-1"}},"policy":{"typeName":"String","expression":{"type":"Literal"},"memoryReference":{"id":"HttpEndpoint1:input-2"}},"parsedContent":null,"routeData":null,"queryStringData":null,"headers":null,"result":null,"id":"HttpEndpoint1","name":null,"type":"Elsa.HttpEndpoint","version":1,"customProperties":{"canStartWorkflow":true,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":120,"y":260}}}},{"statusCode":{"typeName":"System.Net.HttpStatusCode, System.Net.Primitives","expression":{"type":"Literal","value":"OK"},"memoryReference":{"id":"WriteHttpResponse1:input-1"}},"content":{"typeName":"Object","expression":{"type":"JavaScript","value":"const users = getUsers();\nreturn users;"},"memoryReference":{"id":"09552413-74b1-4156-86a3-6679feeec83e"}},"contentType":{"typeName":"String","expression":{"type":"Literal","value":"application/json"},"memoryReference":{"id":"a7b8ff37-34a3-4400-88b2-026f19de8901"}},"responseHeaders":{"typeName":"Elsa.Http.Models.HttpResponseHeaders, Elsa.Http","expression":{"type":"Literal","value":"{}"},"memoryReference":{"id":"WriteHttpResponse1:input-2"}},"id":"WriteHttpResponse1","name":null,"type":"Elsa.WriteHttpResponse","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":920,"y":260}}}},{"variable":{"id":"c4c6fbc0926f40d7a93e61eb7668b40b","name":"Users","typeName":"Object","value":"","storageDriverTypeName":"Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core"},"value":{"typeName":"Object","expression":{"type":"JavaScript","value":"getParsedContentFromGetUsers1()"},"memoryReference":{"id":"b1f4ed34-25d8-42f4-a59b-03541b11bfa6"}},"id":"SetVariable1","name":null,"type":"Elsa.SetVariable","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":660,"y":260}},"displayText":"Set Users"}},{"expectedStatusCodes":[],"unmatchedStatusCode":null,"url":{"typeName":"System.Uri, System.Private.Uri","memoryReference":{"id":"9ba5ad9b-b88a-45de-8e08-aec043e22a10"}},"method":{"typeName":"String","memoryReference":{"id":"ab690185-cda3-44e6-8aaa-bb1c2a2e7941"}},"content":null,"contentType":null,"authorization":null,"requestHeaders":{"typeName":"Elsa.Http.Models.HttpRequestHeaders, Elsa.Http","expression":{"type":"Literal","value":"{}"},"memoryReference":{}},"parsedContent":null,"result":null,"id":"GetUsers1","name":null,"type":"Demo.Reqres.GetUsers","version":0,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":460,"y":260}}}}],"connections":[{"source":{"activity":"HttpEndpoint1","port":"Done"},"target":{"activity":"GetUsers1","port":"In"}},{"source":{"activity":"SetVariable1","port":"Done"},"target":{"activity":"WriteHttpResponse1","port":"In"}},{"source":{"activity":"GetUsers1","port":"Done"},"target":{"activity":"SetVariable1","port":"In"}}]}}

View file

@ -0,0 +1 @@
{"id":"cfd60b01f85148b29e99b72d8c91754f","definitionId":"91390522c8674589bf9383e9c8e05447","name":"Get User","createdAt":"2023-07-13T14:10:52.554187+00:00","version":9,"variables":[{"id":"be5481f1f8f64df39012282404fbe7c7","name":"User","typeName":"Object","isArray":false,"value":"","storageDriverTypeName":"Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core"},{"id":"abd12e6b760840e38e7e79e8430d33db","name":"UserId","typeName":"Int32","isArray":false,"value":"0","storageDriverTypeName":"Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core"}],"inputs":[],"outputs":[],"outcomes":[],"customProperties":{},"isReadonly":false,"isLatest":true,"isPublished":true,"options":{"autoUpdateConsumingWorkflows":false},"root":{"type":"Elsa.Flowchart","version":1,"id":"Flowchart1","metadata":{},"customProperties":{"NotFoundConnectionsKey":[],"canStartWorkflow":false,"runAsynchronously":false},"start":"HttpEndpoint1","activities":[{"path":{"typeName":"String","expression":{"type":"Literal","value":"users/{userId}"},"memoryReference":{"id":"36cc8af8-3b83-49fd-aca2-1b8ba40583e8"}},"supportedMethods":{"typeName":"String[]","expression":{"type":"Object","value":"[\u0022GET\u0022]"},"memoryReference":{"id":"7389a64a-0fdb-4b8b-af55-72bad1eb72c9"}},"authorize":{"typeName":"Boolean","expression":{"type":"Literal","value":"False"},"memoryReference":{"id":"HttpEndpoint1:input-1"}},"policy":null,"parsedContent":null,"routeData":{"typeName":"ObjectDictionary","memoryReference":{"id":"ed6d5b4f6e794477837ee29e746e8ccb"}},"queryStringData":null,"headers":null,"result":null,"id":"HttpEndpoint1","name":null,"type":"Elsa.HttpEndpoint","version":1,"customProperties":{"canStartWorkflow":true,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":260,"y":220}}}},{"variable":{"id":"abd12e6b760840e38e7e79e8430d33db","name":"UserId","typeName":"Int32","value":"0","storageDriverTypeName":"Elsa.Workflows.Core.Services.WorkflowStorageDriver, Elsa.Workflows.Core"},"value":{"typeName":"Object","expression":{"type":"JavaScript","value":"getRouteDataFromHttpEndpoint1()[\u0022userid\u0022]"},"memoryReference":{"id":"4ae05d95-e23f-4158-b53f-1043728d2ad1"}},"id":"SetVariable1","name":null,"type":"Elsa.SetVariable","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":520,"y":220}},"displayText":"Set UserId"}},{"expectedStatusCodes":[],"unmatchedStatusCode":null,"url":{"typeName":"System.Uri, System.Private.Uri","memoryReference":{"id":"31406d9b-528a-4149-aed6-4dacfd6d566a"}},"method":{"typeName":"String","memoryReference":{"id":"91cbdddc-1df1-42ed-b63a-8ed7cfae115a"}},"content":null,"contentType":null,"authorization":null,"requestHeaders":{"typeName":"Elsa.Http.Models.HttpRequestHeaders, Elsa.Http","expression":{"type":"Literal","value":"{}"},"memoryReference":{}},"parsedContent":{"typeName":"Object","memoryReference":{"id":"be5481f1f8f64df39012282404fbe7c7"}},"result":null,"id":"GetUser1","name":null,"type":"Demo.Reqres.GetUser","version":0,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":760,"y":220}}},"userId":{"typeName":"Int32","expression":{"type":"JavaScript","value":"getUserId()"},"memoryReference":{"id":"66cf67ac-5c36-48cd-8a3a-d24fb831e1b0"}}},{"statusCode":{"typeName":"System.Net.HttpStatusCode, System.Net.Primitives","expression":{"type":"Literal","value":"OK"},"memoryReference":{"id":"WriteHttpResponse1:input-1"}},"content":{"typeName":"Object","expression":{"type":"JavaScript","value":"getUser()"},"memoryReference":{"id":"36f78ecf-9b4c-4245-b1af-a44d9730b52e"}},"contentType":{"typeName":"String","expression":{"type":"Literal","value":"application/json"},"memoryReference":{"id":"5146a788-d413-4ea4-9ac7-99fcf717bb33"}},"responseHeaders":{"typeName":"Elsa.Http.Models.HttpResponseHeaders, Elsa.Http","expression":{"type":"Literal","value":"{}"},"memoryReference":{"id":"WriteHttpResponse1:input-2"}},"id":"WriteHttpResponse1","name":null,"type":"Elsa.WriteHttpResponse","version":1,"customProperties":{"canStartWorkflow":false,"runAsynchronously":false},"metadata":{"designer":{"position":{"x":940,"y":220}}}}],"connections":[{"source":{"activity":"HttpEndpoint1","port":"Done"},"target":{"activity":"SetVariable1","port":"In"}},{"source":{"activity":"SetVariable1","port":"Done"},"target":{"activity":"GetUser1","port":"In"}},{"source":{"activity":"GetUser1","port":"Done"},"target":{"activity":"WriteHttpResponse1","port":"In"}}]}}

View file

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View file

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View file

@ -0,0 +1,17 @@
### Create a new user
POST https://localhost:5001/workflows/users
Content-Type: application/json
Accept: application/json
{
"name": "Bob",
"job": "Postman"
}
### Get all users
GET https://localhost:5001/workflows/users/all
Accept: application/json
### Get a user
GET https://localhost:5001/workflows/users/2
Accept: application/json