Add project files.

This commit is contained in:
Behzad Alizadeh
2025-07-02 16:25:46 +03:30
parent 7391bb6626
commit d58167d24a
137 changed files with 85333 additions and 0 deletions
@@ -0,0 +1,107 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>Caspian.WorkflowFramework</PackageId>
<Version>1.0.1-preview2</Version>
<Authors>Digital banking team</Authors>
<Company>Caspian</Company>
<Product>Caspian.WorkflowFramework</Product>
<Description>Caspian Workflow Framework</Description>
<PackageProjectUrl>https://caspco.ir</PackageProjectUrl>
<PackageIcon>package-icon.png</PackageIcon>
<PackageReadmeFile>readme.md</PackageReadmeFile>
<PackageTags>caspian, nextbank, workflow</PackageTags>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>caspian-pkg-key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Caspian.Elsa" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Expressions" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Alterations" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Alterations.Core" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Alterations.MassTransit" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Api.Client" Version="1.0.2-preview1" />
<PackageReference Include="Caspian.Elsa.Api.Common" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Caching" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Caching.Distributed.ProtoActor" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Common" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Connections.Api" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Connections.Core" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Connections.Models" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.CSharp" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Dapper.Migrations" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.DropIns" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.DropIns.Core" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Dsl" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Email" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Common" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.MySql" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Oracle" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.PostgreSql" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.Sqlite" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.EntityFrameworkCore.SqlServer" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Environments" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Features" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Hangfire" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Hosting.Management" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Http" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Identity" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.JavaScript" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.JavaScript.Libraries" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Liquid" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Mediator" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.ProtoActor.Core" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Python" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Quartz" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.MySql" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.PostgreSql" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.Sqlite" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Quartz.EntityFrameworkCore.SqlServer" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Retention" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.SasTokens" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Scheduling" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Sql.PostgreSql" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Sql.Sqlite" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Sql.SqlServer" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Tenants" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Tenants.AspNetCore" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Testing.Shared" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Testing.Shared.Component" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Testing.Shared.Integration" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Webhooks" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.WorkflowContexts" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.WorkflowProviders.BlobStorage" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Workflows.Api" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Workflows.Core" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Workflows.Management" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Workflows.Runtime" Version="1.0.1" />
<PackageReference Include="Caspian.Elsa.Workflows.Runtime.Distributed" Version="1.0.1" />
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
<PackageReference Include="MongoLogger" Version="1.9.2.8" />
</ItemGroup>
<ItemGroup>
<None Update="LICENSE.txt">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Update="package-icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Update="readme.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,130 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>Caspian.WorkflowFramework</id>
<version>1.0.0-preview34</version>
<authors>Digital Banking Team</authors>
<owners>Caspian</owners>
<description>Caspian workflow framework</description>
<projectUrl>https://caspco.ir</projectUrl>
<icon>package-icon.png</icon>
<readme>readme.md</readme>
<tags>caspian, nextbank, workflow</tags>
<license type="file">LICENSE.txt</license>
<dependencies>
<group targetFramework="net9.0">
<dependency id="Microsoft.EntityFrameworkCore" version="*" />
<dependency id="ConfigureAwait.Fody" version="*" />
<dependency id="Cronos" version="*" />
<dependency id="DistributedLock.Core" version="*" />
<dependency id="Fody" version="*" />
<dependency id="IronCompress" version="*" />
<dependency id="JetBrains.Annotations" version="*" />
<dependency id="LinqKit.Core" version="*" />
<dependency id="Microsoft.AspNetCore.Http.Abstractions" version="*" />
<dependency id="Microsoft.Extensions.Configuration" version="*" />
<dependency id="Microsoft.Extensions.Configuration.Json" version="*" />
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="*" />
<dependency id="Microsoft.Extensions.Hosting" version="*" />
<dependency id="Microsoft.Extensions.Hosting.Abstractions" version="*" />
<dependency id="Microsoft.Extensions.Logging" version="*" />
<dependency id="Microsoft.SourceLink.GitHub" version="*" />
<dependency id="MongoLogger" version="*" />
<dependency id="Open.Linq.AsyncExtensions" version="*" />
<dependency id="Proto.Actor" version="*" />
<dependency id="Proto.Cluster" version="*" />
<dependency id="Proto.Cluster.TestProvider" version="*" />
<dependency id="Proto.OpenTelemetry" version="*" />
<dependency id="Proto.Persistence" version="*" />
<dependency id="Proto.Remote" version="*" />
<dependency id="FastEndpoints" version="*" />
<dependency id="FastEndpoints.Security" version="*" />
<dependency id="FastEndpoints.Swagger" version="*" />
<dependency id="Microsoft.Extensions.DependencyInjection" version="*" />
<dependency id="Microsoft.Extensions.Options" version="*" />
<dependency id="NuGet.Packaging" version="*" />
<dependency id="NuGet.Protocol" version="*" />
<dependency id="System.Formats.Asn1" version="*" />
<dependency id="ThrottleDebounce" version="*" />
<dependency id="Microsoft.Extensions.Options.ConfigurationExtensions" version="*" />
<dependency id="Microsoft.Extensions.Caching.Memory" version="*" />
<dependency id="Scrutor" version="*" />
<dependency id="Google.Protobuf" version="*" />
<dependency id="Grpc.Tools" version="*" />
<dependency id="Proto.Cluster.CodeGen" version="*" />
<dependency id="Microsoft.Data.Sqlite" version="*" />
<dependency id="Microsoft.EntityFrameworkCore.Sqlite" version="*" />
<!-- <dependency id="Microsoft.EntityFrameworkCore.Design" version="*" /> -->
<dependency id="MailKit" version="*" />
<dependency id="Microsoft.Extensions.Http" version="*" />
<dependency id="FluentStorage" version="*" />
<dependency id="Microsoft.Extensions.Http.Resilience" version="*" />
<dependency id="Microsoft.Extensions.Resilience" version="*" />
<dependency id="Microsoft.Extensions.Http.Polly" version="*" />
<dependency id="WebhooksCore" version="*" />
<dependency id="Azure.Identity" version="*" />
<dependency id="Dapper" version="*" />
<dependency id="FluentMigrator" version="*" />
<dependency id="FluentMigrator.Runner" version="*" />
<dependency id="Microsoft.Data.Sqlite.Core" version="*" />
<dependency id="Microsoft.Identity.Client" version="*" />
<!-- <dependency id="Npgsql" /> -->
<dependency id="System.Data.SqlClient" version="*" />
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="*" />
<dependency id="System.CommandLine" version="*" />
<dependency id="DistributedLock.FileSystem" version="*" />
<!-- <dependency id="Microsoft.CodeAnalysis.CSharp.Scripting" version="*" /> -->
<dependency id="Antlr4.Runtime.Standard" version="*" />
<dependency id="System.Linq.Async" version="*" />
<dependency id="Jint" version="*" />
<dependency id="Fluid.Core" version="*" />
<dependency id="pythonnet" version="*" />
<dependency id="Microsoft.AspNetCore.DataProtection.Abstractions" version="*" />
<dependency id="AspNetCore.Authentication.ApiKey" version="*" />
<dependency id="Azure.Messaging.ServiceBus" version="*" />
<dependency id="Azure.ResourceManager.ServiceBus" version="*" />
<dependency id="Confluent.Kafka" version="*" />
<dependency id="Confluent.SchemaRegistry.Serdes.Avro" version="*" />
<dependency id="MassTransit" version="*" />
<dependency id="MassTransit.Azure.ServiceBus.Core" version="*" />
<dependency id="MassTransit.RabbitMQ" version="*" />
<dependency id="Hangfire" version="*" />
<dependency id="Hangfire.MemoryStorage" version="*" />
<dependency id="Hangfire.Storage.SQLite" version="*" />
<dependency id="Quartz.Extensions.Hosting" version="*" />
<dependency id="AppAny.Quartz.EntityFrameworkCore.Migrations.MySql" version="*" />
<dependency id="Quartz.Serialization.Json" version="*" />
<dependency id="AppAny.Quartz.EntityFrameworkCore.Migrations.SqlServer" version="*" />
<dependency id="Humanizer.Core" version="*" />
<dependency id="Newtonsoft.Json" version="*" />
<dependency id="ShortGuid" version="*" />
<dependency id="System.Linq.Dynamic.Core" version="*" />
<dependency id="PolySharp" version="*" />
</group>
</dependencies>
</metadata>
<files>
<!-- Include the favicon -->
<file src="favicon.ico" target="\" />
<!-- Include license, icon, and readme files -->
<file src="LICENSE.txt" target="\" />
<file src="package-icon.png" target="\" />
<file src="readme.md" target="\" />
<!-- Include all required DLLs in the lib folder -->
<file src="bin\release\net9.0\*.dll" target="lib\net9.0" />
<!-- <file src="..\..\common\Elsa.Features\bin\Release\net9.0\Elsa.Features.dll" target="lib\net9.0\Elsa.Features.dll" /> -->
<!-- <file src="..\..\modules\Elsa.CSharp\bin\Release\net9.0\Elsa.CSharp.dll" target="lib\net9.0\Elsa.CSharp.dll" /> -->
<!-- <file src="..\..\modules\Elsa.Email\bin\Release\net9.0\Elsa.Email.dll" target="lib\net9.0\Elsa.Email.dll" /> -->
<!-- <file src="..\..\modules\Elsa.EntityFrameworkCore.Common\bin\Release\net9.0\Elsa.EntityFrameworkCore.Common.dll" target="lib\net9.0\Elsa.EntityFrameworkCore.Common.dll" /> -->
<!-- <file src="..\..\modules\Elsa.EntityFrameworkCore.SqlServer\bin\Release\net9.0\Elsa.EntityFrameworkCore.SqlServer.dll" target="lib\net9.0\Elsa.EntityFrameworkCore.SqlServer.dll" /> -->
<!-- <file src="..\..\modules\Elsa.EntityFrameworkCore\bin\Release\net9.0\Elsa.EntityFrameworkCore.dll" target="lib\net9.0\Elsa.EntityFrameworkCore.dll" /> -->
<!-- <file src="..\..\modules\Elsa.JavaScript\bin\Release\net9.0\Elsa.JavaScript.dll" target="lib\net9.0\Elsa.JavaScript.dll" /> -->
<!-- <file src="..\..\modules\Elsa.Scheduling\bin\Release\net9.0\Elsa.Scheduling.dll" target="lib\net9.0\Elsa.Scheduling.dll" /> -->
<!-- <file src="..\..\modules\Elsa.Workflows.Api\bin\Release\net9.0\Elsa.Workflows.Api.dll" target="lib\net9.0\Elsa.Workflows.Api.dll" /> -->
<!-- <file src="..\..\modules\Elsa.Workflows.Management\bin\Release\net9.0\Elsa.Workflows.Management.dll" target="lib\net9.0\Elsa.Workflows.Management.dll" /> -->
<!-- <file src="..\..\modules\Elsa.Workflows.Runtime\bin\Release\net9.0\Elsa.Workflows.Runtime.dll" target="lib\net9.0\Elsa.Workflows.Runtime.dll" /> -->
<!-- <file src="..\..\modules\Elsa\bin\Release\net9.0\Elsa.dll" target="lib\net9.0\Elsa.dll" /> -->
</files>
</package>
@@ -0,0 +1,72 @@
using Caspian.WorkflowFramework.Contracts;
using Caspian.WorkflowFramework.Services;
using Elsa.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Elsa.EntityFrameworkCore.Extensions;
using Elsa.EntityFrameworkCore.Modules.Management;
using Elsa.EntityFrameworkCore.Modules.Runtime;
using Elsa.EntityFrameworkCore.Modules.Identity;
using Elsa.Email;
using MongoLogger;
using MongoLogger.Models;
namespace Caspian.WorkflowFramework;
public static class DependencyInjectionq
{
public static void AddWorkflowFramework(this IHostApplicationBuilder builder, string connectionString)
{
builder.Services.AddMongoLogger<LogModel>(builder.Configuration);
builder.Services.AddElsa(elsa =>
{
// Configure Management layer to use EF Core.
elsa.UseWorkflowManagement(management => management
.UseEntityFrameworkCore(ef => ef.UseSqlServer(connectionString)));
// Configure Runtime layer to use EF Core.
elsa.UseWorkflowRuntime(runtime => runtime
.UseEntityFrameworkCore(ef => ef.UseSqlServer(connectionString)));
// Expose Elsa API endpoints.
elsa.UseWorkflowsApi();
// Enable C# workflow expressions
elsa.UseCSharp();
// Enable JavaScript workflow expressions
elsa.UseJavaScript(options => options.AllowClrAccess = true);
});
//// Configure CORS to allow designer app hosted on a different origin to invoke the APIs.
//builder.Services.AddCors(cors => cors
// .AddDefaultPolicy(policy => policy
// .AllowAnyOrigin() // For demo purposes only. Use a specific origin instead.
// .AllowAnyHeader()
// .AllowAnyMethod()
// .WithExposedHeaders("x-elsa-workflow-instance-id"))); // Required for Elsa Studio in order to support running workflows from the designer. Alternatively, you can use the `*` wildcard to expose all headers.
// Add Health Checks.
builder.Services.AddHealthChecks();
builder.Services.AddScoped<IWorkflowService, WorkflowService>();
}
public static void UseWorkflowFramework(this IApplicationBuilder app)
{
try
{
app.UseMongoLogger<LogModel>();
}
catch (Exception ex)
{
var d = ex;
}
//app.UseWorkflowsApi(); // Use Elsa API endpoints.
app.UseWorkflows(); // Use Elsa middleware to handle HTTP requests mapped to HTTP Endpoint activities.
}
}
@@ -0,0 +1,29 @@
using Caspian.WorkflowFramework.Models;
namespace Caspian.WorkflowFramework.Contracts
{
public interface IWorkflowService
{
/// <summary>
/// Create and executes a new workflow instance.
/// </summary>
/// <param name="input"></param>
/// <returns>A new <see cref="WorkflowResponse<WorkflowModel>"/> object.</returns>
/// <remarks>Create a new workflow instance and executes it and waits for it to complete or reach a suspend point.</remarks>
Task<WorkflowResponse<WorkflowModel>> CreateAndExecuteAsync(CreateAndExecuteWorkflowModel input);
/// <summary>
/// Publishes the specified event.
/// </summary>
/// <param name="input"></param>
/// <returns>A new <see cref="WorkflowResponse<WorkflowModel>"/> object.</returns>
Task<WorkflowResponse<WorkflowModel>> PublishEventAsync(PublishEventModel input);
/// <summary>
/// Inquiry last state of workflow instance.
/// </summary>
/// <param name="input"></param>
/// <returns>A new <see cref="WorkflowResponse<WorkflowModel>"/> object.</returns>
Task<WorkflowResponse<WorkflowModel>> InquiryStateAsync(InquiryStateModel input);
}
}
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait />
</Weavers>
@@ -0,0 +1,3 @@
Terms and Conditions of Use, Reproduction and Distribution are permitted only for Caspian Company.
Copyright [2025] Caspian Company
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Elsa.Common.Models;
using JetBrains.Annotations;
namespace Caspian.WorkflowFramework.Models
{
[PublicAPI]
public class CreateAndExecuteWorkflowModel
{
/// <summary>
/// Workflow name
/// </summary>
[Required]
public string? Name { get; set; }
/// <summary>
/// Workflow version
/// </summary>
[Required]
public VersionOptions Version { get; set; }
/// <summary>
/// Current user's id
/// </summary>
[Required]
public long? UserId { get; set; }
}
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Caspian.WorkflowFramework.Models
{
public class InquiryStateModel
{
[Required]
public string WorkflowInstanceId { get; set; }
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Caspian.WorkflowFramework.Models
{
[PublicAPI]
public class PublishEventModel
{
[Required]
public string WorkflowInstanceId { get; set; }
[Required]
public string EventName { get; set; }
[Required]
public string? EventData { get; set; }
}
}
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Caspian.WorkflowFramework.Models
{
[PublicAPI]
public class WorkflowModel
{
/// <summary>
/// شناسه گردش کار
/// </summary>
public string? InstanceId { get; set; }
/// <summary>
/// نام گردش کار
/// </summary>
public string? Name { get; set; }
/// <summary>
/// اتمام گردش کار؟
/// </summary>
public bool IsComplete { get; set; }
/// <summary>
/// برای کدام کاربر؟
/// </summary>
public long? UserId { get; set; }
/// <summary>
/// داده صفحه جاری
/// </summary>
public string? CurrentPageData { get; set; }
/// <summary>
/// داده صفحه بعد
/// <remark>
/// فعلا استفاده ای نداریم
/// </remark>
/// </summary>
public string? NextPageData { get; set; }
/// <summary>
/// آدرس صفحه بعدی
/// </summary>
public string? NextPageUrl { get; set; }
/// <summary>
/// رویدادی که باید پس از سابمیت صفحه بعدی منتشر شود
/// </summary>
public string? NextPageEventName { get; set; }
}
}
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Caspian.WorkflowFramework.Models
{
[PublicAPI]
public class WorkflowResponse<T> : WorkflowResponseBase where T : class, new()
{
public WorkflowResponse()
{
Data = new T();
}
/// <summary>
/// پاسخ
/// </summary>
public T? Data { get; set; }
}
[PublicAPI]
public class WorkflowResponseBase
{
/// <summary>
/// وضعیت پاسخ
/// </summary>
public int? Status { get; set; }
/// <summary>
/// پیام پاسخ
/// </summary>
public string? Message { get; set; }
}
}
@@ -0,0 +1,251 @@
using Caspian.WorkflowFramework.Models;
using Caspian.WorkflowFramework.Contracts;
using Newtonsoft.Json;
using Elsa.Workflows.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Elsa.Workflows.Management;
using Elsa.Workflows.Management.Filters;
using Elsa.Workflows.Runtime.Messages;
using Elsa.Workflows.Models;
using Elsa.Common.Models;
using Caspian.WorkflowFramework.Utility;
using MongoLogger;
using System.Diagnostics;
namespace Caspian.WorkflowFramework.Services
{
public class WorkflowService : IWorkflowService, ILoggable
{
#region Fields
private readonly IServiceProvider _serviceProvider;
private readonly IWorkflowRuntime _workflowRuntime;
private readonly IWorkflowDefinitionService _workflowDefinitionService;
private readonly IWorkflowInstanceVariableManager _workflowInstanceVariableManager;
private readonly IWorkflowInstanceManager _workflowInstanceManager;
private readonly IEventPublisher _eventPublisher;
private readonly IMdbLogger<WorkflowService> _logger;
#endregion
#region Ctor
public WorkflowService(IServiceProvider serviceProvider,
IMdbLogger<WorkflowService> logger)
{
_serviceProvider = serviceProvider;
_workflowRuntime = _serviceProvider.GetRequiredService<IWorkflowRuntime>();
_workflowDefinitionService = _serviceProvider.GetRequiredService<IWorkflowDefinitionService>();
_workflowInstanceVariableManager = _serviceProvider.GetRequiredService<IWorkflowInstanceVariableManager>();
_workflowInstanceManager = _serviceProvider.GetRequiredService<IWorkflowInstanceManager>();
_eventPublisher = _serviceProvider.GetRequiredService<IEventPublisher>();
_logger = logger;
}
#endregion
#region CreateAndExecuteAsync
/// <inheritdoc />
public async Task<WorkflowResponse<WorkflowModel>> CreateAndExecuteAsync(CreateAndExecuteWorkflowModel input)
{
try
{
_logger.Log("Start of CreateAndExecuteAsync", JsonConvert.SerializeObject(input));
WorkflowResponse<WorkflowModel> response;
var workflowClient = await _workflowRuntime.CreateClientAsync();
var definition = await _workflowDefinitionService
.FindWorkflowDefinitionAsync(new WorkflowDefinitionFilter()
{
Name = input.Name
});
if (definition == null)
{
var msg = $"Workflow '{input.Name}' defintion not found";
response = new WorkflowResponse<WorkflowModel>()
{
Status = 1,
Message = msg,
Data = null
};
_logger.Log("End of CreateAndExecuteAsync", WFInstanceId: response.Data?.InstanceId, JsonConvert.SerializeObject(response));
return response;
}
var instanceInput = new Dictionary<string, object> { ["UserId"] = input.UserId };
input.Version = VersionOptions.Published;
var newInstance = await workflowClient.CreateInstanceAsync(new CreateWorkflowInstanceRequest
{
WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(definition.DefinitionId, input.Version),
Input = instanceInput,
ExternalUserId = input.UserId
});
var result = await workflowClient.RunInstanceAsync(RunWorkflowInstanceRequest.Empty);
var variables = await _workflowInstanceVariableManager.GetVariablesAsync(result.WorkflowInstanceId);
// تبدیل به دیکشنری
var dictionary = variables.ToDictionary(a => a.Variable.Name, a => a.Value);
var workflowModel = dictionary.ConvertToWorkflowModel();
workflowModel.InstanceId = workflowClient.WorkflowInstanceId;
workflowModel.UserId = input.UserId;
response = new WorkflowResponse<WorkflowModel>()
{
Status = 0,
Message = "Success",
Data = workflowModel
};
_logger.Log("End of CreateAndExecuteAsync", WFInstanceId: response.Data?.InstanceId, JsonConvert.SerializeObject(response));
return response;
}
catch (Exception ex)
{
var response = new WorkflowResponse<WorkflowModel>()
{
Status = 100,
Message = ex.Message,
Data = null
};
_logger.Log("Exception occurs in CreateAndExecuteAsync", WFInstanceId: response.Data?.InstanceId, JsonConvert.SerializeObject(response), ex);
return response;
}
}
#endregion
#region PublishEventAsync
/// <inheritdoc />
public async Task<WorkflowResponse<WorkflowModel>> PublishEventAsync(PublishEventModel input)
{
try
{
_logger.Log("Start of PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(input));
WorkflowResponse<WorkflowModel> response;
var instance = await _workflowInstanceManager.FindByIdAsync(input.WorkflowInstanceId);
if (instance == null)
{
var msg = $"Workflow instance with id '{input.WorkflowInstanceId}' not found";
response = new WorkflowResponse<WorkflowModel>()
{
Status = 1,
Message = msg,
Data = null
};
_logger.Log("End of PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(response));
return response;
}
await _eventPublisher.PublishAsync(input.EventName, null, input.WorkflowInstanceId, null, input.EventData);
var variables = await _workflowInstanceVariableManager.GetVariablesAsync(input.WorkflowInstanceId);
// تبدیل به دیکشنری
var dictionary = variables.ToDictionary(a => a.Variable.Name, a => a.Value);
var workflowModel = dictionary.ConvertToWorkflowModel();
workflowModel.InstanceId = instance.Id;
workflowModel.UserId = instance.ExternalUserId;
response = new WorkflowResponse<WorkflowModel>()
{
Status = 0,
Message = "Success",
Data = workflowModel
};
_logger.Log("End of PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(response));
return response;
}
catch (Exception ex)
{
var response = new WorkflowResponse<WorkflowModel>()
{
Status = 100,
Message = ex.Message,
Data = null
};
_logger.Log("Exception occurs in PublishEventAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(response), ex);
return response;
}
}
#endregion
#region InquiryStateAsync
/// <inheritdoc />
public async Task<WorkflowResponse<WorkflowModel>> InquiryStateAsync(InquiryStateModel input)
{
try
{
_logger.Log("Start of InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(input));
WorkflowResponse<WorkflowModel> response;
var instance = await _workflowInstanceManager.FindByIdAsync(input.WorkflowInstanceId);
if (instance == null)
{
var msg = $"Workflow instance with id '{input.WorkflowInstanceId}' not found";
response = new WorkflowResponse<WorkflowModel>()
{
Status = 1,
Message = msg,
Data = null
};
_logger.Log("End of InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(response));
return response;
}
var variables = await _workflowInstanceVariableManager.GetVariablesAsync(input.WorkflowInstanceId);
// تبدیل به دیکشنری
var dictionary = variables.ToDictionary(a => a.Variable.Name, a => a.Value);
var workflowModel = dictionary.ConvertToWorkflowModel();
workflowModel.InstanceId = instance.Id;
workflowModel.UserId = instance.ExternalUserId;
response = new WorkflowResponse<WorkflowModel>()
{
Status = 0,
Message = "Success",
Data = workflowModel
};
_logger.Log("End of InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(response));
return response;
}
catch (Exception ex)
{
var response = new WorkflowResponse<WorkflowModel>()
{
Status = 100,
Message = ex.Message,
Data = null
};
_logger.Log("Exception occurs in InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, JsonConvert.SerializeObject(response), ex);
return response;
}
}
#endregion
}
}
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Caspian.WorkflowFramework.Models;
namespace Caspian.WorkflowFramework.Utility
{
public static class ConversionExtensions
{
public static WorkflowModel ConvertToWorkflowModel(this Dictionary<string, object?> dictionary)
{
var workflowModel = new WorkflowModel();
if (dictionary == null || dictionary.Count == 0)
return workflowModel;
//Map dictionary values to WorkflowModel properties
workflowModel.InstanceId = dictionary.ContainsKey(nameof(workflowModel.InstanceId))
? dictionary[nameof(workflowModel.InstanceId)]?.ToString()
: null;
workflowModel.Name = dictionary.ContainsKey(nameof(workflowModel.Name))
? dictionary[nameof(workflowModel.Name)]?.ToString()
: null;
workflowModel.IsComplete = dictionary.ContainsKey(nameof(workflowModel.IsComplete))
? bool.TryParse(dictionary[nameof(workflowModel.IsComplete)]?.ToString(), out var isComplete) && isComplete
: false;
workflowModel.UserId = dictionary.ContainsKey(nameof(workflowModel.UserId))
? long.TryParse(dictionary[nameof(workflowModel.UserId)]?.ToString(), out var userId) ? userId : (long?)null
: null;
//workflowModel.CurrentPageData = dictionary.ContainsKey(nameof(workflowModel.CurrentPageData))
// ? (object?)dictionary[nameof(workflowModel.CurrentPageData)]
// : null;
workflowModel.CurrentPageData = dictionary.ContainsKey(nameof(workflowModel.CurrentPageData))
? dictionary[nameof(workflowModel.CurrentPageData)]?.ToString()
: null;
//workflowModel.NextPageData = dictionary.ContainsKey(nameof(workflowModel.NextPageData))
// ? (object?)dictionary[nameof(workflowModel.NextPageData)]
// : null;
workflowModel.NextPageData = dictionary.ContainsKey(nameof(workflowModel.NextPageData))
? dictionary[nameof(workflowModel.NextPageData)]?.ToString()
: null;
workflowModel.NextPageUrl = dictionary.ContainsKey(nameof(workflowModel.NextPageUrl))
? dictionary[nameof(workflowModel.NextPageUrl)]?.ToString()
: null;
workflowModel.NextPageEventName = dictionary.ContainsKey(nameof(workflowModel.NextPageEventName))
? dictionary[nameof(workflowModel.NextPageEventName)]?.ToString()
: null;
return workflowModel;
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.
@@ -0,0 +1 @@
nuget pack Caspian.WorkflowFramework.nuspec -IncludeReferencedProjects
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,37 @@
# Caspian.WorkflowFramework
Caspian workflow framework
## Installation
```bash
install-package Caspian.WorkflowFramework
```
## Usage Example
In your Program.cs :
```csharp
//Workflow
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.AddWorkflowFramework(connectionString);
//Mongo
builder.Services.AddMongoLogger<LogModel>(builder.Configuration);
var app = builder.Build();
//Mongo
app.UseMongoLogger<LogModel>();
//Workflow
app.UseWorkflowFramework();
```
Then use service "WorkflowService"
## Features
- Start new instance of every workflow
- Publish event and get next step information
- Get last status of workflow instance
## Version History
### 1.0.0-alfa
- Initial prerelease