Added MassTransit support (#46)
This commit is contained in:
parent
877674619d
commit
7cab475321
16
Elsa.sln
16
Elsa.sln
|
|
@ -27,7 +27,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Activities", "Activities",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.Email", "src\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj", "{D20FCB88-9DCA-49EA-9CC2-5B94DD935D30}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.Cron", "src\activities\Elsa.Activities.Cron\Elsa.Activities.Cron.csproj", "{E4B71DC4-3E73-49C3-9B4E-CA13909F222D}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.Timers", "src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj", "{E4B71DC4-3E73-49C3-9B4E-CA13909F222D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample01", "samples\Sample01\Sample01.csproj", "{92750B10-8DAF-4E4F-8999-33304034EDF4}"
|
||||
EndProject
|
||||
|
|
@ -45,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{2269
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample07", "samples\Sample07\Sample07.csproj", "{CC1012DE-511E-41A1-8714-3F1DFCA70BC6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Activities.MassTransit", "src\activities\Elsa.Activities.MassTransit\Elsa.Activities.MassTransit.csproj", "{C4939482-9447-47D1-B6AF-E9F8C6323841}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample08", "samples\Sample08\Sample08.csproj", "{0E58E5FA-BF2F-44CA-9AC8-E8B33CF6AAAA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -103,6 +107,14 @@ Global
|
|||
{CC1012DE-511E-41A1-8714-3F1DFCA70BC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC1012DE-511E-41A1-8714-3F1DFCA70BC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC1012DE-511E-41A1-8714-3F1DFCA70BC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C4939482-9447-47D1-B6AF-E9F8C6323841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C4939482-9447-47D1-B6AF-E9F8C6323841}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C4939482-9447-47D1-B6AF-E9F8C6323841}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C4939482-9447-47D1-B6AF-E9F8C6323841}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0E58E5FA-BF2F-44CA-9AC8-E8B33CF6AAAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E58E5FA-BF2F-44CA-9AC8-E8B33CF6AAAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E58E5FA-BF2F-44CA-9AC8-E8B33CF6AAAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E58E5FA-BF2F-44CA-9AC8-E8B33CF6AAAA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -123,6 +135,8 @@ Global
|
|||
{F48E32ED-4E85-4D03-8166-7E63E7AB1D6F} = {2269E8BE-894F-46BF-A767-1E0FD046F681}
|
||||
{484E698C-6CC1-4D30-879C-F333AD0D44DD} = {2269E8BE-894F-46BF-A767-1E0FD046F681}
|
||||
{CC1012DE-511E-41A1-8714-3F1DFCA70BC6} = {2269E8BE-894F-46BF-A767-1E0FD046F681}
|
||||
{C4939482-9447-47D1-B6AF-E9F8C6323841} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180}
|
||||
{0E58E5FA-BF2F-44CA-9AC8-E8B33CF6AAAA} = {2269E8BE-894F-46BF-A767-1E0FD046F681}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Sample01.Activities;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ using Elsa.Activities.Console.Activities;
|
|||
using Elsa.Activities.Console.Extensions;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Sample02
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ using Elsa.Activities.Console.Extensions;
|
|||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Serialization.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Sample03
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Threading.Tasks;
|
|||
using Elsa.Activities.Console.Extensions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Sample04.Activities;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Console.Extensions;
|
||||
using Elsa.Activities.Cron.Extensions;
|
||||
using Elsa.Activities.Timers.Extensions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Persistence.Extensions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -46,7 +45,7 @@ namespace Sample05
|
|||
services
|
||||
.AddWorkflows()
|
||||
.AddConsoleActivities()
|
||||
.AddCronActivities(options => options.Configure(x => x.SweepInterval = Period.FromSeconds(10)))
|
||||
.AddTimerActivities(options => options.Configure(x => x.SweepInterval = Period.FromSeconds(10)))
|
||||
.AddMemoryWorkflowDefinitionStore()
|
||||
.AddMemoryWorkflowInstanceStore();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using Elsa.Activities.Console.Activities;
|
||||
using Elsa.Activities.Cron.Activities;
|
||||
using Elsa.Activities.Timers.Activities;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
|
@ -13,7 +13,7 @@ namespace Sample05
|
|||
builder
|
||||
.WithId("RecurringWorkflow")
|
||||
.AsSingleton()
|
||||
.StartWith<CronTrigger>(x => x.CronExpression = new PlainTextExpression("* * * * *"))
|
||||
.StartWith<CronEvent>(x => x.CronExpression = new PlainTextExpression("* * * * *"))
|
||||
.Then<WriteLine>(x => x.TextExpression = new JavaScriptExpression<string>("`Trigger received. The time is: ${new Date().toISOString()}`"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Console\Elsa.Activities.Console.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Cron\Elsa.Activities.Cron.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
|
||||
<ProjectReference Include="..\..\src\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Cron\Elsa.Activities.Cron.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
|
||||
<ProjectReference Include="..\..\src\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using Elsa.Activities.Email.Activities;
|
|||
using Elsa.Activities.Http.Activities;
|
||||
using Elsa.Core.Activities.Primitives;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ namespace Sample07
|
|||
activity =>
|
||||
{
|
||||
activity.VariableName = "document";
|
||||
activity.ValueExpression = new JavaScriptExpression<object>("lastResult().FormattedContent");
|
||||
activity.ValueExpression = new JavaScriptExpression<object>("lastResult().ParsedContent");
|
||||
}
|
||||
)
|
||||
.Then<SendEmail>(
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Sample07
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Cron\Elsa.Activities.Cron.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
|
||||
<ProjectReference Include="..\..\src\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
9
samples/Sample08/Messages/CreateOrder.cs
Normal file
9
samples/Sample08/Messages/CreateOrder.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using Sample08.Models;
|
||||
|
||||
namespace Sample08.Messages
|
||||
{
|
||||
public class CreateOrder
|
||||
{
|
||||
public Order Order { get; set; }
|
||||
}
|
||||
}
|
||||
9
samples/Sample08/Messages/OrderShipped.cs
Normal file
9
samples/Sample08/Messages/OrderShipped.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using Sample08.Models;
|
||||
|
||||
namespace Sample08.Messages
|
||||
{
|
||||
public class OrderShipped
|
||||
{
|
||||
public Order Order { get; set; }
|
||||
}
|
||||
}
|
||||
8
samples/Sample08/Models/Customer.cs
Normal file
8
samples/Sample08/Models/Customer.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace Sample08.Models
|
||||
{
|
||||
public class Customer
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
10
samples/Sample08/Models/Order.cs
Normal file
10
samples/Sample08/Models/Order.cs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
namespace Sample08.Models
|
||||
{
|
||||
public class Order
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public Customer Customer { get; set; }
|
||||
public string Product { get; set; }
|
||||
public decimal Amount { get; set; }
|
||||
}
|
||||
}
|
||||
17
samples/Sample08/Program.cs
Normal file
17
samples/Sample08/Program.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace Sample08
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
||||
30
samples/Sample08/Properties/launchSettings.json
Normal file
30
samples/Sample08/Properties/launchSettings.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:32051",
|
||||
"sslPort": 44347
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "api/values",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Sample07": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "api/values",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
samples/Sample08/Sample08.csproj
Normal file
22
samples/Sample08/Sample08.csproj
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MassTransit.AspNetCore" Version="5.5.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Email\Elsa.Activities.Email.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Http\Elsa.Activities.Http.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.MassTransit\Elsa.Activities.MassTransit.csproj" />
|
||||
<ProjectReference Include="..\..\src\activities\Elsa.Activities.Timers\Elsa.Activities.Timers.csproj" />
|
||||
<ProjectReference Include="..\..\src\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
56
samples/Sample08/Startup.cs
Normal file
56
samples/Sample08/Startup.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
using Elsa.Activities.Email.Extensions;
|
||||
using Elsa.Activities.Http.Extensions;
|
||||
using Elsa.Activities.MassTransit.Extensions;
|
||||
using Elsa.Activities.Timers.Extensions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Persistence.Extensions;
|
||||
using Elsa.Services;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NodaTime;
|
||||
using Sample08.Messages;
|
||||
using Sample08.Workflows;
|
||||
using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment;
|
||||
|
||||
namespace Sample08
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services
|
||||
.AddWorkflows()
|
||||
.AddHttpActivities()
|
||||
.AddTimerActivities(options => options.Configure(x => x.SweepInterval = Period.FromSeconds(10)))
|
||||
.AddEmailActivities(options => options.Bind(Configuration.GetSection("Smtp")))
|
||||
.AddRabbitMqActivities(
|
||||
options => options.Bind(Configuration.GetSection("MassTransit:RabbitMq")),
|
||||
typeof(CreateOrder),
|
||||
typeof(OrderShipped))
|
||||
.AddMemoryWorkflowDefinitionStore()
|
||||
.AddMemoryWorkflowInstanceStore();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IWorkflowRegistry workflowRegistry)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseHttpActivities();
|
||||
|
||||
workflowRegistry.RegisterWorkflow<CreateOrderWorkflow>();
|
||||
workflowRegistry.RegisterWorkflow<HandleOrderWorkflow>();
|
||||
}
|
||||
}
|
||||
}
|
||||
74
samples/Sample08/Workflows/CreateOrderWorkflow.cs
Normal file
74
samples/Sample08/Workflows/CreateOrderWorkflow.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Elsa.Activities.Email.Activities;
|
||||
using Elsa.Activities.Http.Activities;
|
||||
using Elsa.Activities.MassTransit.Activities;
|
||||
using Elsa.Core.Activities.Primitives;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Sample08.Messages;
|
||||
|
||||
namespace Sample08.Workflows
|
||||
{
|
||||
public class CreateOrderWorkflow : IWorkflow
|
||||
{
|
||||
public void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder
|
||||
.StartWith<HttpRequestTrigger>(
|
||||
activity =>
|
||||
{
|
||||
activity.Method = HttpMethod.Post.Method;
|
||||
activity.Path = new Uri("/orders", UriKind.RelativeOrAbsolute);
|
||||
activity.ReadContent = true;
|
||||
}
|
||||
)
|
||||
.Then<SetVariable>(
|
||||
activity =>
|
||||
{
|
||||
activity.VariableName = "order";
|
||||
activity.ValueExpression = new JavaScriptExpression<object>("lastResult().ParsedContent");
|
||||
}
|
||||
)
|
||||
.Then<SendMassTransitMessage>(activity =>
|
||||
{
|
||||
activity.Message = new JavaScriptExpression<CreateOrder>("return {order: order};");
|
||||
activity.MessageType = typeof(CreateOrder);
|
||||
}
|
||||
)
|
||||
.Then<Fork>(
|
||||
activity => activity.Forks = new[] { "Write-Response", "Await-Shipment" },
|
||||
fork =>
|
||||
{
|
||||
fork
|
||||
.When("Write-Response")
|
||||
.Then<HttpResponseAction>(
|
||||
activity =>
|
||||
{
|
||||
activity.Body = new PlainTextExpression("<h1>Order Received</h1><p>Your order has been received. Waiting for shipment.</p>");
|
||||
activity.ContentType = new PlainTextExpression("text/html");
|
||||
activity.StatusCode = HttpStatusCode.Accepted;
|
||||
}
|
||||
);
|
||||
|
||||
fork
|
||||
.When("Await-Shipment")
|
||||
.Then<ReceiveMassTransitMessage>(activity => activity.MessageType = typeof(OrderShipped))
|
||||
.Then<SendEmail>(
|
||||
activity =>
|
||||
{
|
||||
activity.From = new PlainTextExpression("shipment@acme.com");
|
||||
activity.To = new JavaScriptExpression<string>("order.customer.email");
|
||||
activity.Subject = new JavaScriptExpression<string>("`Your order with ID #${order.id} has been shipped!`");
|
||||
activity.Body = new JavaScriptExpression<string>(
|
||||
"`Dear ${order.customer.name}, your order has shipped!`"
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
samples/Sample08/Workflows/HandleOrderWorkflow.cs
Normal file
34
samples/Sample08/Workflows/HandleOrderWorkflow.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using Elsa.Activities.MassTransit.Activities;
|
||||
using Elsa.Activities.Timers.Activities;
|
||||
using Elsa.Core.Activities.Primitives;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Sample08.Messages;
|
||||
|
||||
namespace Sample08.Workflows
|
||||
{
|
||||
public class HandleOrderWorkflow : IWorkflow
|
||||
{
|
||||
public void Build(IWorkflowBuilder builder)
|
||||
{
|
||||
builder
|
||||
.StartWith<ReceiveMassTransitMessage>(activity => activity.MessageType = typeof(CreateOrder))
|
||||
.Then<SetVariable>(
|
||||
activity =>
|
||||
{
|
||||
activity.VariableName = "order";
|
||||
activity.ValueExpression = new JavaScriptExpression<object>("lastResult().Order");
|
||||
}
|
||||
)
|
||||
.Then<TimerEvent>(activity => activity.TimeoutExpression = new PlainTextExpression<TimeSpan>("00:00:05"))
|
||||
.Then<SendMassTransitMessage>(activity =>
|
||||
{
|
||||
activity.Message = new JavaScriptExpression<OrderShipped>("return {order: order}");
|
||||
activity.MessageType = typeof(OrderShipped);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
6
samples/Sample08/app.config
Normal file
6
samples/Sample08/app.config
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<gcServer enabled="true"/>
|
||||
</runtime>
|
||||
</configuration>
|
||||
9
samples/Sample08/appsettings.Development.json
Normal file
9
samples/Sample08/appsettings.Development.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
17
samples/Sample08/appsettings.json
Normal file
17
samples/Sample08/appsettings.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Smtp": {
|
||||
"Host": "localhost",
|
||||
"Port": "2525"
|
||||
},
|
||||
"MassTransit": {
|
||||
"RabbitMq": {
|
||||
"Host": "rabbitmq://localhost:5672"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
samples/Sample08/docker-compose.yaml
Normal file
10
samples/Sample08/docker-compose.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
version: '3.7'
|
||||
|
||||
services:
|
||||
rabbitmq:
|
||||
image: "rabbitmq:3-management"
|
||||
ports:
|
||||
- "15672:15672"
|
||||
- "5672:5672"
|
||||
labels:
|
||||
name: "rabbitmq"
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
using Elsa.Activities.Cron.Activities;
|
||||
using Elsa.Activities.Cron.HostedServices;
|
||||
using Elsa.Activities.Cron.Options;
|
||||
using Elsa.Core.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Activities.Cron.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddCronActivities(this IServiceCollection services, Action<OptionsBuilder<CronOptions>> options = null)
|
||||
{
|
||||
var optionsBuilder = services.AddOptions<CronOptions>();
|
||||
options?.Invoke(optionsBuilder);
|
||||
|
||||
return services
|
||||
.AddOptions()
|
||||
.AddHostedService<CronHostedService>()
|
||||
.AddActivity<CronTrigger>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Net.Mail;
|
|||
using Elsa.Activities.Email.Activities;
|
||||
using Elsa.Activities.Email.Options;
|
||||
using Elsa.Core.Extensions;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||
using Elsa.Activities.Http.Models;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
@ -111,7 +112,7 @@ namespace Elsa.Activities.Http.Activities
|
|||
StatusCode = response.StatusCode,
|
||||
Headers = new HeaderDictionary(response.Headers.ToDictionary(x => x.Key, x => new StringValues(x.Value.ToArray()))),
|
||||
Content = content,
|
||||
FormattedContent = await formatter.FormatAsync(content, contentType)
|
||||
FormattedContent = await formatter.ParseAsync(content, contentType)
|
||||
};
|
||||
|
||||
workflowContext.SetLastResult(responseModel);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ using Elsa.Activities.Http.Models;
|
|||
using Elsa.Activities.Http.Services;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
@ -98,10 +96,10 @@ namespace Elsa.Activities.Http.Activities
|
|||
model.Form = (await request.ReadFormAsync(cancellationToken)).ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
|
||||
var formatter = SelectContentFormatter(request.ContentType);
|
||||
var parser = SelectContentParser(request.ContentType);
|
||||
var content = await request.ReadBodyAsync();
|
||||
model.Content = content;
|
||||
model.FormattedContent = await formatter.FormatAsync(content, request.ContentType);
|
||||
model.ParsedContent = await parser.ParseAsync(content, request.ContentType);
|
||||
}
|
||||
|
||||
workflowContext.CurrentScope.LastResult = model;
|
||||
|
|
@ -109,7 +107,7 @@ namespace Elsa.Activities.Http.Activities
|
|||
return Done();
|
||||
}
|
||||
|
||||
private IContentFormatter SelectContentFormatter(string contentType)
|
||||
private IContentFormatter SelectContentParser(string contentType)
|
||||
{
|
||||
var formatters = contentFormatters.OrderByDescending(x => x.Priority).ToList();
|
||||
return formatters.FirstOrDefault(x => x.SupportedContentTypes.Contains(contentType, StringComparer.OrdinalIgnoreCase)) ?? formatters.Last();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.AsyncInitialization" Version="1.1.2" />
|
||||
<PackageReference Include="CSharpFunctionalExtensions" Version="1.18.2" />
|
||||
<PackageReference Include="LanguageExt.Core" Version="3.1.24" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="2.2.0" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Activities.Http.Middleware;
|
||||
using Elsa.Activities.Http.RequestHandlers;
|
||||
using Elsa.Activities.Http.RequestHandlers.Handlers;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,12 @@
|
|||
using Elsa.Activities.Http.Activities;
|
||||
using Elsa.Activities.Http.Formatters;
|
||||
using Elsa.Activities.Http.Middleware;
|
||||
using Elsa.Activities.Http.Models;
|
||||
using Elsa.Activities.Http.RequestHandlers;
|
||||
using Elsa.Activities.Http.RequestHandlers.Handlers;
|
||||
using Elsa.Activities.Http.Scripting;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Scripting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ using System.Dynamic;
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Activities.Http.Formatters
|
||||
{
|
||||
|
|
@ -12,7 +11,7 @@ namespace Elsa.Activities.Http.Formatters
|
|||
public int Priority => 0;
|
||||
public IEnumerable<string> SupportedContentTypes => new[] { "application/json", "text/json" };
|
||||
|
||||
public Task<object> FormatAsync(string content, string contentType)
|
||||
public Task<object> ParseAsync(string content, string contentType)
|
||||
{
|
||||
return Task.FromResult<object>(JsonConvert.DeserializeObject<ExpandoObject>(content));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Elsa.Activities.Http.Formatters
|
|||
public int Priority => -1;
|
||||
public IEnumerable<string> SupportedContentTypes => new[] { "", default };
|
||||
|
||||
public Task<object> FormatAsync(string content, string contentType)
|
||||
public Task<object> ParseAsync(string content, string contentType)
|
||||
{
|
||||
return Task.FromResult<object>(content);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Http.RequestHandlers;
|
||||
using Elsa.Activities.Http.Services;
|
||||
using Elsa.Persistence;
|
||||
using Elsa.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Elsa.Activities.Http.Middleware
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Elsa.Activities.Http.Models
|
|||
public IDictionary<string, StringValues> QueryString { get; set; }
|
||||
public IDictionary<string, StringValues> Headers { get; set; }
|
||||
public string Content { get; set; }
|
||||
public object FormattedContent { get; set; }
|
||||
public object ParsedContent { get; set; }
|
||||
public IDictionary<string, StringValues> Form { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -8,6 +7,6 @@ namespace Elsa.Activities.Http.Services
|
|||
{
|
||||
int Priority { get; }
|
||||
IEnumerable<string> SupportedContentTypes { get; }
|
||||
Task<object> FormatAsync(string content, string contentType);
|
||||
Task<object> ParseAsync(string content, string contentType);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Activities.MassTransit.Activities
|
||||
{
|
||||
public class ReceiveMassTransitMessage : Activity
|
||||
{
|
||||
public static Type GetMessageType(JObject state)
|
||||
{
|
||||
var typeName = state.GetState<string>(nameof(MessageType));
|
||||
return string.IsNullOrWhiteSpace(typeName) ? null : Type.GetType(typeName);
|
||||
}
|
||||
|
||||
public Type MessageType
|
||||
{
|
||||
get => GetMessageType(State);
|
||||
set => SetState(value.AssemblyQualifiedName);
|
||||
}
|
||||
|
||||
protected override bool OnCanExecute(WorkflowExecutionContext context)
|
||||
{
|
||||
var message = context.Workflow.Input["message"];
|
||||
var messageType = MessageType;
|
||||
|
||||
return message != null && messageType != null && message.GetType() == messageType;
|
||||
}
|
||||
|
||||
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext context)
|
||||
{
|
||||
return Halt(true);
|
||||
}
|
||||
|
||||
protected override Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
var message = context.Workflow.Input["message"];
|
||||
context.SetLastResult(message);
|
||||
|
||||
return Task.FromResult(Done());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using MassTransit;
|
||||
|
||||
namespace Elsa.Activities.MassTransit.Activities
|
||||
{
|
||||
public class SendMassTransitMessage : Activity
|
||||
{
|
||||
private readonly ISendEndpointProvider sender;
|
||||
private readonly IWorkflowExpressionEvaluator evaluator;
|
||||
|
||||
public SendMassTransitMessage(ISendEndpointProvider sender, IWorkflowExpressionEvaluator evaluator)
|
||||
{
|
||||
this.sender = sender;
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
public Type MessageType
|
||||
{
|
||||
get
|
||||
{
|
||||
var typeName = GetState<string>();
|
||||
return string.IsNullOrWhiteSpace(typeName) ? null : Type.GetType(typeName);
|
||||
}
|
||||
set => SetState(value.AssemblyQualifiedName);
|
||||
}
|
||||
|
||||
public WorkflowExpression Message
|
||||
{
|
||||
get => GetState(() => new WorkflowExpression(JavaScriptEvaluator.SyntaxName, string.Empty));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override bool OnCanExecute(WorkflowExecutionContext context)
|
||||
{
|
||||
return MessageType != null;
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnExecuteAsync(WorkflowExecutionContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
var message = await evaluator.EvaluateAsync(Message, MessageType, context, cancellationToken);
|
||||
await sender.Send(message, cancellationToken);
|
||||
|
||||
return Done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.MassTransit.Activities;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using MassTransit;
|
||||
|
||||
namespace Elsa.Activities.MassTransit.Consumers
|
||||
{
|
||||
public class WorkflowConsumer<T> : IConsumer<T> where T : class
|
||||
{
|
||||
private readonly IWorkflowInvoker workflowInvoker;
|
||||
|
||||
public WorkflowConsumer(IWorkflowInvoker workflowInvoker)
|
||||
{
|
||||
this.workflowInvoker = workflowInvoker;
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<T> context)
|
||||
{
|
||||
var message = context.Message;
|
||||
var activityType = nameof(ReceiveMassTransitMessage);
|
||||
var input = new Variables { ["message"] = message };
|
||||
|
||||
await workflowInvoker.TriggerAsync(
|
||||
activityType,
|
||||
input,
|
||||
x => ReceiveMassTransitMessage.GetMessageType(x) == message.GetType(),
|
||||
context.CancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MassTransit.AspNetCore" Version="5.5.2" />
|
||||
<PackageReference Include="MassTransit.Extensions.DependencyInjection" Version="5.5.2" />
|
||||
<PackageReference Include="MassTransit.RabbitMQ" Version="5.5.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Activities.MassTransit.Activities;
|
||||
using Elsa.Activities.MassTransit.Consumers;
|
||||
using Elsa.Activities.MassTransit.Options;
|
||||
using Elsa.Core.Extensions;
|
||||
using MassTransit;
|
||||
using MassTransit.AspNetCoreIntegration;
|
||||
using MassTransit.AspNetCoreIntegration.HealthChecks;
|
||||
using MassTransit.ExtensionsDependencyInjectionIntegration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Activities.MassTransit.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddRabbitMqActivities(this IServiceCollection services, Action<OptionsBuilder<RabbitMqOptions>> options = null, params Type[] messageTypes)
|
||||
{
|
||||
var optionsBuilder = services.AddOptions<RabbitMqOptions>();
|
||||
options?.Invoke(optionsBuilder);
|
||||
|
||||
services
|
||||
.AddActivity<SendMassTransitMessage>()
|
||||
.AddActivity<ReceiveMassTransitMessage>();
|
||||
|
||||
services.AddSingleton<SimplifiedBusHealthCheck>();
|
||||
services.AddSingleton<ReceiveEndpointHealthCheck>();
|
||||
|
||||
services.AddMassTransit(
|
||||
massTransit =>
|
||||
{
|
||||
massTransit.AddBus(sp => CreateUsingRabbitMq(massTransit, sp, messageTypes));
|
||||
});
|
||||
|
||||
services.AddSingleton<IHostedService, MassTransitHostedService>();
|
||||
|
||||
foreach (var messageType in messageTypes)
|
||||
{
|
||||
var consumerType = CreateConsumerType(messageType);
|
||||
services.AddSingleton(consumerType);
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IBusControl CreateUsingRabbitMq(IServiceCollectionConfigurator massTransit, IServiceProvider sp, IEnumerable<Type> messageTypes)
|
||||
{
|
||||
return Bus.Factory.CreateUsingRabbitMq(
|
||||
bus =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<RabbitMqOptions>>();
|
||||
var host = bus.Host(new Uri(options.Value.Host), _ => { });
|
||||
|
||||
foreach (var messageType in messageTypes)
|
||||
{
|
||||
var queueName = messageType.Name;
|
||||
var consumerType = CreateConsumerType(messageType);
|
||||
|
||||
bus.ReceiveEndpoint(
|
||||
host,
|
||||
queueName,
|
||||
endpoint =>
|
||||
{
|
||||
endpoint.PrefetchCount = 16;
|
||||
endpoint.Consumer(consumerType, sp.GetRequiredService);
|
||||
MapEndpointConvention(messageType, endpoint.InputAddress);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void MapEndpointConvention(Type messageType, Uri destinationAddress)
|
||||
{
|
||||
var method = typeof(EndpointConvention).GetMethod("Map", new[]{ typeof(Uri) });
|
||||
var generic = method.MakeGenericMethod(messageType);
|
||||
generic.Invoke(null, new object[]{destinationAddress});
|
||||
}
|
||||
|
||||
private static Type CreateConsumerType(Type messageType)
|
||||
{
|
||||
return typeof(WorkflowConsumer<>).MakeGenericType(messageType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Elsa.Activities.MassTransit.Options
|
||||
{
|
||||
public class RabbitMqOptions
|
||||
{
|
||||
public string Host { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
@ -8,14 +9,14 @@ using Elsa.Services.Models;
|
|||
using NCrontab;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Activities.Cron.Activities
|
||||
namespace Elsa.Activities.Timers.Activities
|
||||
{
|
||||
public class CronTrigger : Activity
|
||||
public class CronEvent : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
private readonly IClock clock;
|
||||
|
||||
public CronTrigger(IWorkflowExpressionEvaluator expressionEvaluator, IClock clock)
|
||||
public CronEvent(IWorkflowExpressionEvaluator expressionEvaluator, IClock clock)
|
||||
{
|
||||
this.expressionEvaluator = expressionEvaluator;
|
||||
this.clock = clock;
|
||||
|
|
@ -27,7 +28,7 @@ namespace Elsa.Activities.Cron.Activities
|
|||
set => SetState(value);
|
||||
}
|
||||
|
||||
public Instant? StartTimestamp
|
||||
public Instant? StartTime
|
||||
{
|
||||
get => GetState<Instant?>();
|
||||
set => SetState(value);
|
||||
|
|
@ -35,9 +36,9 @@ namespace Elsa.Activities.Cron.Activities
|
|||
|
||||
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
if (StartTimestamp == null)
|
||||
if (StartTime == null)
|
||||
{
|
||||
StartTimestamp = clock.GetCurrentInstant();
|
||||
StartTime = clock.GetCurrentInstant();
|
||||
}
|
||||
|
||||
return Halt();
|
||||
|
|
@ -55,8 +56,8 @@ namespace Elsa.Activities.Cron.Activities
|
|||
var cronExpression = await expressionEvaluator.EvaluateAsync(CronExpression, workflowContext, cancellationToken);
|
||||
var schedule = CrontabSchedule.Parse(cronExpression);
|
||||
var now = clock.GetCurrentInstant();
|
||||
var startTimestamp = StartTimestamp ?? now;
|
||||
var nextOccurrence = schedule.GetNextOccurrence(startTimestamp.ToDateTimeUtc());
|
||||
var startTime = StartTime ?? now;
|
||||
var nextOccurrence = schedule.GetNextOccurrence(startTime.ToDateTimeUtc());
|
||||
|
||||
return now.ToDateTimeUtc() >= nextOccurrence;
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Activities.Timers.Activities
|
||||
{
|
||||
public class TimerEvent : Activity
|
||||
{
|
||||
private readonly IWorkflowExpressionEvaluator expressionEvaluator;
|
||||
private readonly IClock clock;
|
||||
|
||||
public TimerEvent(IWorkflowExpressionEvaluator expressionEvaluator, IClock clock)
|
||||
{
|
||||
this.expressionEvaluator = expressionEvaluator;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public WorkflowExpression<TimeSpan> TimeoutExpression
|
||||
{
|
||||
get => GetState(() => new PlainTextExpression<TimeSpan>("00:01:00"));
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
public Instant? StartTime
|
||||
{
|
||||
get => GetState<Instant?>();
|
||||
set => SetState(value);
|
||||
}
|
||||
|
||||
protected override ActivityExecutionResult OnExecute(WorkflowExecutionContext workflowContext)
|
||||
{
|
||||
if (StartTime == null)
|
||||
{
|
||||
StartTime = clock.GetCurrentInstant();
|
||||
}
|
||||
|
||||
return Halt();
|
||||
}
|
||||
|
||||
protected override async Task<ActivityExecutionResult> OnResumeAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var isExpired = await IsExpiredAsync(workflowContext, cancellationToken);
|
||||
|
||||
return isExpired ? Done() : Halt();
|
||||
}
|
||||
|
||||
private async Task<bool> IsExpiredAsync(WorkflowExecutionContext workflowContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var timeSpan = await expressionEvaluator.EvaluateAsync(TimeoutExpression, workflowContext, cancellationToken);
|
||||
var now = clock.GetCurrentInstant();
|
||||
var startTime = StartTime ?? now;
|
||||
var expiresAt = startTime.ToDateTimeUtc() + timeSpan;
|
||||
|
||||
return now.ToDateTimeUtc() >= expiresAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using Elsa.Activities.Timers.Activities;
|
||||
using Elsa.Activities.Timers.HostedServices;
|
||||
using Elsa.Activities.Timers.Options;
|
||||
using Elsa.Core.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Activities.Timers.Extensions
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddTimerActivities(this IServiceCollection services, Action<OptionsBuilder<TimersOptions>> options = null)
|
||||
{
|
||||
var optionsBuilder = services.AddOptions<TimersOptions>();
|
||||
options?.Invoke(optionsBuilder);
|
||||
|
||||
return services
|
||||
.AddOptions()
|
||||
.AddHostedService<TimersHostedService>()
|
||||
.AddActivity<CronEvent>()
|
||||
.AddActivity<TimerEvent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,24 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Activities.Cron.Activities;
|
||||
using Elsa.Activities.Cron.Options;
|
||||
using Elsa.Activities.Timers.Activities;
|
||||
using Elsa.Activities.Timers.Options;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Activities.Cron.HostedServices
|
||||
namespace Elsa.Activities.Timers.HostedServices
|
||||
{
|
||||
public class CronHostedService : BackgroundService
|
||||
public class TimersHostedService : BackgroundService
|
||||
{
|
||||
private readonly IWorkflowInvoker workflowInvoker;
|
||||
private readonly IOptions<CronOptions> options;
|
||||
private readonly ILogger<CronHostedService> logger;
|
||||
private readonly IOptions<TimersOptions> options;
|
||||
private readonly ILogger<TimersHostedService> logger;
|
||||
|
||||
public CronHostedService(IWorkflowInvoker workflowInvoker, IOptions<CronOptions> options, ILogger<CronHostedService> logger)
|
||||
public TimersHostedService(IWorkflowInvoker workflowInvoker, IOptions<TimersOptions> options, ILogger<TimersHostedService> logger)
|
||||
{
|
||||
this.workflowInvoker = workflowInvoker;
|
||||
this.options = options;
|
||||
|
|
@ -30,7 +31,8 @@ namespace Elsa.Activities.Cron.HostedServices
|
|||
{
|
||||
try
|
||||
{
|
||||
await workflowInvoker.TriggerAsync(nameof(CronTrigger), Variables.Empty, stoppingToken);
|
||||
await workflowInvoker.TriggerAsync(nameof(TimerEvent), Variables.Empty, stoppingToken);
|
||||
await workflowInvoker.TriggerAsync(nameof(CronEvent), Variables.Empty, stoppingToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
using NodaTime;
|
||||
|
||||
namespace Elsa.Activities.Cron.Options
|
||||
namespace Elsa.Activities.Timers.Options
|
||||
{
|
||||
public class CronOptions
|
||||
public class TimersOptions
|
||||
{
|
||||
public CronOptions()
|
||||
public TimersOptions()
|
||||
{
|
||||
SweepInterval = Period.FromMinutes(1);
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Elsa.Expressions
|
||||
{
|
||||
public interface IWorkflowExpression<T>
|
||||
public interface IWorkflowExpression
|
||||
{
|
||||
string Syntax { get; }
|
||||
string Expression { get; }
|
||||
}
|
||||
|
||||
public interface IWorkflowExpression<T> : IWorkflowExpression
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Serialization.Models;
|
||||
|
||||
namespace Elsa.Persistence
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using Elsa.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Serialization.Models
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Services.Extensions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Services.Extensions
|
||||
{
|
||||
public static class WorkflowInvokerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts new workflows that start with the specified activity name and resumes halted workflows that are blocked on activities with the specified activity name.
|
||||
/// </summary>
|
||||
public static Task TriggerAsync(
|
||||
this IWorkflowInvoker workflowInvoker,
|
||||
string activityType,
|
||||
Variables input,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return workflowInvoker.TriggerAsync(activityType, input, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ namespace Elsa.Services
|
|||
{
|
||||
public interface IActivityResolver
|
||||
{
|
||||
IActivity ResolveActivity(string activityTypeName, Action<IActivity> setup = null);
|
||||
T ResolveActivity<T>(Action<T> configure = null) where T : class, IActivity;
|
||||
IActivity ResolveActivity(string activityTypeName, Action<IActivity> setup = default);
|
||||
T ResolveActivity<T>(Action<T> configure = default) where T : class, IActivity;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Services.Models;
|
||||
|
|
@ -7,6 +8,6 @@ namespace Elsa.Services
|
|||
public interface IExpressionEvaluator
|
||||
{
|
||||
string Syntax { get; }
|
||||
Task<T> EvaluateAsync<T>(string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken);
|
||||
Task<object> EvaluateAsync(string expression, Type type, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ namespace Elsa.Services
|
|||
{
|
||||
IActivityBuilder Source { get; }
|
||||
string Outcome { get; }
|
||||
IActivityBuilder Then<T>(Action<T> setup, string id = null) where T : class, IActivity;
|
||||
IActivityBuilder Then<T>(Action<T> setup = default, string id = default) where T : class, IActivity;
|
||||
WorkflowDefinition Build();
|
||||
IConnectionBuilder Then(string activityId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Models;
|
||||
using Elsa.Serialization.Models;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Services
|
||||
|
|
@ -12,10 +11,10 @@ namespace Elsa.Services
|
|||
IReadOnlyList<IActivityBuilder> Activities { get; }
|
||||
IWorkflowBuilder WithId(string id);
|
||||
IWorkflowBuilder AsSingleton(bool value = true);
|
||||
IActivityBuilder Add<T>(Action<T> setupActivity, string id = null) where T : class, IActivity;
|
||||
IActivityBuilder StartWith<T>(Action<T> setup = null, string id = null) where T: class, IActivity;
|
||||
IConnectionBuilder Connect(IActivityBuilder source, IActivityBuilder target, string outcome = null);
|
||||
IConnectionBuilder Connect(Func<IActivityBuilder> source, Func<IActivityBuilder> target, string outcome = null);
|
||||
IActivityBuilder Add<T>(Action<T> setupActivity = default, string id = default) where T : class, IActivity;
|
||||
IActivityBuilder StartWith<T>(Action<T> setup = default, string id = default) where T: class, IActivity;
|
||||
IConnectionBuilder Connect(IActivityBuilder source, IActivityBuilder target, string outcome = default);
|
||||
IConnectionBuilder Connect(Func<IActivityBuilder> source, Func<IActivityBuilder> target, string outcome = default);
|
||||
WorkflowDefinition Build();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Expressions;
|
||||
|
|
@ -7,6 +8,6 @@ namespace Elsa.Services
|
|||
{
|
||||
public interface IWorkflowExpressionEvaluator
|
||||
{
|
||||
Task<T> EvaluateAsync<T>(IWorkflowExpression<T> expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken);
|
||||
Task<object> EvaluateAsync(IWorkflowExpression expression, Type type, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Serialization.Models;
|
||||
using Elsa.Services.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
|
|
@ -40,6 +42,10 @@ namespace Elsa.Services
|
|||
/// <summary>
|
||||
/// Starts new workflows that start with the specified activity name and resumes halted workflows that are blocked on activities with the specified activity name.
|
||||
/// </summary>
|
||||
Task TriggerAsync(string activityType, Variables input, CancellationToken cancellationToken = default);
|
||||
Task TriggerAsync(
|
||||
string activityType,
|
||||
Variables input,
|
||||
Func<JObject, bool> activityStatePredicate = default,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Elsa.Models;
|
||||
using Elsa.Serialization.Models;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Results;
|
||||
using Elsa.Services;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Scripting;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
using Esprima.Ast;
|
||||
using Jint;
|
||||
using Jint.Native;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Elsa.Core.Expressions
|
||||
{
|
||||
|
|
@ -32,14 +28,14 @@ namespace Elsa.Core.Expressions
|
|||
|
||||
public string Syntax => SyntaxName;
|
||||
|
||||
public Task<T> EvaluateAsync<T>(string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
public Task<object> EvaluateAsync(string expression, Type type, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var engine = new Engine(options => { options.AllowClr(); });
|
||||
|
||||
ConfigureEngine(engine, workflowExecutionContext);
|
||||
engine.Execute(expression);
|
||||
|
||||
var result = ConvertValue<T>(engine.GetCompletionValue());
|
||||
var result = ConvertValue(engine.GetCompletionValue(), type);
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
|
@ -52,11 +48,6 @@ namespace Elsa.Core.Expressions
|
|||
}
|
||||
}
|
||||
|
||||
private T ConvertValue<T>(JsValue value)
|
||||
{
|
||||
return (T)ConvertValue(value, typeof(T));
|
||||
}
|
||||
|
||||
private object ConvertValue(JsValue value, Type targetType)
|
||||
{
|
||||
if (value.IsNull())
|
||||
|
|
@ -75,7 +66,11 @@ namespace Elsa.Core.Expressions
|
|||
return value.AsString();
|
||||
|
||||
if (value.IsObject())
|
||||
return value.AsObject().ToObject();
|
||||
{
|
||||
var obj = value.AsObject().ToObject();
|
||||
var json = JsonConvert.SerializeObject(obj);
|
||||
return JsonConvert.DeserializeObject(json, targetType);
|
||||
}
|
||||
|
||||
if (value.IsArray())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Core.Extensions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
|
|
@ -17,12 +17,12 @@ namespace Elsa.Core.Expressions
|
|||
public const string SyntaxName = "PlainText";
|
||||
public string Syntax => SyntaxName;
|
||||
|
||||
public Task<T> EvaluateAsync<T>(string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
public Task<object> EvaluateAsync(string expression, Type type, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(expression))
|
||||
return Task.FromResult(default(T));
|
||||
return Task.FromResult(default(object));
|
||||
|
||||
return Task.FromResult((T) Convert.ChangeType(expression, typeof(T)));
|
||||
return Task.FromResult(expression.Parse(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,16 @@
|
|||
namespace Elsa.Core.Expressions
|
||||
{
|
||||
public class PlainTextExpression : WorkflowExpression<string>
|
||||
public class PlainTextExpression<T> : WorkflowExpression<T>
|
||||
{
|
||||
public PlainTextExpression(string expression) : base(PlainTextEvaluator.SyntaxName, expression)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class PlainTextExpression : PlainTextExpression<string>
|
||||
{
|
||||
public PlainTextExpression(string expression) : base(expression)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
namespace Elsa.Core.Expressions
|
||||
{
|
||||
public class WorkflowExpression
|
||||
public class WorkflowExpression : IWorkflowExpression
|
||||
{
|
||||
protected WorkflowExpression(string syntax, string expression)
|
||||
public WorkflowExpression(string syntax, string expression)
|
||||
{
|
||||
Syntax = syntax;
|
||||
Expression = expression;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
@ -16,14 +17,14 @@ namespace Elsa.Core.Expressions
|
|||
{
|
||||
this.evaluators = evaluators.ToDictionary(x => x.Syntax);
|
||||
}
|
||||
|
||||
public async Task<T> EvaluateAsync<T>(IWorkflowExpression<T> expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
|
||||
public async Task<object> EvaluateAsync(IWorkflowExpression expression, Type type, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
{
|
||||
if (expression == null)
|
||||
return default;
|
||||
|
||||
var evaluator = evaluators[expression.Syntax];
|
||||
return await evaluator.EvaluateAsync<T>(expression.Expression, workflowExecutionContext, cancellationToken);
|
||||
return await evaluator.EvaluateAsync(expression.Expression, type, workflowExecutionContext, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Core.Extensions
|
||||
{
|
||||
public static class ExpressionEvaluatorExtensions
|
||||
{
|
||||
public static async Task<T> EvaluateAsync<T>(this IExpressionEvaluator evaluator, string expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
{
|
||||
return (T)await evaluator.EvaluateAsync(expression, typeof(T), workflowExecutionContext, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using Elsa.Core.Activities.Primitives;
|
||||
using Elsa.Core.Expressions;
|
||||
using Elsa.Core.Scripting;
|
||||
using Elsa.Core.Serialization;
|
||||
using Elsa.Core.Serialization.Formatters;
|
||||
using Elsa.Core.Services;
|
||||
using Elsa.Core.Services.WorkflowBuilders;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Scripting;
|
||||
using Elsa.Serialization;
|
||||
using Elsa.Serialization.Formatters;
|
||||
|
|
@ -40,6 +41,7 @@ namespace Elsa.Core.Extensions
|
|||
.AddSingleton<IWorkflowExpressionEvaluator, WorkflowExpressionEvaluator>()
|
||||
.AddSingleton<IWorkflowSerializerProvider, WorkflowSerializerProvider>()
|
||||
.AddTransient<IWorkflowBuilder, WorkflowBuilder>()
|
||||
.AddSingleton<Func<IWorkflowBuilder>>(sp => sp.GetRequiredService<IWorkflowBuilder>)
|
||||
.AddSingleton<IWorkflowRegistry, WorkflowRegistry>()
|
||||
.AddPrimitiveActivities();
|
||||
}
|
||||
|
|
|
|||
23
src/core/Elsa.Core/Extensions/StringExtensions.cs
Normal file
23
src/core/Elsa.Core/Extensions/StringExtensions.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Elsa.Core.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static T Parse<T>(this string value)
|
||||
{
|
||||
return (T)value.Parse(typeof(T));
|
||||
}
|
||||
|
||||
public static object Parse(this string value, Type targetType)
|
||||
{
|
||||
if (typeof(string) == targetType)
|
||||
return value;
|
||||
|
||||
var converter = TypeDescriptor.GetConverter(targetType);
|
||||
return converter.ConvertFromString(default, CultureInfo.InvariantCulture, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Core.Extensions
|
||||
{
|
||||
public static class WorkflowExpressionEvaluatorExtensions
|
||||
{
|
||||
public static async Task<T> EvaluateAsync<T>(this IWorkflowExpressionEvaluator evaluator, IWorkflowExpression<T> expression, WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)
|
||||
{
|
||||
return (T)await evaluator.EvaluateAsync(expression, typeof(T), workflowExecutionContext, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence;
|
||||
using Elsa.Serialization.Models;
|
||||
|
||||
namespace Elsa.Core.Persistence.Memory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Elsa.Expressions;
|
||||
using Elsa.Scripting;
|
||||
using Elsa.Services.Models;
|
||||
using Jint;
|
||||
|
||||
namespace Elsa.Core.Expressions
|
||||
namespace Elsa.Core.Scripting
|
||||
{
|
||||
public class CommonScriptEngineConfigurator : IScriptEngineConfigurator
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Models;
|
||||
|
||||
namespace Elsa.Core.Services.WorkflowBuilders
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Elsa.Core.Services.WorkflowBuilders
|
|||
public IActivityBuilder Source { get; }
|
||||
public string Outcome { get; }
|
||||
|
||||
public IActivityBuilder Then<T>(Action<T> setup, string id = null) where T : class, IActivity
|
||||
public IActivityBuilder Then<T>(Action<T> setup = default, string id = default) where T : class, IActivity
|
||||
{
|
||||
var target = WorkflowBuilder.Add(setup, id);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace Elsa.Core.Services.WorkflowBuilders
|
|||
return this;
|
||||
}
|
||||
|
||||
public IActivityBuilder Add<T>(Action<T> setupActivity, string id = null) where T : class, IActivity
|
||||
public IActivityBuilder Add<T>(Action<T> setupActivity = default, string id = default) where T : class, IActivity
|
||||
{
|
||||
var activity = activityResolver.ResolveActivity(setupActivity);
|
||||
var activityBlueprint = ActivityDefinition.FromActivity(activity);
|
||||
|
|
@ -47,12 +47,12 @@ namespace Elsa.Core.Services.WorkflowBuilders
|
|||
return activityBuilder;
|
||||
}
|
||||
|
||||
public IConnectionBuilder Connect(IActivityBuilder source, IActivityBuilder target, string outcome = null)
|
||||
public IConnectionBuilder Connect(IActivityBuilder source, IActivityBuilder target, string outcome = default)
|
||||
{
|
||||
return Connect(() => source, () => target, outcome);
|
||||
}
|
||||
|
||||
public IConnectionBuilder Connect(Func<IActivityBuilder> source, Func<IActivityBuilder> target, string outcome = null)
|
||||
public IConnectionBuilder Connect(Func<IActivityBuilder> source, Func<IActivityBuilder> target, string outcome = default)
|
||||
{
|
||||
var connectionBuilder = new ConnectionBuilder(this, source, target, outcome);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Elsa.Services;
|
|||
using Elsa.Services.Extensions;
|
||||
using Elsa.Services.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Core.Services
|
||||
|
|
@ -89,15 +90,23 @@ namespace Elsa.Core.Services
|
|||
return InvokeAsync(definition, input, workflowInstance, startActivityIds, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task TriggerAsync(string activityType, Variables input, CancellationToken cancellationToken)
|
||||
public async Task TriggerAsync(
|
||||
string activityType,
|
||||
Variables input,
|
||||
Func<JObject, bool> activityStatePredicate = default,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var workflowDefinitions = workflowRegistry.ListByStartActivity(activityType).ToDictionary(x => x.Item1.Id);
|
||||
var workflowInstances = await workflowInstanceStore.ListByBlockingActivityAsync(activityType, cancellationToken).ToListAsync();
|
||||
var workflowInstancesByDefinitionId = workflowInstances.ToDictionary(x => x.Item1.DefinitionId);
|
||||
var workflowsToStart = workflowDefinitions.Values.Where(x => !workflowInstancesByDefinitionId.ContainsKey(x.Item1.Id));
|
||||
var workflowDefinitions = workflowRegistry.ListByStartActivity(activityType).ToList();
|
||||
|
||||
await StartWorkflowsAsync(workflowsToStart, input, cancellationToken);
|
||||
await ResumeWorkflowsAsync(workflowDefinitions, workflowInstances, input, cancellationToken);
|
||||
if (activityStatePredicate != null)
|
||||
workflowDefinitions = workflowDefinitions.Where(x => activityStatePredicate(x.Item2.State)).ToList();
|
||||
|
||||
if (activityStatePredicate != null)
|
||||
workflowInstances = workflowInstances.Where(x => activityStatePredicate(x.Item2.State)).ToList();
|
||||
|
||||
await StartWorkflowsAsync(workflowDefinitions, input, cancellationToken);
|
||||
await ResumeWorkflowsAsync(workflowInstances, input, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task StartWorkflowsAsync(IEnumerable<(WorkflowDefinition, ActivityDefinition)> workflowDefinitions, Variables variables, CancellationToken cancellationToken1)
|
||||
|
|
@ -109,15 +118,15 @@ namespace Elsa.Core.Services
|
|||
}
|
||||
}
|
||||
|
||||
private async Task ResumeWorkflowsAsync(IReadOnlyDictionary<string, (WorkflowDefinition, ActivityDefinition)> workflowDefinitions, IList<(WorkflowInstance, ActivityInstance)> workflowInstances, Variables input, CancellationToken cancellationToken)
|
||||
private async Task ResumeWorkflowsAsync(IEnumerable<(WorkflowInstance, ActivityInstance)> workflowInstances, Variables input, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var (workflowInstance, startActivityInstance) in workflowInstances)
|
||||
{
|
||||
var workflowDefinition = workflowDefinitions[workflowInstance.DefinitionId];
|
||||
var workflowDefinition = workflowRegistry.GetById(workflowInstance.DefinitionId);
|
||||
|
||||
workflowInstance.Status = WorkflowStatus.Resuming;
|
||||
|
||||
await InvokeAsync(workflowDefinition.Item1, input, workflowInstance, new[] { startActivityInstance.Id }, cancellationToken);
|
||||
await InvokeAsync(workflowDefinition, input, workflowInstance, new[] { startActivityInstance.Id }, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Elsa.Services.Extensions;
|
||||
|
|
@ -10,12 +10,12 @@ namespace Elsa.Core.Services
|
|||
{
|
||||
public class WorkflowRegistry : IWorkflowRegistry
|
||||
{
|
||||
private readonly IWorkflowBuilder workflowBuilder;
|
||||
private readonly Func<IWorkflowBuilder> workflowBuilderFactory;
|
||||
private readonly IDictionary<string, WorkflowDefinition> workflowDefinitions;
|
||||
|
||||
public WorkflowRegistry(IWorkflowBuilder workflowBuilder)
|
||||
public WorkflowRegistry(Func<IWorkflowBuilder> workflowBuilderFactory)
|
||||
{
|
||||
this.workflowBuilder = workflowBuilder;
|
||||
this.workflowBuilderFactory = workflowBuilderFactory;
|
||||
workflowDefinitions = new Dictionary<string, WorkflowDefinition>();
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ namespace Elsa.Core.Services
|
|||
|
||||
public void RegisterWorkflow<T>() where T : IWorkflow, new()
|
||||
{
|
||||
var definition = workflowBuilder.Build<T>();
|
||||
var definition = workflowBuilderFactory().Build<T>();
|
||||
RegisterWorkflow(definition);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue