Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4dba6874c | ||
|
|
b144c07970 | ||
|
|
83738f809b | ||
|
|
2b15c8a1af | ||
|
|
f607e4fbd4 | ||
|
|
d1c0b06ec6 | ||
|
|
4abfe079db | ||
|
|
aa855c4def | ||
|
|
46ff917edf | ||
|
|
3a5aa27fad |
@@ -5,8 +5,8 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<PackageId>Caspian.WorkflowFramework</PackageId>
|
<PackageId>Caspian.WorkflowFramework</PackageId>
|
||||||
<Version>1.1.0-preview.10</Version>
|
<Version>1.1.0-preview.25</Version>
|
||||||
<Authors>Digital banking team</Authors>
|
<Authors>Behzad Alizadeh</Authors>
|
||||||
<Company>Caspian</Company>
|
<Company>Caspian</Company>
|
||||||
<Product>Caspian.WorkflowFramework</Product>
|
<Product>Caspian.WorkflowFramework</Product>
|
||||||
<Description>Caspian Workflow Framework</Description>
|
<Description>Caspian Workflow Framework</Description>
|
||||||
@@ -17,58 +17,61 @@
|
|||||||
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>caspian-pkg-key.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>caspian-pkg-key.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<PackageOutputPath>
|
||||||
|
$(MSBuildThisFileDirectory)packages
|
||||||
|
</PackageOutputPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Caspian.Elsa.WorkflowContexts" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.WorkflowContexts" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Workflows.Runtime.Distributed" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Workflows.Runtime.Distributed" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Alterations" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Alterations" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Alterations.MassTransit" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Alterations.MassTransit" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Caching.Distributed.MassTransit" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Caching.Distributed.MassTransit" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Caching.Distributed.ProtoActor" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Caching.Distributed.ProtoActor" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.CSharp" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.CSharp" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Dapper" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Dapper" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Dapper.Migrations" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Dapper.Migrations" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.DropIns" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.DropIns" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Email" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Email" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Elasticsearch" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Elasticsearch" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Environments" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Environments" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.MySql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.MySql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Oracle" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Oracle" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.PostgreSql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.PostgreSql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Sqlite" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Sqlite" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.SqlServer" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.SqlServer" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.FileStorage" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.FileStorage" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Hangfire" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Hangfire" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Http" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Http" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Identity" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Identity" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Kafka" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Kafka" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Labels" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Labels" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Liquid" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Liquid" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.MassTransit" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.MassTransit" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.MassTransit.AzureServiceBus" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.MassTransit.AzureServiceBus" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.MassTransit.RabbitMq" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.MassTransit.RabbitMq" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.MongoDb" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.MongoDb" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.OpenTelemetry" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.OpenTelemetry" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Quartz" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Quartz" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.MySql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.MySql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.PostgreSql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.PostgreSql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.Sqlite" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.Sqlite" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Retention" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Retention" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Secrets.Api" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Secrets.Api" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Secrets.Persistence.EntityFrameworkCore.PostgreSql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Secrets.Persistence.EntityFrameworkCore.PostgreSql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Secrets.Persistence.EntityFrameworkCore.Sqlite" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Secrets.Persistence.EntityFrameworkCore.Sqlite" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Secrets.Persistence.EntityFrameworkCore.SqlServer" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Secrets.Persistence.EntityFrameworkCore.SqlServer" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Secrets.Scripting" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Secrets.Scripting" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Sql.MySql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Sql.MySql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Sql.PostgreSql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Sql.PostgreSql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Sql.Sqlite" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Sql.Sqlite" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Sql.SqlServer" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Sql.SqlServer" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Sql" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Sql" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Tenants.AspNetCore" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Tenants.AspNetCore" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa.Webhooks" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa.Webhooks" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="Caspian.Elsa" Version="1.1.0-preview.1" />
|
<PackageReference Include="Caspian.Elsa" Version="1.1.0-preview.8" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
|
||||||
|
|||||||
@@ -127,9 +127,9 @@ public static class DependencyInjection
|
|||||||
// engine.Execute("function sayHelloWorld() { return greet('World'); }");
|
// engine.Execute("function sayHelloWorld() { return greet('World'); }");
|
||||||
//});
|
//});
|
||||||
})
|
})
|
||||||
|
// برای ثبت Activityهایی مانند Elsa.SendHttpRequest
|
||||||
|
.UseHttp()
|
||||||
.UseWorkflowContexts();
|
.UseWorkflowContexts();
|
||||||
|
|
||||||
//elsa.AddFastEndpointsAssembly<Program>();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Optionally configure recurring tasks using alternative schedules.
|
// Optionally configure recurring tasks using alternative schedules.
|
||||||
@@ -172,7 +172,7 @@ public static class DependencyInjection
|
|||||||
// Captures unhandled exceptions and returns a JSON response.
|
// Captures unhandled exceptions and returns a JSON response.
|
||||||
app.UseJsonSerializationErrorHandler();
|
app.UseJsonSerializationErrorHandler();
|
||||||
|
|
||||||
//app.UseWorkflows();
|
app.UseWorkflows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,5 +48,15 @@ namespace Caspian.WorkflowFramework.Contracts
|
|||||||
/// Cancels the specified workflow instance.
|
/// Cancels the specified workflow instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<WorkflowResponse<dynamic>> CancelInstanceAsync(CancelWorkflowInstanceModel input);
|
Task<WorkflowResponse<dynamic>> CancelInstanceAsync(CancelWorkflowInstanceModel input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancels the specified workflow instance.
|
||||||
|
/// </summary>
|
||||||
|
Task<WorkflowResponse<dynamic>> ForceCancelInstanceAsync(CancelWorkflowInstanceModel input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evicts a workflow definition from cache (optional, commented out in service).
|
||||||
|
/// </summary>
|
||||||
|
Task EvictDefFromCacheAsync(string name, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,4 +14,6 @@ public class PublishEventModel
|
|||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public JsonElement EventData { get; set; }
|
public JsonElement EventData { get; set; }
|
||||||
|
|
||||||
|
public string? SessionId { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using Caspian.WorkflowFramework.Utility;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Caspian.WorkflowFramework.Models;
|
namespace Caspian.WorkflowFramework.Models;
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
@@ -24,10 +20,15 @@ public class WorkflowModel
|
|||||||
public string? InstanceMode { get; set; } = "exist";
|
public string? InstanceMode { get; set; } = "exist";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// نام گردش کار
|
/// کلیدواژه گردش کار
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// عنوان گردش کار
|
||||||
|
/// </summary>
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// اتمام گردش کار؟
|
/// اتمام گردش کار؟
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -61,6 +62,11 @@ public class WorkflowModel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int? PageNumber { get; set; }
|
public int? PageNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد کل صفحات
|
||||||
|
/// </summary>
|
||||||
|
public int? TotalPage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// رویدادی که باید پس از سابمیت صفحه بعدی منتشر شود
|
/// رویدادی که باید پس از سابمیت صفحه بعدی منتشر شود
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -70,4 +76,9 @@ public class WorkflowModel
|
|||||||
/// جای ذخیرهی موقت برای استفاده های بعدی
|
/// جای ذخیرهی موقت برای استفاده های بعدی
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public JsonElement? WorkflowStash { get; set; }
|
public JsonElement? WorkflowStash { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// مرحله
|
||||||
|
/// </summary>
|
||||||
|
public WorkflowPhase WorkflowPhase { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using Caspian.WorkflowFramework.Contracts;
|
||||||
using System.Dynamic;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Caspian.WorkflowFramework.Contracts;
|
|
||||||
using Caspian.WorkflowFramework.Models;
|
using Caspian.WorkflowFramework.Models;
|
||||||
using Caspian.WorkflowFramework.Utility;
|
using Caspian.WorkflowFramework.Utility;
|
||||||
using Elsa.Common.Entities;
|
using Elsa.Common.Entities;
|
||||||
@@ -11,11 +8,15 @@ using Elsa.Workflows.Management;
|
|||||||
using Elsa.Workflows.Management.Filters;
|
using Elsa.Workflows.Management.Filters;
|
||||||
using Elsa.Workflows.Models;
|
using Elsa.Workflows.Models;
|
||||||
using Elsa.Workflows.Runtime;
|
using Elsa.Workflows.Runtime;
|
||||||
|
using Elsa.Workflows.Runtime.Filters;
|
||||||
using Elsa.Workflows.Runtime.Messages;
|
using Elsa.Workflows.Runtime.Messages;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using San.MongoLogger;
|
using San.MongoLogger;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Caspian.WorkflowFramework.Services;
|
namespace Caspian.WorkflowFramework.Services;
|
||||||
public class WorkflowService : IWorkflowService, ILoggable
|
public class WorkflowService : IWorkflowService, ILoggable
|
||||||
@@ -29,6 +30,8 @@ public class WorkflowService : IWorkflowService, ILoggable
|
|||||||
private readonly IWorkflowInstanceStore _workflowInstanceStore;
|
private readonly IWorkflowInstanceStore _workflowInstanceStore;
|
||||||
private readonly IEventPublisher _eventPublisher;
|
private readonly IEventPublisher _eventPublisher;
|
||||||
private readonly IWorkflowDefinitionCacheManager _workflowDefinitionCacheManager;
|
private readonly IWorkflowDefinitionCacheManager _workflowDefinitionCacheManager;
|
||||||
|
private readonly IBookmarkStore _bookmarkStore;
|
||||||
|
private readonly IActivityExecutionStore _activityExecutionStore;
|
||||||
private readonly IMdbLogger<WorkflowService> _logger;
|
private readonly IMdbLogger<WorkflowService> _logger;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -42,7 +45,10 @@ public class WorkflowService : IWorkflowService, ILoggable
|
|||||||
_workflowInstanceVariableManager = _serviceProvider.GetRequiredService<IWorkflowInstanceVariableManager>();
|
_workflowInstanceVariableManager = _serviceProvider.GetRequiredService<IWorkflowInstanceVariableManager>();
|
||||||
_workflowInstanceManager = _serviceProvider.GetRequiredService<IWorkflowInstanceManager>();
|
_workflowInstanceManager = _serviceProvider.GetRequiredService<IWorkflowInstanceManager>();
|
||||||
_workflowInstanceStore = _serviceProvider.GetRequiredService<IWorkflowInstanceStore>();
|
_workflowInstanceStore = _serviceProvider.GetRequiredService<IWorkflowInstanceStore>();
|
||||||
|
_workflowDefinitionCacheManager = _serviceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
|
||||||
_eventPublisher = _serviceProvider.GetRequiredService<IEventPublisher>();
|
_eventPublisher = _serviceProvider.GetRequiredService<IEventPublisher>();
|
||||||
|
_bookmarkStore = _serviceProvider.GetRequiredService<IBookmarkStore>();
|
||||||
|
_activityExecutionStore = _serviceProvider.GetRequiredService<IActivityExecutionStore>();
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -256,65 +262,119 @@ public class WorkflowService : IWorkflowService, ILoggable
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PublishEventAsync
|
#region PublishEventAsync
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<WorkflowResponse<WorkflowModel>> PublishEventAsync(PublishEventModel input)
|
public async Task<WorkflowResponse<WorkflowModel>> PublishEventAsync(
|
||||||
|
PublishEventModel input)
|
||||||
{
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.Log("Start of PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, input);
|
_logger.Log(
|
||||||
|
"Start of PublishEventAsync",
|
||||||
|
WFInstanceId: input.WorkflowInstanceId,
|
||||||
|
input);
|
||||||
|
|
||||||
WorkflowResponse<WorkflowModel> response;
|
var instance = await _workflowInstanceManager.FindByIdAsync(
|
||||||
|
input.WorkflowInstanceId);
|
||||||
var instance = await _workflowInstanceManager.FindByIdAsync(input.WorkflowInstanceId);
|
|
||||||
|
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
{
|
{
|
||||||
var msg = $"Workflow instance with id '{input.WorkflowInstanceId}' not found";
|
var notFoundResponse = new WorkflowResponse<WorkflowModel>
|
||||||
response = new WorkflowResponse<WorkflowModel>()
|
|
||||||
{
|
{
|
||||||
Status = 1,
|
Status = 1,
|
||||||
Message = msg,
|
Message =
|
||||||
|
$"Workflow instance with id " +
|
||||||
|
$"'{input.WorkflowInstanceId}' not found",
|
||||||
Data = null
|
Data = null
|
||||||
};
|
};
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|
||||||
_logger.Log("End of PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds);
|
_logger.Log(
|
||||||
|
"End of PublishEventAsync",
|
||||||
|
WFInstanceId: input.WorkflowInstanceId,
|
||||||
|
notFoundResponse,
|
||||||
|
sw.ElapsedMilliseconds);
|
||||||
|
|
||||||
return response;
|
return notFoundResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic payload = null;
|
/*
|
||||||
|
* JsonElement
|
||||||
|
* ↓
|
||||||
|
* ExpandoObject
|
||||||
|
* ↓
|
||||||
|
* اضافهشدن SessionId
|
||||||
|
* ↓
|
||||||
|
* PublishEvent
|
||||||
|
*/
|
||||||
|
|
||||||
if (input.EventData.ValueKind != JsonValueKind.Undefined &&
|
ExpandoObject payload = new();
|
||||||
input.EventData.ValueKind != JsonValueKind.Null)
|
|
||||||
|
if (input.EventData.ValueKind is not JsonValueKind.Undefined
|
||||||
|
and not JsonValueKind.Null)
|
||||||
{
|
{
|
||||||
|
if (input.EventData.ValueKind != JsonValueKind.Object)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"EventData must be a JSON object.");
|
||||||
|
}
|
||||||
|
|
||||||
var json = input.EventData.GetRawText();
|
var json = input.EventData.GetRawText();
|
||||||
|
|
||||||
var settings = new JsonSerializerSettings
|
var serializerSettings = new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
Converters = { new ExpandoObjectConverter() }
|
Converters =
|
||||||
|
{
|
||||||
|
new ExpandoObjectConverter()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// تبدیل JSON به object داینامیک
|
payload =
|
||||||
payload = JsonConvert.DeserializeObject<ExpandoObject>(json, settings);
|
JsonConvert.DeserializeObject<ExpandoObject>(
|
||||||
|
json,
|
||||||
|
serializerSettings)
|
||||||
|
?? new ExpandoObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
//await _eventPublisher.PublishAsync(input.EventName, null, input.WorkflowInstanceId, null, input.EventData, asynchronous: true);
|
/*
|
||||||
await _eventPublisher.PublishAsync(input.EventName, null, input.WorkflowInstanceId, null, payload);
|
* ExpandoObject پیادهسازی IDictionary است؛
|
||||||
|
* بنابراین بدون Serialize/Deserialize مجدد میتوانیم
|
||||||
|
* SessionId را به Payload اضافه کنیم.
|
||||||
|
*/
|
||||||
|
if (!string.IsNullOrWhiteSpace(input.SessionId))
|
||||||
|
{
|
||||||
|
var payloadDictionary =
|
||||||
|
(IDictionary<string, object?>)payload;
|
||||||
|
|
||||||
var variables = await _workflowInstanceVariableManager.GetVariablesAsync(input.WorkflowInstanceId);
|
payloadDictionary["SessionId"] = input.SessionId;
|
||||||
|
}
|
||||||
|
|
||||||
// تبدیل به دیکشنری
|
await _eventPublisher.PublishAsync(
|
||||||
var dictionary = variables.ToDictionary(a => a.Variable.Name, a => a.Value);
|
eventName: input.EventName,
|
||||||
|
correlationId: null,
|
||||||
|
workflowInstanceId: input.WorkflowInstanceId,
|
||||||
|
activityInstanceId: null,
|
||||||
|
payload: payload,
|
||||||
|
asynchronous: false);
|
||||||
|
|
||||||
|
var variables =
|
||||||
|
await _workflowInstanceVariableManager.GetVariablesAsync(
|
||||||
|
input.WorkflowInstanceId);
|
||||||
|
|
||||||
|
var dictionary = variables.ToDictionary(
|
||||||
|
x => x.Variable.Name,
|
||||||
|
x => x.Value);
|
||||||
|
|
||||||
var workflowModel = dictionary.ConvertToWorkflowModel();
|
var workflowModel = dictionary.ConvertToWorkflowModel();
|
||||||
|
|
||||||
workflowModel.InstanceId = instance.Id;
|
workflowModel.InstanceId = instance.Id;
|
||||||
workflowModel.UserId = instance.ExternalUserId;
|
workflowModel.UserId = instance.ExternalUserId;
|
||||||
workflowModel.InstanceMode = "exist";
|
workflowModel.InstanceMode = "exist";
|
||||||
|
|
||||||
response = new WorkflowResponse<WorkflowModel>()
|
var response = new WorkflowResponse<WorkflowModel>
|
||||||
{
|
{
|
||||||
Status = 0,
|
Status = 0,
|
||||||
Message = "Success",
|
Message = "Success",
|
||||||
@@ -323,26 +383,36 @@ public class WorkflowService : IWorkflowService, ILoggable
|
|||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|
||||||
_logger.Log("End of PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds);
|
_logger.Log(
|
||||||
|
"End of PublishEventAsync",
|
||||||
|
WFInstanceId: input.WorkflowInstanceId,
|
||||||
|
response,
|
||||||
|
sw.ElapsedMilliseconds);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var response = new WorkflowResponse<WorkflowModel>()
|
sw.Stop();
|
||||||
|
|
||||||
|
var response = new WorkflowResponse<WorkflowModel>
|
||||||
{
|
{
|
||||||
Status = 100,
|
Status = 100,
|
||||||
Message = ex.Message,
|
Message = ex.Message,
|
||||||
Data = null
|
Data = null
|
||||||
};
|
};
|
||||||
|
|
||||||
sw.Stop();
|
_logger.Log(
|
||||||
|
"Exception occurs in PublishEventAsync",
|
||||||
_logger.Log("Exception occurs in PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds, ex);
|
WFInstanceId: input.WorkflowInstanceId,
|
||||||
|
response,
|
||||||
|
sw.ElapsedMilliseconds,
|
||||||
|
ex);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region InquiryStateAsync
|
#region InquiryStateAsync
|
||||||
@@ -678,6 +748,7 @@ public class WorkflowService : IWorkflowService, ILoggable
|
|||||||
new WorkflowInstanceFilter
|
new WorkflowInstanceFilter
|
||||||
{
|
{
|
||||||
ExternalUserId = input.UserId,
|
ExternalUserId = input.UserId,
|
||||||
|
Id = input.WorkflowInstanceId,
|
||||||
WorkflowStatus = WorkflowStatus.Running
|
WorkflowStatus = WorkflowStatus.Running
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -723,4 +794,117 @@ public class WorkflowService : IWorkflowService, ILoggable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region ForceCancelInstanceAsync
|
||||||
|
public async Task<WorkflowResponse<dynamic>> ForceCancelInstanceAsync(CancelWorkflowInstanceModel input)
|
||||||
|
{
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Log("Start ForceCancelInstanceAsync", WFInstanceId: input.WorkflowInstanceId, input);
|
||||||
|
|
||||||
|
var instance = await _workflowInstanceManager.FindByIdAsync(input.WorkflowInstanceId);
|
||||||
|
|
||||||
|
if (instance == null)
|
||||||
|
return new WorkflowResponse<dynamic> { Status = 1, Message = "Instance not found", Data = false };
|
||||||
|
|
||||||
|
// جلوگری از Resume شدن دوباره
|
||||||
|
instance.Status = WorkflowStatus.Finished;
|
||||||
|
instance.SubStatus = WorkflowSubStatus.Cancelled;
|
||||||
|
|
||||||
|
// پاکسازی bookmarks از دیتابیس واقعی
|
||||||
|
var bookmarkFilter = new BookmarkFilter()
|
||||||
|
{
|
||||||
|
WorkflowInstanceId = input.WorkflowInstanceId
|
||||||
|
};
|
||||||
|
await _bookmarkStore.DeleteAsync(bookmarkFilter);
|
||||||
|
|
||||||
|
// پاکسازی scheduled activities (در صورتی که runtime distributed باشد)
|
||||||
|
var activityFilter = new ActivityExecutionRecordFilter()
|
||||||
|
{
|
||||||
|
WorkflowInstanceId = input.WorkflowInstanceId
|
||||||
|
};
|
||||||
|
await _activityExecutionStore.DeleteManyAsync(activityFilter);
|
||||||
|
|
||||||
|
//// پاکسازی incidents (در پروژههای بزرگ ضروری است)
|
||||||
|
//await _incidentStore.DeleteManyAsync(
|
||||||
|
// x => x.WorkflowInstanceId == input.WorkflowInstanceId
|
||||||
|
//);
|
||||||
|
|
||||||
|
// ذخیره instance تغییر یافته
|
||||||
|
await _workflowInstanceManager.SaveAsync(instance);
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
|
||||||
|
var response = new WorkflowResponse<dynamic>
|
||||||
|
{
|
||||||
|
Status = 0,
|
||||||
|
Message = "Force cancel completed",
|
||||||
|
Data = true
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.Log("End ForceCancelInstanceAsync", WFInstanceId: instance.Id, response, sw.ElapsedMilliseconds);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
|
||||||
|
var response = new WorkflowResponse<dynamic>
|
||||||
|
{
|
||||||
|
Status = 100,
|
||||||
|
Message = ex.Message,
|
||||||
|
Data = false
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.Log("Exception in ForceCancelInstanceAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds, ex);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EvictDefFromCacheAsync
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task EvictDefFromCacheAsync(string name, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Log("Start of EvictDefFromCacheAsync", name);
|
||||||
|
|
||||||
|
var defFilter = new WorkflowDefinitionFilter()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
VersionOptions = VersionOptions.Published
|
||||||
|
};
|
||||||
|
|
||||||
|
var definition = await _workflowDefinitionService
|
||||||
|
.FindWorkflowDefinitionAsync(defFilter);
|
||||||
|
|
||||||
|
await _workflowDefinitionCacheManager.EvictWorkflowDefinitionAsync(definition.DefinitionId);
|
||||||
|
|
||||||
|
var workflowDefinitionFilter = new WorkflowDefinitionFilter()
|
||||||
|
{
|
||||||
|
DefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(definition.DefinitionId, VersionOptions.Published)
|
||||||
|
};
|
||||||
|
|
||||||
|
var createWorkflowDefinitionFilterCacheKey = _workflowDefinitionCacheManager.CreateWorkflowDefinitionFilterCacheKey(workflowDefinitionFilter);
|
||||||
|
_workflowDefinitionCacheManager.Cache.Remove(createWorkflowDefinitionFilterCacheKey);
|
||||||
|
|
||||||
|
|
||||||
|
var createWorkflowFilterCacheKey = _workflowDefinitionCacheManager.CreateWorkflowFilterCacheKey(workflowDefinitionFilter);
|
||||||
|
_workflowDefinitionCacheManager.Cache.Remove(createWorkflowFilterCacheKey);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
_logger.Log("End of EvictDefFromCacheAsync", name, sw.ElapsedMilliseconds, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,9 @@ namespace Caspian.WorkflowFramework.Utility
|
|||||||
if (dictionary == null || dictionary.Count == 0)
|
if (dictionary == null || dictionary.Count == 0)
|
||||||
return workflowModel;
|
return workflowModel;
|
||||||
|
|
||||||
|
// قبل از تبدیل به مدل خروجی، sessionId حذف میشود.
|
||||||
|
dictionary.RemoveSessionId();
|
||||||
|
|
||||||
//Map dictionary values to WorkflowModel properties
|
//Map dictionary values to WorkflowModel properties
|
||||||
workflowModel.InstanceId = dictionary.ContainsKey(nameof(workflowModel.InstanceId))
|
workflowModel.InstanceId = dictionary.ContainsKey(nameof(workflowModel.InstanceId))
|
||||||
? dictionary[nameof(workflowModel.InstanceId)]?.ToString()
|
? dictionary[nameof(workflowModel.InstanceId)]?.ToString()
|
||||||
@@ -31,6 +34,10 @@ namespace Caspian.WorkflowFramework.Utility
|
|||||||
? dictionary[nameof(workflowModel.Name)]?.ToString()
|
? dictionary[nameof(workflowModel.Name)]?.ToString()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
workflowModel.Title = dictionary.ContainsKey(nameof(workflowModel.Title))
|
||||||
|
? dictionary[nameof(workflowModel.Title)]?.ToString()
|
||||||
|
: null;
|
||||||
|
|
||||||
workflowModel.IsComplete = dictionary.ContainsKey(nameof(workflowModel.IsComplete))
|
workflowModel.IsComplete = dictionary.ContainsKey(nameof(workflowModel.IsComplete))
|
||||||
? bool.TryParse(dictionary[nameof(workflowModel.IsComplete)]?.ToString(), out var isComplete) && isComplete
|
? bool.TryParse(dictionary[nameof(workflowModel.IsComplete)]?.ToString(), out var isComplete) && isComplete
|
||||||
: false;
|
: false;
|
||||||
@@ -109,10 +116,52 @@ namespace Caspian.WorkflowFramework.Utility
|
|||||||
? int.TryParse(dictionary[nameof(workflowModel.PageNumber)]?.ToString(), out var pageNumber) ? pageNumber : (int?)null
|
? int.TryParse(dictionary[nameof(workflowModel.PageNumber)]?.ToString(), out var pageNumber) ? pageNumber : (int?)null
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
workflowModel.TotalPage = dictionary.ContainsKey(nameof(workflowModel.TotalPage))
|
||||||
|
? int.TryParse(dictionary[nameof(workflowModel.TotalPage)]?.ToString(), out var totalPage) ? totalPage : (int?)null
|
||||||
|
: null;
|
||||||
|
|
||||||
workflowModel.NextPageEventName = dictionary.ContainsKey(nameof(workflowModel.NextPageEventName))
|
workflowModel.NextPageEventName = dictionary.ContainsKey(nameof(workflowModel.NextPageEventName))
|
||||||
? dictionary[nameof(workflowModel.NextPageEventName)]?.ToString()
|
? dictionary[nameof(workflowModel.NextPageEventName)]?.ToString()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
//WorkflowStash
|
||||||
|
if (dictionary.TryGetValue(nameof(workflowModel.WorkflowStash), out var workflowStashObj) &&
|
||||||
|
workflowStashObj is not null)
|
||||||
|
{
|
||||||
|
switch (workflowStashObj)
|
||||||
|
{
|
||||||
|
case JsonElement je:
|
||||||
|
workflowModel.WorkflowStash = je;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonNode node:
|
||||||
|
// .NET 6+
|
||||||
|
workflowModel.WorkflowStash = JsonSerializer.SerializeToElement(node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case string s:
|
||||||
|
// اگر به صورت string JSON ذخیره شده
|
||||||
|
workflowModel.WorkflowStash = JsonSerializer.Deserialize<JsonElement>(s);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// هر نوع دیگری: serialize و تبدیل به JsonElement
|
||||||
|
workflowModel.WorkflowStash = JsonSerializer.SerializeToElement(workflowStashObj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
workflowModel.WorkflowStash = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
workflowModel.WorkflowPhase =
|
||||||
|
dictionary.TryGetValue(nameof(workflowModel.WorkflowPhase), out var phaseObj) &&
|
||||||
|
phaseObj != null &&
|
||||||
|
Enum.TryParse(typeof(WorkflowPhase), phaseObj.ToString(), out var phase)
|
||||||
|
? (WorkflowPhase)phase
|
||||||
|
: WorkflowPhase.Client;
|
||||||
|
|
||||||
return workflowModel;
|
return workflowModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Caspian.WorkflowFramework.Utility
|
||||||
|
{
|
||||||
|
public enum WorkflowPhase : short
|
||||||
|
{
|
||||||
|
Client = 0,
|
||||||
|
Admin
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace Caspian.WorkflowFramework.Utility;
|
||||||
|
|
||||||
|
public static class WorkflowVariableExtensions
|
||||||
|
{
|
||||||
|
private const string SessionIdKey = "SessionId";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SessionId را فقط از سطح اول دیکشنری متغیرهای Workflow حذف میکند.
|
||||||
|
/// مقایسه نام کلید به حروف بزرگ و کوچک حساس نیست.
|
||||||
|
/// </summary>
|
||||||
|
public static Dictionary<string, object?> RemoveSessionId(
|
||||||
|
this Dictionary<string, object?> variables)
|
||||||
|
{
|
||||||
|
if (variables is null || variables.Count == 0)
|
||||||
|
return variables!;
|
||||||
|
|
||||||
|
var sessionIdKey = variables.Keys.FirstOrDefault(
|
||||||
|
key => string.Equals(
|
||||||
|
key,
|
||||||
|
SessionIdKey,
|
||||||
|
StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (sessionIdKey is not null)
|
||||||
|
variables.Remove(sessionIdKey);
|
||||||
|
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,5 +8,7 @@
|
|||||||
<add key="Webhooks Core Preview" value="https://f.feedz.io/sfmskywalker/webhooks-core/nuget/index.json" />
|
<add key="Webhooks Core Preview" value="https://f.feedz.io/sfmskywalker/webhooks-core/nuget/index.json" />
|
||||||
<add key="Local Package source" value="D:\MyNugetPackages" />
|
<add key="Local Package source" value="D:\MyNugetPackages" />
|
||||||
<add key="Workflow Package source" value="D:\NugetPackageRepository\WorkflowPackages" />
|
<add key="Workflow Package source" value="D:\NugetPackageRepository\WorkflowPackages" />
|
||||||
|
<add key="Caspian package source" value="https://nuget.caspian.com/v3/index.json" />
|
||||||
|
<add key="Gitea Package source" value="D:\CaspianProjects\NugetPackageRepository\AllPackages" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Data Source=.;Initial Catalog=WfDb;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;"
|
"DefaultConnection": "Data Source=.;Initial Catalog=WfLive;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;"
|
||||||
},
|
},
|
||||||
"LogDatabaseSettings": {
|
"LogDatabaseSettings": {
|
||||||
"LogsCollectionName": "TestWorkflowCollection",
|
"LogsCollectionName": "TestWorkflowCollection",
|
||||||
|
|||||||
Reference in New Issue
Block a user