73 changed files with 4074 additions and 46 deletions
@ -1,32 +1,13 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.RabbitMQ; |
|||
using WorkflowCore.Interface; |
|||
using WorkflowCore.Models; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowCore.RabbitMQ |
|||
{ |
|||
[DependsOn(typeof(AbpUnitOfWorkModule))] |
|||
[DependsOn(typeof(AbpRabbitMqModule))] |
|||
[DependsOn(typeof(AbpWorkflowCoreModule))] |
|||
public class AbpWorkflowCoreRabbitMQModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddSingleton<IQueueProvider, AbpRabbitMqQueueProvider>(); |
|||
context.Services.AddSingleton<AbpRabbitMqQueueProvider>(); |
|||
|
|||
PreConfigure<WorkflowOptions>(options => |
|||
{ |
|||
options.UseQueueProvider(provider => provider.GetRequiredService<AbpRabbitMqQueueProvider>()); |
|||
}); |
|||
} |
|||
|
|||
public override void OnApplicationShutdown(ApplicationShutdownContext context) |
|||
{ |
|||
context.ServiceProvider |
|||
.GetRequiredService<AbpRabbitMqQueueProvider>() |
|||
.Dispose(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,67 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Uow; |
|||
using WorkflowCore.Interface; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowCore |
|||
{ |
|||
/// <summary>
|
|||
/// 当触发新的工作流时,如果持久层在事务中会导致默认队列获取工作流实例失败
|
|||
/// 建立一个事务适配队列在工作单元结束时再将消息入队
|
|||
/// </summary>
|
|||
public class AbpUnitOfWorkQueueProvider : IQueueProvider |
|||
{ |
|||
private readonly IUnitOfWorkManager _unitOfWorkManager; |
|||
private readonly IQueueAdapterProvider _queueProvider; |
|||
|
|||
public AbpUnitOfWorkQueueProvider( |
|||
IQueueAdapterProvider queueProvider, |
|||
IUnitOfWorkManager unitOfWorkManager) |
|||
{ |
|||
_queueProvider = queueProvider; |
|||
_unitOfWorkManager = unitOfWorkManager; |
|||
} |
|||
|
|||
public bool IsDequeueBlocking => _queueProvider.IsDequeueBlocking; |
|||
|
|||
public virtual async Task<string> DequeueWork(QueueType queue, CancellationToken cancellationToken) |
|||
{ |
|||
if (_unitOfWorkManager.Current != null && !_unitOfWorkManager.Current.IsCompleted) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return await _queueProvider.DequeueWork(queue, cancellationToken); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_queueProvider.Dispose(); |
|||
} |
|||
|
|||
public async Task QueueWork(string id, QueueType queue) |
|||
{ |
|||
if (_unitOfWorkManager.Current != null) |
|||
{ |
|||
_unitOfWorkManager.Current.OnCompleted(async () => |
|||
{ |
|||
await _queueProvider.QueueWork(id, queue); |
|||
}); |
|||
} |
|||
else |
|||
{ |
|||
await _queueProvider.QueueWork(id, queue); |
|||
} |
|||
} |
|||
|
|||
public async Task Start() |
|||
{ |
|||
await _queueProvider.Start(); |
|||
} |
|||
|
|||
public async Task Stop() |
|||
{ |
|||
await _queueProvider.Stop(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using WorkflowCore.Interface; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowCore |
|||
{ |
|||
public interface IQueueAdapterProvider : IDisposable |
|||
{ |
|||
bool IsDequeueBlocking { get; } |
|||
|
|||
Task QueueWork(string id, QueueType queue); |
|||
|
|||
Task<string> DequeueWork(QueueType queue, CancellationToken cancellationToken); |
|||
|
|||
Task Start(); |
|||
|
|||
Task Stop(); |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using WorkflowCore.Interface; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowCore |
|||
{ |
|||
[Dependency(TryRegister = true)] |
|||
public class SingleNodeQueueAdapterProvider : IQueueAdapterProvider, ISingletonDependency |
|||
{ |
|||
private readonly Dictionary<QueueType, BlockingCollection<string>> _queues = new Dictionary<QueueType, BlockingCollection<string>> |
|||
{ |
|||
[QueueType.Workflow] = new BlockingCollection<string>(), |
|||
[QueueType.Event] = new BlockingCollection<string>(), |
|||
[QueueType.Index] = new BlockingCollection<string>() |
|||
}; |
|||
|
|||
public bool IsDequeueBlocking => true; |
|||
|
|||
public Task QueueWork(string id, QueueType queue) |
|||
{ |
|||
_queues[queue].Add(id); |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task<string> DequeueWork(QueueType queue, CancellationToken cancellationToken) |
|||
{ |
|||
if (_queues[queue].TryTake(out string id, 100, cancellationToken)) |
|||
return Task.FromResult(id); |
|||
|
|||
return Task.FromResult<string>(null); |
|||
} |
|||
|
|||
public Task Start() |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task Stop() |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
public class ActivityFailureInput |
|||
{ |
|||
[Required] |
|||
public string Token { get; set; } |
|||
|
|||
[Required] |
|||
public object Result { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
public class ActivityReleaseInput |
|||
{ |
|||
public string Token { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
public class ActivitySuccessInput |
|||
{ |
|||
[Required] |
|||
public string Token { get; set; } |
|||
|
|||
[Required] |
|||
public object Result { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
public class GetPendingActivityInput |
|||
{ |
|||
public string ActivityName { get; set; } |
|||
|
|||
public string WorkflowId { get; set; } |
|||
|
|||
public TimeSpan? Timeout { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
public class PendingActivityDto |
|||
{ |
|||
public string Token { get; set; } |
|||
|
|||
public string ActivityName { get; set; } |
|||
|
|||
public object Parameters { get; set; } |
|||
|
|||
public DateTime TokenExpiry { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
public interface IActivityAppService : IApplicationService |
|||
{ |
|||
Task<PendingActivityDto> GetAsync(GetPendingActivityInput input); |
|||
|
|||
Task DeleteAsync(ActivityReleaseInput input); |
|||
|
|||
Task SuccessAsync(ActivitySuccessInput input); |
|||
|
|||
Task FailureAsync(ActivityFailureInput input); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Events |
|||
{ |
|||
public class EventPublishInput |
|||
{ |
|||
[Required] |
|||
public string EventName { get; set; } |
|||
|
|||
[Required] |
|||
public string EventKey { get; set; } |
|||
|
|||
[Required] |
|||
public object EventData { get; set; } |
|||
|
|||
public DateTime? EffectiveDate { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Events |
|||
{ |
|||
public interface IEventAppService : IApplicationService |
|||
{ |
|||
Task PublishAsync(EventPublishInput input); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Data; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
public class StepDto |
|||
{ |
|||
public string Name { get; set; } |
|||
public string StepType { get; set; } |
|||
public string CancelCondition { get; set; } |
|||
public TimeSpan? RetryInterval { get; set; } |
|||
public bool Saga { get; set; } |
|||
public string NextStep { get; set; } |
|||
public List<StepDto> CompensateWith { get; set; } = new List<StepDto>(); |
|||
public ExtraPropertyDictionary Inputs { get; set; } = new ExtraPropertyDictionary(); |
|||
public ExtraPropertyDictionary Outputs { get; set; } = new ExtraPropertyDictionary(); |
|||
public ExtraPropertyDictionary SelectNextStep { get; set; } = new ExtraPropertyDictionary(); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
public class WorkflowCreateDto |
|||
{ |
|||
/// <summary>
|
|||
/// 是否启用
|
|||
/// </summary>
|
|||
public bool IsEnabled { get; set; } |
|||
/// <summary>
|
|||
/// 名称
|
|||
/// </summary>
|
|||
public string Name { get; set; } |
|||
/// <summary>
|
|||
/// 显示名称
|
|||
/// </summary>
|
|||
public string DisplayName { get; set; } |
|||
/// <summary>
|
|||
/// 描述
|
|||
/// </summary>
|
|||
public string Description { get; set; } |
|||
/// <summary>
|
|||
/// 版本号
|
|||
/// </summary>
|
|||
public int Version { get; set; } |
|||
|
|||
public List<StepDto> Steps { get; set; } = new List<StepDto>(); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
public class WorkflowDefinitionDto |
|||
{ |
|||
/// <summary>
|
|||
/// 描述
|
|||
/// </summary>
|
|||
public string Description { get; set; } |
|||
/// <summary>
|
|||
/// 版本号
|
|||
/// </summary>
|
|||
public int Version { get; set; } |
|||
|
|||
public List<StepDto> Steps { get; set; } = new List<StepDto>(); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
public class WorkflowDto |
|||
{ |
|||
public string WorkflowId { get; set; } |
|||
public object Data { get; set; } |
|||
public string DefinitionId { get; set; } |
|||
public int Version { get; set; } |
|||
public string Status { get; set; } |
|||
public string Reference { get; set; } |
|||
public DateTime StartTime { get; set; } |
|||
public DateTime? EndTime { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
public class WorkflowStartInput |
|||
{ |
|||
public Dictionary<string, object> Data { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
public interface IWorkflowAppService : IApplicationService |
|||
{ |
|||
Task<WorkflowDto> GetAsync(string id); |
|||
|
|||
Task CreateAsync(WorkflowCreateDto input); |
|||
|
|||
Task<WorkflowDto> StartAsync(string id, WorkflowStartInput input); |
|||
|
|||
Task SuspendAsync(string id); |
|||
|
|||
Task ResumeAsync(string id); |
|||
|
|||
Task TerminateAsync(string id); |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System.Threading.Tasks; |
|||
using WorkflowCore.Interface; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
[Authorize] |
|||
public class ActivityAppService : WorkflowManagementAppServiceBase, IActivityAppService |
|||
{ |
|||
private readonly IActivityController _controller; |
|||
|
|||
public ActivityAppService(IActivityController controller) |
|||
{ |
|||
_controller = controller; |
|||
} |
|||
|
|||
public virtual async Task FailureAsync(ActivityFailureInput input) |
|||
{ |
|||
await _controller.SubmitActivityFailure(input.Token, input.Result); |
|||
} |
|||
|
|||
public virtual async Task<PendingActivityDto> GetAsync(GetPendingActivityInput input) |
|||
{ |
|||
var activity = await _controller.GetPendingActivity( |
|||
input.ActivityName, input.WorkflowId, input.Timeout); |
|||
|
|||
return ObjectMapper.Map<PendingActivity, PendingActivityDto>(activity); |
|||
} |
|||
|
|||
public virtual async Task DeleteAsync(ActivityReleaseInput input) |
|||
{ |
|||
await _controller.ReleaseActivityToken(input.Token); |
|||
} |
|||
|
|||
public virtual async Task SuccessAsync(ActivitySuccessInput input) |
|||
{ |
|||
await _controller.SubmitActivitySuccess(input.Token, input.Result); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System.Threading.Tasks; |
|||
using WorkflowCore.Interface; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Events |
|||
{ |
|||
[Authorize] |
|||
public class EventAppService : WorkflowManagementAppServiceBase, IEventAppService |
|||
{ |
|||
private readonly IWorkflowController _controller; |
|||
|
|||
public EventAppService(IWorkflowController controller) |
|||
{ |
|||
_controller = controller; |
|||
} |
|||
|
|||
public virtual async Task PublishAsync(EventPublishInput input) |
|||
{ |
|||
await _controller.PublishEvent(input.EventName, input.EventKey, input.EventData, input.EffectiveDate); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,165 @@ |
|||
using Newtonsoft.Json; |
|||
using System.Collections.Generic; |
|||
using System.Text.Json; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using WorkflowCore.Interface; |
|||
using WorkflowCore.Models; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
//[Authorize]
|
|||
public class WorkflowAppService : WorkflowManagementAppServiceBase, IWorkflowAppService |
|||
{ |
|||
private readonly WorkflowManager _workflowManager; |
|||
private readonly IWorkflowController _controller; |
|||
private readonly IPersistenceProvider _persistence; |
|||
private readonly IWorkflowRepository _workflowRepository; |
|||
private readonly IStepNodeRepository _stepNodeRepository; |
|||
private readonly ICompensateNodeRepository _compensateNodeRepository; |
|||
|
|||
public WorkflowAppService( |
|||
IWorkflowController controller, |
|||
IPersistenceProvider persistence, |
|||
WorkflowManager workflowManager, |
|||
IWorkflowRepository workflowRepository, |
|||
IStepNodeRepository stepNodeRepository, |
|||
ICompensateNodeRepository compensateNodeRepository) |
|||
{ |
|||
_controller = controller; |
|||
_persistence = persistence; |
|||
_workflowManager = workflowManager; |
|||
_workflowRepository = workflowRepository; |
|||
_stepNodeRepository = stepNodeRepository; |
|||
_compensateNodeRepository = compensateNodeRepository; |
|||
} |
|||
|
|||
public virtual async Task<WorkflowDto> GetAsync(string id) |
|||
{ |
|||
var workflow = await _persistence.GetWorkflowInstance(id); |
|||
|
|||
return ObjectMapper.Map<WorkflowInstance, WorkflowDto>(workflow); |
|||
} |
|||
|
|||
public virtual async Task ResumeAsync(string id) |
|||
{ |
|||
var result = await _controller.ResumeWorkflow(id); |
|||
if (!result) |
|||
{ |
|||
throw new BusinessException(); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task CreateAsync(WorkflowCreateDto input) |
|||
{ |
|||
if (await _workflowRepository.CheckVersionAsync(input.Name, input.Version)) |
|||
{ |
|||
throw new BusinessException(); |
|||
} |
|||
|
|||
var workflow = new Workflow( |
|||
GuidGenerator.Create(), |
|||
input.Name, |
|||
input.Description, |
|||
input.Description, |
|||
input.Version, |
|||
tenantId: CurrentTenant.Id); |
|||
|
|||
var stepNodes = new List<StepNode>(); |
|||
var stepCompensateNodes = new List<CompensateNode>(); |
|||
|
|||
ICollection<CompensateNode> CreateCompensateNodes(StepNode node, ICollection<StepDto> steps) |
|||
{ |
|||
var stepNodes = new List<CompensateNode>(); |
|||
foreach (var step in steps) |
|||
{ |
|||
var stepNode = new CompensateNode( |
|||
GuidGenerator.Create(), |
|||
workflow.Id, |
|||
step.Name, |
|||
step.StepType, |
|||
step.CancelCondition, |
|||
saga: step.Saga, |
|||
parentId: node.Id, |
|||
tenantId: CurrentTenant.Id); |
|||
stepNode.Inputs.AddIfNotContains(step.Inputs); |
|||
stepNode.Outputs.AddIfNotContains(step.Outputs); |
|||
stepNode.SelectNextStep.AddIfNotContains(step.SelectNextStep); |
|||
|
|||
stepNodes.Add(stepNode); |
|||
} |
|||
return stepNodes; |
|||
} |
|||
|
|||
foreach (var stepInput in input.Steps) |
|||
{ |
|||
var stepNode = new StepNode( |
|||
GuidGenerator.Create(), |
|||
workflow.Id, |
|||
stepInput.Name, |
|||
stepInput.StepType, |
|||
stepInput.CancelCondition, |
|||
saga: stepInput.Saga, |
|||
tenantId: CurrentTenant.Id); |
|||
stepNode.Inputs.AddIfNotContains(stepInput.Inputs); |
|||
stepNode.Outputs.AddIfNotContains(stepInput.Outputs); |
|||
stepNode.SelectNextStep.AddIfNotContains(stepInput.SelectNextStep); |
|||
|
|||
stepNodes.Add(stepNode); |
|||
stepCompensateNodes.AddRange(CreateCompensateNodes(stepNode, stepInput.CompensateWith)); |
|||
} |
|||
|
|||
await _workflowRepository.InsertAsync(workflow); |
|||
await _stepNodeRepository.InsertManyAsync(stepNodes); |
|||
await _compensateNodeRepository.InsertManyAsync(stepCompensateNodes); |
|||
|
|||
_workflowManager.Register(workflow, stepNodes, stepCompensateNodes); |
|||
} |
|||
|
|||
public virtual async Task<WorkflowDto> StartAsync(string id, WorkflowStartInput input) |
|||
{ |
|||
var workflowData = new Dictionary<string, object>(); |
|||
foreach (var data in input.Data) |
|||
{ |
|||
if (data.Value is JsonElement element) |
|||
{ |
|||
//var dataDic = new Dictionary<string, object>();
|
|||
//var children = element.EnumerateObject();
|
|||
//while (children.MoveNext())
|
|||
//{
|
|||
// dataDic.TryAdd(children.Current.Name, children.Current.Value.ToString());
|
|||
//}
|
|||
//JsonConvert.DeserializeObject(element.ToString())
|
|||
workflowData.TryAdd(data.Key, JsonConvert.DeserializeObject(element.ToString())); |
|||
} |
|||
else |
|||
{ |
|||
workflowData.TryAdd(data.Key, data.Value); |
|||
} |
|||
} |
|||
|
|||
var instanceId = await _controller.StartWorkflow(id, workflowData); |
|||
var result = await _persistence.GetWorkflowInstance(instanceId); |
|||
|
|||
return ObjectMapper.Map<WorkflowInstance, WorkflowDto>(result); |
|||
} |
|||
|
|||
public virtual async Task SuspendAsync(string id) |
|||
{ |
|||
var result = await _controller.SuspendWorkflow(id); |
|||
if (!result) |
|||
{ |
|||
throw new BusinessException(); |
|||
} |
|||
} |
|||
|
|||
public virtual async Task TerminateAsync(string id) |
|||
{ |
|||
var result = await _controller.TerminateWorkflow(id); |
|||
if (!result) |
|||
{ |
|||
throw new BusinessException(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public static class WorkflowConsts |
|||
{ |
|||
public static int MaxCancelConditionLength { get; set; } = 200; |
|||
public static int MaxNameLength { get; set; } = 100; |
|||
public static int MaxDisplayNameLength { get; set; } = 200; |
|||
public static int MaxDescriptionLength { get; set; } = 200; |
|||
public static int MaxStepTypeLength { get; set; } = 100; |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using System; |
|||
using WorkflowCore.Models; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public class CompensateNode : Step |
|||
{ |
|||
public CompensateNode() |
|||
{ |
|||
} |
|||
|
|||
public CompensateNode( |
|||
Guid id, |
|||
Guid workflowId, |
|||
string name, |
|||
string stepType, |
|||
string cancelCondition, |
|||
WorkflowErrorHandling? errorBehavior = null, |
|||
TimeSpan? retryInterval = null, |
|||
bool saga = false, |
|||
Guid? parentId = null, |
|||
Guid? tenantId = null) |
|||
: base(id, workflowId, name, stepType, cancelCondition, errorBehavior, retryInterval, saga, parentId, tenantId) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public interface ICompensateNodeRepository : IRepository<CompensateNode, Guid> |
|||
{ |
|||
Task<List<CompensateNode>> GetAllChildrenWithWorkflowAsync( |
|||
Guid workflowId, |
|||
CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using Volo.Abp.Data; |
|||
using WorkflowCore.Models; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public interface IStep |
|||
{ |
|||
Guid WorkflowId { get; } |
|||
string Name { get; } |
|||
string StepType { get; } |
|||
Guid? ParentId { get; } |
|||
WorkflowErrorHandling? ErrorBehavior { get; } |
|||
string CancelCondition { get; set; } |
|||
TimeSpan? RetryInterval { get; set; } |
|||
bool Saga { get; set; } |
|||
ExtraPropertyDictionary Inputs { get; set; } |
|||
ExtraPropertyDictionary Outputs { get; set; } |
|||
ExtraPropertyDictionary SelectNextStep { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public interface IStepNodeRepository : IRepository<StepNode, Guid> |
|||
{ |
|||
Task<List<StepNode>> GetAllChildrenWithWorkflowAsync( |
|||
Guid workflowId, |
|||
CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public interface IWorkflowRepository : IRepository<Workflow, Guid> |
|||
{ |
|||
Task<bool> CheckVersionAsync( |
|||
string name, |
|||
int version, |
|||
CancellationToken cancellationToken = default); |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using System; |
|||
using WorkflowCore.Models; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public class StepNode : Step |
|||
{ |
|||
protected StepNode() |
|||
{ |
|||
} |
|||
|
|||
public StepNode( |
|||
Guid id, |
|||
Guid workflowId, |
|||
string name, |
|||
string stepType, |
|||
string cancelCondition, |
|||
WorkflowErrorHandling? errorBehavior = null, |
|||
TimeSpan? retryInterval = null, |
|||
bool saga = false, |
|||
Guid? parentId = null, |
|||
Guid? tenantId = null) |
|||
: base(id, workflowId, name, stepType, cancelCondition, errorBehavior, retryInterval, saga, parentId, tenantId) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,530 @@ |
|||
using Newtonsoft.Json.Linq; |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Dynamic.Core; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Services; |
|||
using WorkflowCore.Exceptions; |
|||
using WorkflowCore.Interface; |
|||
using WorkflowCore.Models; |
|||
using WorkflowCore.Models.DefinitionStorage.v1; |
|||
using WorkflowCore.Primitives; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public class WorkflowManager : DomainService, ITransientDependency |
|||
{ |
|||
private readonly IWorkflowRegistry _registry; |
|||
private readonly IPersistenceProvider _persistenceProvider; |
|||
|
|||
public WorkflowManager( |
|||
IWorkflowRegistry registry, |
|||
IPersistenceProvider persistenceProvider) |
|||
{ |
|||
_registry = registry; |
|||
_persistenceProvider = persistenceProvider; |
|||
} |
|||
|
|||
public virtual WorkflowDefinition Register( |
|||
Workflow workflow, |
|||
ICollection<StepNode> steps, |
|||
ICollection<CompensateNode> compensates) |
|||
{ |
|||
var dataType = typeof(Dictionary<string, object>); |
|||
var source = new DefinitionSourceV1 |
|||
{ |
|||
Id = workflow.Id.ToString(), |
|||
Version = workflow.Version, |
|||
Description = workflow.Description ?? workflow.DisplayName, |
|||
DataType = $"{dataType.FullName}, {dataType.Assembly}", |
|||
DefaultErrorBehavior = workflow.ErrorBehavior, |
|||
DefaultErrorRetryInterval = workflow.ErrorRetryInterval, |
|||
Steps = ConvertSteps(steps, compensates) |
|||
}; |
|||
|
|||
var def = Convert(source); |
|||
_registry.RegisterWorkflow(def); |
|||
|
|||
return def; |
|||
} |
|||
|
|||
private List<StepSourceV1> ConvertSteps( |
|||
ICollection<StepNode> steps, |
|||
ICollection<CompensateNode> compensates) |
|||
{ |
|||
var nodes = new List<StepSourceV1>(); |
|||
|
|||
foreach (var step in steps) |
|||
{ |
|||
var source = new StepSourceV1 |
|||
{ |
|||
Id = step.Id.ToString(), |
|||
Saga = step.Saga, |
|||
StepType = step.StepType, |
|||
CancelCondition = step.CancelCondition, |
|||
ErrorBehavior = step.ErrorBehavior, |
|||
RetryInterval = step.RetryInterval, |
|||
Name = step.Name |
|||
}; |
|||
|
|||
foreach (var input in step.Inputs) |
|||
{ |
|||
source.Inputs.AddIfNotContains(input); |
|||
} |
|||
|
|||
foreach (var output in step.Outputs) |
|||
{ |
|||
source.Outputs.Add(output.Key, output.Value.ToString()); |
|||
} |
|||
|
|||
foreach (var nextStep in step.SelectNextStep) |
|||
{ |
|||
source.SelectNextStep.Add(nextStep.Key, nextStep.Value.ToString()); |
|||
} |
|||
|
|||
var childrenNodes = steps.Where(x => Equals(x.ParentId, step.Id)).ToArray(); |
|||
if (childrenNodes.Any()) |
|||
{ |
|||
source.NextStepId = childrenNodes[0].Id.ToString(); |
|||
|
|||
nodes.AddRange(ConvertSteps(childrenNodes, compensates)); |
|||
} |
|||
|
|||
var stepCps = compensates.Where(x => Equals(x.ParentId, step.Id)).ToArray(); |
|||
if (stepCps.Any()) |
|||
{ |
|||
source.CompensateWith.AddRange(ConvertCompensateSteps(stepCps)); |
|||
} |
|||
|
|||
nodes.Add(source); |
|||
} |
|||
|
|||
return nodes; |
|||
} |
|||
|
|||
private List<StepSourceV1> ConvertCompensateSteps( |
|||
ICollection<CompensateNode> compensates) |
|||
{ |
|||
var nodes = new List<StepSourceV1>(); |
|||
|
|||
foreach (var step in compensates) |
|||
{ |
|||
var source = new StepSourceV1 |
|||
{ |
|||
Id = step.Id.ToString(), |
|||
Saga = step.Saga, |
|||
StepType = step.StepType, |
|||
CancelCondition = step.CancelCondition, |
|||
ErrorBehavior = step.ErrorBehavior, |
|||
RetryInterval = step.RetryInterval, |
|||
Name = step.Name |
|||
}; |
|||
|
|||
foreach (var input in step.Inputs) |
|||
{ |
|||
source.Inputs.AddIfNotContains(input); |
|||
} |
|||
|
|||
foreach (var output in step.Outputs) |
|||
{ |
|||
source.Outputs.Add(output.Key, output.Value.ToString()); |
|||
} |
|||
|
|||
foreach (var nextStep in step.SelectNextStep) |
|||
{ |
|||
source.SelectNextStep.Add(nextStep.Key, nextStep.Value.ToString()); |
|||
} |
|||
|
|||
var stepCps = compensates.Where(x => Equals(x.ParentId, step.Id)).ToArray(); |
|||
if (stepCps.Any()) |
|||
{ |
|||
source.CompensateWith.AddRange(ConvertCompensateSteps(stepCps)); |
|||
} |
|||
|
|||
nodes.Add(source); |
|||
} |
|||
|
|||
return nodes; |
|||
} |
|||
|
|||
private WorkflowDefinition Convert(DefinitionSourceV1 source) |
|||
{ |
|||
var dataType = typeof(object); |
|||
if (!string.IsNullOrEmpty(source.DataType)) |
|||
dataType = FindType(source.DataType); |
|||
|
|||
var result = new WorkflowDefinition |
|||
{ |
|||
Id = source.Id, |
|||
Version = source.Version, |
|||
Steps = ConvertSteps(source.Steps, dataType), |
|||
DefaultErrorBehavior = source.DefaultErrorBehavior, |
|||
DefaultErrorRetryInterval = source.DefaultErrorRetryInterval, |
|||
Description = source.Description, |
|||
DataType = dataType |
|||
}; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
|
|||
private WorkflowStepCollection ConvertSteps(ICollection<StepSourceV1> source, Type dataType) |
|||
{ |
|||
var result = new WorkflowStepCollection(); |
|||
int i = 0; |
|||
var stack = new Stack<StepSourceV1>(source.Reverse<StepSourceV1>()); |
|||
var parents = new List<StepSourceV1>(); |
|||
var compensatables = new List<StepSourceV1>(); |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var nextStep = stack.Pop(); |
|||
|
|||
var stepType = FindType(nextStep.StepType); |
|||
|
|||
WorkflowStep targetStep; |
|||
|
|||
Type containerType; |
|||
if (stepType.GetInterfaces().Contains(typeof(IStepBody))) |
|||
{ |
|||
containerType = typeof(WorkflowStep<>).MakeGenericType(stepType); |
|||
|
|||
targetStep = (containerType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep); |
|||
} |
|||
else |
|||
{ |
|||
targetStep = stepType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep; |
|||
if (targetStep != null) |
|||
stepType = targetStep.BodyType; |
|||
} |
|||
|
|||
if (nextStep.Saga) |
|||
{ |
|||
containerType = typeof(SagaContainer<>).MakeGenericType(stepType); |
|||
targetStep = (containerType.GetConstructor(new Type[] { }).Invoke(null) as WorkflowStep); |
|||
} |
|||
|
|||
if (!string.IsNullOrEmpty(nextStep.CancelCondition)) |
|||
{ |
|||
var cancelExprType = typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(dataType, typeof(bool))); |
|||
var dataParameter = Expression.Parameter(dataType, "data"); |
|||
var cancelExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter }, typeof(bool), nextStep.CancelCondition); |
|||
targetStep.CancelCondition = cancelExpr; |
|||
} |
|||
|
|||
targetStep.Id = i; |
|||
targetStep.Name = nextStep.Name; |
|||
targetStep.ErrorBehavior = nextStep.ErrorBehavior; |
|||
targetStep.RetryInterval = nextStep.RetryInterval; |
|||
targetStep.ExternalId = $"{nextStep.Id}"; |
|||
|
|||
AttachInputs(nextStep, dataType, stepType, targetStep); |
|||
AttachOutputs(nextStep, dataType, stepType, targetStep); |
|||
|
|||
if (nextStep.Do != null) |
|||
{ |
|||
foreach (var branch in nextStep.Do) |
|||
{ |
|||
foreach (var child in branch.Reverse<StepSourceV1>()) |
|||
stack.Push(child); |
|||
} |
|||
|
|||
if (nextStep.Do.Count > 0) |
|||
parents.Add(nextStep); |
|||
} |
|||
|
|||
if (nextStep.CompensateWith != null) |
|||
{ |
|||
foreach (var compChild in nextStep.CompensateWith.Reverse<StepSourceV1>()) |
|||
stack.Push(compChild); |
|||
|
|||
if (nextStep.CompensateWith.Count > 0) |
|||
compensatables.Add(nextStep); |
|||
} |
|||
|
|||
AttachOutcomes(nextStep, dataType, targetStep); |
|||
|
|||
result.Add(targetStep); |
|||
|
|||
i++; |
|||
} |
|||
|
|||
foreach (var step in result) |
|||
{ |
|||
if (result.Any(x => x.ExternalId == step.ExternalId && x.Id != step.Id)) |
|||
throw new WorkflowDefinitionLoadException($"Duplicate step Id {step.ExternalId}"); |
|||
|
|||
foreach (var outcome in step.Outcomes) |
|||
{ |
|||
if (result.All(x => x.ExternalId != outcome.ExternalNextStepId)) |
|||
throw new WorkflowDefinitionLoadException($"Cannot find step id {outcome.ExternalNextStepId}"); |
|||
|
|||
outcome.NextStep = result.Single(x => x.ExternalId == outcome.ExternalNextStepId).Id; |
|||
} |
|||
} |
|||
|
|||
foreach (var parent in parents) |
|||
{ |
|||
var target = result.Single(x => x.ExternalId == parent.Id); |
|||
foreach (var branch in parent.Do) |
|||
{ |
|||
var childTags = branch.Select(x => x.Id).ToList(); |
|||
target.Children.AddRange(result |
|||
.Where(x => childTags.Contains(x.ExternalId)) |
|||
.OrderBy(x => x.Id) |
|||
.Select(x => x.Id) |
|||
.Take(1) |
|||
.ToList()); |
|||
} |
|||
} |
|||
|
|||
foreach (var item in compensatables) |
|||
{ |
|||
var target = result.Single(x => x.ExternalId == item.Id); |
|||
var tag = item.CompensateWith.Select(x => x.Id).FirstOrDefault(); |
|||
if (tag != null) |
|||
{ |
|||
var compStep = result.FirstOrDefault(x => x.ExternalId == tag); |
|||
if (compStep != null) |
|||
target.CompensationStepId = compStep.Id; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private void AttachInputs(StepSourceV1 source, Type dataType, Type stepType, WorkflowStep step) |
|||
{ |
|||
foreach (var input in source.Inputs) |
|||
{ |
|||
var dataParameter = Expression.Parameter(dataType, "data"); |
|||
var contextParameter = Expression.Parameter(typeof(IStepExecutionContext), "context"); |
|||
var environmentVarsParameter = Expression.Parameter(typeof(IDictionary), "environment"); |
|||
var stepProperty = stepType.GetProperty(input.Key); |
|||
|
|||
if (stepProperty == null) |
|||
{ |
|||
throw new ArgumentException($"Unknown property for input {input.Key} on {source.Id}"); |
|||
} |
|||
|
|||
if (input.Value is string) |
|||
{ |
|||
var acn = BuildScalarInputAction(input, dataParameter, contextParameter, environmentVarsParameter, stepProperty); |
|||
step.Inputs.Add(new ActionParameter<IStepBody, object>(acn)); |
|||
continue; |
|||
} |
|||
|
|||
if ((input.Value is IDictionary<string, object>) || (input.Value is IDictionary<object, object>)) |
|||
{ |
|||
var acn = BuildObjectInputAction(input, dataParameter, contextParameter, environmentVarsParameter, stepProperty); |
|||
step.Inputs.Add(new ActionParameter<IStepBody, object>(acn)); |
|||
continue; |
|||
} |
|||
|
|||
throw new ArgumentException($"Unknown type for input {input.Key} on {source.Id}"); |
|||
} |
|||
} |
|||
|
|||
private void AttachOutputs(StepSourceV1 source, Type dataType, Type stepType, WorkflowStep step) |
|||
{ |
|||
foreach (var output in source.Outputs) |
|||
{ |
|||
var stepParameter = Expression.Parameter(stepType, "step"); |
|||
var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { stepParameter }, typeof(object), output.Value); |
|||
|
|||
var dataParameter = Expression.Parameter(dataType, "data"); |
|||
|
|||
|
|||
if (output.Key.Contains(".") || output.Key.Contains("[")) |
|||
{ |
|||
AttachNestedOutput(output, step, source, sourceExpr, dataParameter); |
|||
} |
|||
else |
|||
{ |
|||
AttachDirectlyOutput(output, step, dataType, sourceExpr, dataParameter); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void AttachDirectlyOutput(KeyValuePair<string, string> output, WorkflowStep step, Type dataType, LambdaExpression sourceExpr, ParameterExpression dataParameter) |
|||
{ |
|||
Expression targetProperty; |
|||
|
|||
// Check if our datatype has a matching property
|
|||
var propertyInfo = dataType.GetProperty(output.Key); |
|||
if (propertyInfo != null) |
|||
{ |
|||
targetProperty = Expression.Property(dataParameter, propertyInfo); |
|||
var targetExpr = Expression.Lambda(targetProperty, dataParameter); |
|||
step.Outputs.Add(new MemberMapParameter(sourceExpr, targetExpr)); |
|||
} |
|||
else |
|||
{ |
|||
// If we did not find a matching property try to find a Indexer with string parameter
|
|||
propertyInfo = dataType.GetProperty("Item"); |
|||
targetProperty = Expression.Property(dataParameter, propertyInfo, Expression.Constant(output.Key)); |
|||
|
|||
Action<IStepBody, object> acn = (pStep, pData) => |
|||
{ |
|||
object resolvedValue = sourceExpr.Compile().DynamicInvoke(pStep); ; |
|||
propertyInfo.SetValue(pData, resolvedValue, new object[] { output.Key }); |
|||
}; |
|||
|
|||
step.Outputs.Add(new ActionParameter<IStepBody, object>(acn)); |
|||
} |
|||
|
|||
} |
|||
|
|||
private void AttachNestedOutput(KeyValuePair<string, string> output, WorkflowStep step, StepSourceV1 source, LambdaExpression sourceExpr, ParameterExpression dataParameter) |
|||
{ |
|||
PropertyInfo propertyInfo = null; |
|||
String[] paths = output.Key.Split('.'); |
|||
|
|||
Expression targetProperty = dataParameter; |
|||
|
|||
bool hasAddOutput = false; |
|||
|
|||
foreach (String propertyName in paths) |
|||
{ |
|||
if (hasAddOutput) |
|||
{ |
|||
throw new ArgumentException($"Unknown property for output {output.Key} on {source.Id}"); |
|||
} |
|||
|
|||
if (targetProperty == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (propertyName.Contains("[")) |
|||
{ |
|||
String[] items = propertyName.Split('['); |
|||
|
|||
if (items.Length != 2) |
|||
{ |
|||
throw new ArgumentException($"Unknown property for output {output.Key} on {source.Id}"); |
|||
} |
|||
|
|||
items[1] = items[1].Trim().TrimEnd(']').Trim().Trim('"'); |
|||
|
|||
MemberExpression memberExpression = Expression.Property(targetProperty, items[0]); |
|||
|
|||
if (memberExpression == null) |
|||
{ |
|||
throw new ArgumentException($"Unknown property for output {output.Key} on {source.Id}"); |
|||
} |
|||
propertyInfo = ((PropertyInfo)memberExpression.Member).PropertyType.GetProperty("Item"); |
|||
|
|||
Action<IStepBody, object> acn = (pStep, pData) => |
|||
{ |
|||
var targetExpr = Expression.Lambda(memberExpression, dataParameter); |
|||
object data = targetExpr.Compile().DynamicInvoke(pData); |
|||
object resolvedValue = sourceExpr.Compile().DynamicInvoke(pStep); ; |
|||
propertyInfo.SetValue(data, resolvedValue, new object[] { items[1] }); |
|||
}; |
|||
|
|||
step.Outputs.Add(new ActionParameter<IStepBody, object>(acn)); |
|||
hasAddOutput = true; |
|||
} |
|||
else |
|||
{ |
|||
try |
|||
{ |
|||
targetProperty = Expression.Property(targetProperty, propertyName); |
|||
} |
|||
catch |
|||
{ |
|||
targetProperty = null; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (targetProperty != null && !hasAddOutput) |
|||
{ |
|||
var targetExpr = Expression.Lambda(targetProperty, dataParameter); |
|||
step.Outputs.Add(new MemberMapParameter(sourceExpr, targetExpr)); |
|||
} |
|||
} |
|||
|
|||
private void AttachOutcomes(StepSourceV1 source, Type dataType, WorkflowStep step) |
|||
{ |
|||
if (!string.IsNullOrEmpty(source.NextStepId)) |
|||
step.Outcomes.Add(new ValueOutcome { ExternalNextStepId = $"{source.NextStepId}" }); |
|||
|
|||
var dataParameter = Expression.Parameter(dataType, "data"); |
|||
var outcomeParameter = Expression.Parameter(typeof(object), "outcome"); |
|||
|
|||
foreach (var nextStep in source.SelectNextStep) |
|||
{ |
|||
var sourceDelegate = DynamicExpressionParser.ParseLambda(new[] { dataParameter, outcomeParameter }, typeof(object), nextStep.Value).Compile(); |
|||
Expression<Func<object, object, bool>> sourceExpr = (data, outcome) => System.Convert.ToBoolean(sourceDelegate.DynamicInvoke(data, outcome)); |
|||
step.Outcomes.Add(new ExpressionOutcome<object>(sourceExpr) |
|||
{ |
|||
ExternalNextStepId = $"{nextStep.Key}" |
|||
}); |
|||
} |
|||
} |
|||
|
|||
private Type FindType(string name) |
|||
{ |
|||
return Type.GetType(name, true, true); |
|||
} |
|||
|
|||
private static Action<IStepBody, object, IStepExecutionContext> BuildScalarInputAction(KeyValuePair<string, object> input, ParameterExpression dataParameter, ParameterExpression contextParameter, ParameterExpression environmentVarsParameter, PropertyInfo stepProperty) |
|||
{ |
|||
var expr = System.Convert.ToString(input.Value); |
|||
var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), expr); |
|||
|
|||
void acn(IStepBody pStep, object pData, IStepExecutionContext pContext) |
|||
{ |
|||
object resolvedValue = sourceExpr.Compile().DynamicInvoke(pData, pContext, Environment.GetEnvironmentVariables()); |
|||
if (stepProperty.PropertyType.IsEnum) |
|||
stepProperty.SetValue(pStep, Enum.Parse(stepProperty.PropertyType, (string)resolvedValue, true)); |
|||
else |
|||
{ |
|||
if ((resolvedValue != null) && (stepProperty.PropertyType.IsAssignableFrom(resolvedValue.GetType()))) |
|||
stepProperty.SetValue(pStep, resolvedValue); |
|||
else |
|||
stepProperty.SetValue(pStep, System.Convert.ChangeType(resolvedValue, stepProperty.PropertyType)); |
|||
} |
|||
} |
|||
return acn; |
|||
} |
|||
|
|||
private static Action<IStepBody, object, IStepExecutionContext> BuildObjectInputAction(KeyValuePair<string, object> input, ParameterExpression dataParameter, ParameterExpression contextParameter, ParameterExpression environmentVarsParameter, PropertyInfo stepProperty) |
|||
{ |
|||
void acn(IStepBody pStep, object pData, IStepExecutionContext pContext) |
|||
{ |
|||
var stack = new Stack<JObject>(); |
|||
var destObj = JObject.FromObject(input.Value); |
|||
stack.Push(destObj); |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var subobj = stack.Pop(); |
|||
foreach (var prop in subobj.Properties().ToList()) |
|||
{ |
|||
if (prop.Name.StartsWith("@")) |
|||
{ |
|||
var sourceExpr = DynamicExpressionParser.ParseLambda(new[] { dataParameter, contextParameter, environmentVarsParameter }, typeof(object), prop.Value.ToString()); |
|||
object resolvedValue = sourceExpr.Compile().DynamicInvoke(pData, pContext, Environment.GetEnvironmentVariables()); |
|||
subobj.Remove(prop.Name); |
|||
subobj.Add(prop.Name.TrimStart('@'), JToken.FromObject(resolvedValue)); |
|||
} |
|||
} |
|||
|
|||
foreach (var child in subobj.Children<JObject>()) |
|||
stack.Push(child); |
|||
} |
|||
|
|||
stepProperty.SetValue(pStep, destObj); |
|||
} |
|||
return acn; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
using Microsoft.Extensions.Hosting; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement |
|||
{ |
|||
public class WorkflowRegisterService : BackgroundService |
|||
{ |
|||
private readonly WorkflowManager _workflowManager; |
|||
|
|||
private readonly IWorkflowRepository _workflowRepository; |
|||
private readonly IStepNodeRepository _stepNodeRepository; |
|||
private readonly ICompensateNodeRepository _compensateNodeRepository; |
|||
|
|||
public WorkflowRegisterService( |
|||
WorkflowManager workflowManager, |
|||
IWorkflowRepository workflowRepository, |
|||
IStepNodeRepository stepNodeRepository, |
|||
ICompensateNodeRepository compensateNodeRepository) |
|||
{ |
|||
_workflowManager = workflowManager; |
|||
_workflowRepository = workflowRepository; |
|||
_stepNodeRepository = stepNodeRepository; |
|||
_compensateNodeRepository = compensateNodeRepository; |
|||
} |
|||
|
|||
protected override async Task ExecuteAsync(CancellationToken stoppingToken) |
|||
{ |
|||
var workflows = await _workflowRepository.GetListAsync(cancellationToken: stoppingToken); |
|||
|
|||
foreach (var workflow in workflows) |
|||
{ |
|||
var stepNodes = await _stepNodeRepository.GetAllChildrenWithWorkflowAsync(workflow.Id, cancellationToken: stoppingToken); |
|||
var compensateNodes = await _compensateNodeRepository.GetAllChildrenWithWorkflowAsync(workflow.Id, cancellationToken: stoppingToken); |
|||
|
|||
_workflowManager.Register(workflow, stepNodes, compensateNodes); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore |
|||
{ |
|||
public class EfCoreCompensateNodeRepository : EfCoreRepository<WorkflowManagementDbContext, CompensateNode, Guid>, ICompensateNodeRepository |
|||
{ |
|||
public EfCoreCompensateNodeRepository( |
|||
IDbContextProvider<WorkflowManagementDbContext> dbContextProvider) |
|||
: base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<List<CompensateNode>> GetAllChildrenWithWorkflowAsync(Guid workflowId, CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()) |
|||
.Where(x => x.WorkflowId.Equals(workflowId)) |
|||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore |
|||
{ |
|||
public class EfCoreStepNodeRepository : EfCoreRepository<WorkflowManagementDbContext, StepNode, Guid>, IStepNodeRepository |
|||
{ |
|||
public EfCoreStepNodeRepository( |
|||
IDbContextProvider<WorkflowManagementDbContext> dbContextProvider) |
|||
: base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<List<StepNode>> GetAllChildrenWithWorkflowAsync(Guid workflowId, CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()) |
|||
.Where(x => x.WorkflowId.Equals(workflowId)) |
|||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore |
|||
{ |
|||
public class EfCoreWorkflowRepository : EfCoreRepository<WorkflowManagementDbContext, Workflow, Guid>, IWorkflowRepository |
|||
{ |
|||
public EfCoreWorkflowRepository( |
|||
IDbContextProvider<WorkflowManagementDbContext> dbContextProvider) |
|||
: base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<bool> CheckVersionAsync(string name, int version, CancellationToken cancellationToken = default) |
|||
{ |
|||
return await (await GetDbSetAsync()) |
|||
.AnyAsync(x => x.Name.Equals(name) && x.Version == version, |
|||
GetCancellationToken(cancellationToken)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Activitys |
|||
{ |
|||
[RemoteService(Name = WorkflowManagementRemoteServiceConsts.RemoteServiceName)] |
|||
[Area("WorkflowManagement")] |
|||
[Route("api/workflow-management/activitys")] |
|||
public class ActivityController : AbpControllerBase, IActivityAppService |
|||
{ |
|||
private readonly IActivityAppService _service; |
|||
|
|||
public ActivityController(IActivityAppService service) |
|||
{ |
|||
_service = service; |
|||
} |
|||
|
|||
[HttpPost("fail/{token}")] |
|||
public virtual async Task FailureAsync(ActivityFailureInput input) |
|||
{ |
|||
await _service.FailureAsync(input); |
|||
} |
|||
|
|||
[HttpGet("{ActivityName}")] |
|||
public virtual async Task<PendingActivityDto> GetAsync(GetPendingActivityInput input) |
|||
{ |
|||
return await _service.GetAsync(input); |
|||
} |
|||
|
|||
[HttpDelete("{Token}")] |
|||
public virtual async Task DeleteAsync(ActivityReleaseInput input) |
|||
{ |
|||
await _service.DeleteAsync(input); |
|||
} |
|||
|
|||
[HttpPost("success/{Token}")] |
|||
public virtual async Task SuccessAsync(ActivitySuccessInput input) |
|||
{ |
|||
await _service.SuccessAsync(input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Events |
|||
{ |
|||
[RemoteService(Name = WorkflowManagementRemoteServiceConsts.RemoteServiceName)] |
|||
[Area("WorkflowManagement")] |
|||
[Route("api/workflow-management/events")] |
|||
public class EventController : AbpControllerBase, IEventAppService |
|||
{ |
|||
private readonly IEventAppService _service; |
|||
|
|||
public EventController(IEventAppService service) |
|||
{ |
|||
_service = service; |
|||
} |
|||
|
|||
[HttpPost] |
|||
[Route("{EventName}/{EventKey}")] |
|||
public virtual async Task PublishAsync(EventPublishInput input) |
|||
{ |
|||
await _service.PublishAsync(input); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.WorkflowManagement.Workflows |
|||
{ |
|||
[RemoteService(Name = WorkflowManagementRemoteServiceConsts.RemoteServiceName)] |
|||
[Area("WorkflowManagement")] |
|||
[Route("api/workflow-management/workflows")] |
|||
public class WorkflowController : AbpControllerBase, IWorkflowAppService |
|||
{ |
|||
private readonly IWorkflowAppService _service; |
|||
|
|||
public WorkflowController(IWorkflowAppService service) |
|||
{ |
|||
_service = service; |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{id}")] |
|||
public virtual async Task<WorkflowDto> GetAsync(string id) |
|||
{ |
|||
return await _service.GetAsync(id); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}/resume")] |
|||
public virtual async Task ResumeAsync(string id) |
|||
{ |
|||
await _service.ResumeAsync(id); |
|||
} |
|||
|
|||
[HttpPost] |
|||
public virtual async Task CreateAsync(WorkflowCreateDto input) |
|||
{ |
|||
await _service.CreateAsync(input); |
|||
} |
|||
|
|||
[HttpPost] |
|||
[Route("{id}/start")] |
|||
public virtual async Task<WorkflowDto> StartAsync(string id, WorkflowStartInput input) |
|||
{ |
|||
return await _service.StartAsync(id, input); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}/suspend")] |
|||
public virtual async Task SuspendAsync(string id) |
|||
{ |
|||
await _service.SuspendAsync(id); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{id}/terminate")] |
|||
public virtual async Task TerminateAsync(string id) |
|||
{ |
|||
await _service.TerminateAsync(id); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.Controllers |
|||
{ |
|||
public class HomeController : AbpController |
|||
{ |
|||
public IActionResult Index() |
|||
{ |
|||
return Redirect("/swagger/index.html"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
FROM mcr.microsoft.com/dotnet/aspnet:5.0 |
|||
LABEL maintainer="colin.in@foxmail.com" |
|||
WORKDIR /app |
|||
|
|||
COPY . /app |
|||
|
|||
#�Ϻ�ʱ�� |
|||
#ENV TZ=Asia/Shanghai |
|||
#RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone |
|||
|
|||
EXPOSE 80/tcp |
|||
VOLUME [ "./app/Logs" ] |
|||
VOLUME [ "./app/Modules" ] |
|||
|
|||
ENTRYPOINT ["dotnet", "LY.MicroService.WorkflowManagement.HttpApi.Host.dll"] |
|||
@ -0,0 +1,24 @@ |
|||
using LINGYUN.Abp.WorkflowCore.Persistence.EntityFrameworkCore; |
|||
using LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.EntityFrameworkCore |
|||
{ |
|||
public class WorkflowManagementMigrationsDbContext : AbpDbContext<WorkflowManagementMigrationsDbContext> |
|||
{ |
|||
public WorkflowManagementMigrationsDbContext(DbContextOptions<WorkflowManagementMigrationsDbContext> options) |
|||
: base(options) |
|||
{ |
|||
|
|||
} |
|||
|
|||
protected override void OnModelCreating(ModelBuilder modelBuilder) |
|||
{ |
|||
base.OnModelCreating(modelBuilder); |
|||
|
|||
modelBuilder.ConfigureWorkflow(); |
|||
modelBuilder.ConfigureWorkflowManagement(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Design; |
|||
using Microsoft.Extensions.Configuration; |
|||
using System.IO; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.EntityFrameworkCore |
|||
{ |
|||
public class WorkflowManagementMigrationsDbContextFactory : IDesignTimeDbContextFactory<WorkflowManagementMigrationsDbContext> |
|||
{ |
|||
public WorkflowManagementMigrationsDbContext CreateDbContext(string[] args) |
|||
{ |
|||
var configuration = BuildConfiguration(); |
|||
var connectionString = configuration.GetConnectionString("WorkflowManagement"); |
|||
|
|||
var builder = new DbContextOptionsBuilder<WorkflowManagementMigrationsDbContext>() |
|||
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); |
|||
|
|||
return new WorkflowManagementMigrationsDbContext(builder.Options); |
|||
} |
|||
|
|||
private static IConfigurationRoot BuildConfiguration() |
|||
{ |
|||
var builder = new ConfigurationBuilder() |
|||
.SetBasePath(Directory.GetCurrentDirectory()) |
|||
.AddJsonFile("appsettings.json", optional: false) |
|||
.AddJsonFile("appsettings.Development.json", optional: true); |
|||
|
|||
return builder.Build(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
using LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore; |
|||
using LINGYUN.Abp.Data.DbMigrator; |
|||
using LINGYUN.Abp.MultiTenancy; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.Extensions.Logging; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.EventBus.Handlers |
|||
{ |
|||
public class TenantSynchronizer : |
|||
IDistributedEventHandler<CreateEventData>, |
|||
ITransientDependency |
|||
{ |
|||
protected IDataSeeder DataSeeder { get; } |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
protected IDbSchemaMigrator DbSchemaMigrator { get; } |
|||
protected IUnitOfWorkManager UnitOfWorkManager { get; } |
|||
|
|||
protected ILogger<TenantSynchronizer> Logger { get; } |
|||
|
|||
public TenantSynchronizer( |
|||
IDataSeeder dataSeeder, |
|||
ICurrentTenant currentTenant, |
|||
IDbSchemaMigrator dbSchemaMigrator, |
|||
IUnitOfWorkManager unitOfWorkManager, |
|||
ILogger<TenantSynchronizer> logger) |
|||
{ |
|||
DataSeeder = dataSeeder; |
|||
CurrentTenant = currentTenant; |
|||
DbSchemaMigrator = dbSchemaMigrator; |
|||
UnitOfWorkManager = unitOfWorkManager; |
|||
|
|||
Logger = logger; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 租户创建之后需要预置种子数据
|
|||
/// </summary>
|
|||
/// <param name="eventData"></param>
|
|||
/// <returns></returns>
|
|||
public virtual async Task HandleEventAsync(CreateEventData eventData) |
|||
{ |
|||
using (var unitOfWork = UnitOfWorkManager.Begin()) |
|||
{ |
|||
using (CurrentTenant.Change(eventData.Id, eventData.Name)) |
|||
{ |
|||
Logger.LogInformation("Migrating the new tenant database with WorkflowManagement..."); |
|||
// 迁移租户数据
|
|||
await DbSchemaMigrator.MigrateAsync<WorkflowManagementDbContext>( |
|||
(connectionString, builder) => |
|||
{ |
|||
builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); |
|||
|
|||
return new WorkflowManagementDbContext(builder.Options); |
|||
}); |
|||
Logger.LogInformation("Migrated the new tenant database with WorkflowManagement..."); |
|||
|
|||
await DataSeeder.SeedAsync(new DataSeedContext(eventData.Id)); |
|||
|
|||
await unitOfWork.SaveChangesAsync(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<RootNamespace>LY.MicroService.WorkflowManagement</RootNamespace> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="AgileConfig.Client" Version="$(AgileConfigClientPackageVersion)" /> |
|||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="$(MicrosoftPackageVersion)"> |
|||
<PrivateAssets>all</PrivateAssets> |
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
|||
</PackageReference> |
|||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="$(MicrosoftPackageVersion)" /> |
|||
<PackageReference Include="DistributedLock.Redis" Version="$(DistributedLockRedisPackageVersion)" /> |
|||
<PackageReference Include="Serilog.AspNetCore" Version="$(SerilogAspNetCorePackageVersion)" /> |
|||
<PackageReference Include="Serilog.Enrichers.Environment" Version="$(SerilogEnrichersEnvironmentPackageVersion)" /> |
|||
<PackageReference Include="Serilog.Enrichers.Assembly" Version="$(SerilogEnrichersAssemblyPackageVersion)" /> |
|||
<PackageReference Include="Serilog.Enrichers.Process" Version="$(SerilogEnrichersProcessPackageVersion)" /> |
|||
<PackageReference Include="Serilog.Enrichers.Thread" Version="$(SerilogEnrichersThreadPackageVersion)" /> |
|||
<PackageReference Include="Serilog.Settings.Configuration" Version="$(SerilogSettingsConfigurationPackageVersion)" /> |
|||
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="$(SerilogSinksElasticsearchPackageVersion)" /> |
|||
<PackageReference Include="Serilog.Sinks.File" Version="$(SerilogSinksFilePackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.AspNetCore.MultiTenancy" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.Autofac" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.EventBus.RabbitMQ" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.Swashbuckle" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.EntityFrameworkCore.MySql" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.Http.Client.IdentityModel.Web" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.FeatureManagement.EntityFrameworkCore" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" Version="$(VoloAbpPackageVersion)" /> |
|||
<PackageReference Include="Volo.Abp.TenantManagement.EntityFrameworkCore" Version="$(VoloAbpPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\modules\common\LINGYUN.Abp.Data.DbMigrator\LINGYUN.Abp.Data.DbMigrator.csproj" /> |
|||
<ProjectReference Include="..\..\modules\common\LINGYUN.Abp.ExceptionHandling.Emailing\LINGYUN.Abp.ExceptionHandling.Emailing.csproj" /> |
|||
<ProjectReference Include="..\..\modules\tenants\LINGYUN.Abp.MultiTenancy\LINGYUN.Abp.MultiTenancy.csproj" /> |
|||
<ProjectReference Include="..\..\modules\tenants\LINGYUN.Abp.MultiTenancy.DbFinder\LINGYUN.Abp.MultiTenancy.DbFinder.csproj" /> |
|||
<ProjectReference Include="..\..\modules\auditing\LINGYUN.Abp.AuditLogging.Elasticsearch\LINGYUN.Abp.AuditLogging.Elasticsearch.csproj" /> |
|||
<ProjectReference Include="..\..\modules\logging\LINGYUN.Abp.Serilog.Enrichers.Application\LINGYUN.Abp.Serilog.Enrichers.Application.csproj" /> |
|||
<ProjectReference Include="..\..\modules\lt\LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore\LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowCore.Components\LINGYUN.Abp.WorkflowCore.Components.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowCore.DistributedLock\LINGYUN.Abp.WorkflowCore.DistributedLock.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowCore.Elasticsearch\LINGYUN.Abp.WorkflowCore.Elasticsearch.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowCore.LifeCycleEvent\LINGYUN.Abp.WorkflowCore.LifeCycleEvent.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowCore.Persistence.EntityFrameworkCore\LINGYUN.Abp.WorkflowCore.Persistence.EntityFrameworkCore.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowCore.RabbitMQ\LINGYUN.Abp.WorkflowCore.RabbitMQ.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowManagement.Application\LINGYUN.Abp.WorkflowManagement.Application.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore\LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore.csproj" /> |
|||
<ProjectReference Include="..\..\modules\workflow\LINGYUN.Abp.WorkflowManagement.HttpApi\LINGYUN.Abp.WorkflowManagement.HttpApi.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,557 @@ |
|||
// <auto-generated />
|
|||
using System; |
|||
using LY.MicroService.WorkflowManagement.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
#nullable disable |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.Migrations |
|||
{ |
|||
[DbContext(typeof(WorkflowManagementMigrationsDbContext))] |
|||
[Migration("20211212074420_Add-Module-Workflow-Management")] |
|||
partial class AddModuleWorkflowManagement |
|||
{ |
|||
protected override void BuildTargetModel(ModelBuilder modelBuilder) |
|||
{ |
|||
#pragma warning disable 612, 618
|
|||
modelBuilder |
|||
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) |
|||
.HasAnnotation("ProductVersion", "6.0.0") |
|||
.HasAnnotation("Relational:MaxIdentifierLength", 64); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedEvent", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<string>("EventData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("EventKey") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<bool>("IsProcessed") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("CreationTime"); |
|||
|
|||
b.HasIndex("IsProcessed"); |
|||
|
|||
b.HasIndex("EventName", "EventKey"); |
|||
|
|||
b.ToTable("WF_Event", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionError", b => |
|||
{ |
|||
b.Property<int>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<DateTime>("ErrorTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid>("ExecutionPointerId") |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<string>("Message") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_ExecutionError", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<bool>("Active") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("Children") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("ContextItem") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<DateTime?>("EndTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("EventData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("EventKey") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<bool>("EventPublished") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("Outcome") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("PersistenceData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("PredecessorId") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<int>("RetryCount") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Scope") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<DateTime?>("SleepUntil") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<DateTime?>("StartTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<int>("Status") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<int>("StepId") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("StepName") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("WorkflowId"); |
|||
|
|||
b.ToTable("WF_ExecutionPointer", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExtensionAttribute", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid>("ExecutionPointerId") |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<string>("Key") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<string>("Value") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("ExecutionPointerId"); |
|||
|
|||
b.ToTable("WF_ExtensionAttribute", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedScheduledCommand", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("CommandName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("Data") |
|||
.HasMaxLength(500) |
|||
.HasColumnType("varchar(500)"); |
|||
|
|||
b.Property<long>("ExecuteTime") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("ExecuteTime"); |
|||
|
|||
b.HasIndex("CommandName", "Data") |
|||
.IsUnique(); |
|||
|
|||
b.ToTable("WF_ScheduledCommand", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedSubscription", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("EventKey") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<Guid>("ExecutionPointerId") |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<string>("ExternalToken") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<DateTime?>("ExternalTokenExpiry") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("ExternalWorkerId") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int>("StepId") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<DateTime>("SubscribeAsOf") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("SubscriptionData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("EventKey"); |
|||
|
|||
b.HasIndex("EventName"); |
|||
|
|||
b.ToTable("WF_Subscription", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<DateTime?>("CompleteTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("ConcurrencyStamp") |
|||
.IsConcurrencyToken() |
|||
.HasMaxLength(40) |
|||
.HasColumnType("varchar(40)") |
|||
.HasColumnName("ConcurrencyStamp"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("CreatorId"); |
|||
|
|||
b.Property<string>("Data") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("Description") |
|||
.HasMaxLength(500) |
|||
.HasColumnType("varchar(500)"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.HasColumnType("longtext") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<DateTime?>("LastModificationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("LastModificationTime"); |
|||
|
|||
b.Property<Guid?>("LastModifierId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("LastModifierId"); |
|||
|
|||
b.Property<long?>("NextExecution") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("Reference") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int>("Status") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<int>("Version") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("WorkflowDefinitionId") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("NextExecution"); |
|||
|
|||
b.ToTable("WF_Workflow", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.CompensateNode", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("CancelCondition") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int?>("ErrorBehavior") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Inputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("Name") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<string>("Outputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("ParentId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<TimeSpan?>("RetryInterval") |
|||
.HasColumnType("time(6)"); |
|||
|
|||
b.Property<bool>("Saga") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("SelectNextStep") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("StepType") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_Compensate", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.StepNode", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("CancelCondition") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int?>("ErrorBehavior") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Inputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("Name") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<string>("Outputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("ParentId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<TimeSpan?>("RetryInterval") |
|||
.HasColumnType("time(6)"); |
|||
|
|||
b.Property<bool>("Saga") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("SelectNextStep") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("StepType") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_Step", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.Workflow", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("ConcurrencyStamp") |
|||
.IsConcurrencyToken() |
|||
.HasMaxLength(40) |
|||
.HasColumnType("varchar(40)") |
|||
.HasColumnName("ConcurrencyStamp"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("CreatorId"); |
|||
|
|||
b.Property<string>("Description") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("DisplayName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int>("ErrorBehavior") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<TimeSpan?>("ErrorRetryInterval") |
|||
.HasColumnType("time(6)"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.HasColumnType("longtext") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<bool>("IsEnabled") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<DateTime?>("LastModificationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("LastModificationTime"); |
|||
|
|||
b.Property<Guid?>("LastModifierId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("LastModifierId"); |
|||
|
|||
b.Property<string>("Name") |
|||
.IsRequired() |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<int>("Version") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_Definition", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => |
|||
{ |
|||
b.HasOne("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", "Workflow") |
|||
.WithMany("ExecutionPointers") |
|||
.HasForeignKey("WorkflowId") |
|||
.OnDelete(DeleteBehavior.Cascade) |
|||
.IsRequired(); |
|||
|
|||
b.Navigation("Workflow"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExtensionAttribute", b => |
|||
{ |
|||
b.HasOne("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", "ExecutionPointer") |
|||
.WithMany("ExtensionAttributes") |
|||
.HasForeignKey("ExecutionPointerId") |
|||
.OnDelete(DeleteBehavior.Cascade) |
|||
.IsRequired(); |
|||
|
|||
b.Navigation("ExecutionPointer"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => |
|||
{ |
|||
b.Navigation("ExtensionAttributes"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", b => |
|||
{ |
|||
b.Navigation("ExecutionPointers"); |
|||
}); |
|||
#pragma warning restore 612, 618
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,385 @@ |
|||
using System; |
|||
using Microsoft.EntityFrameworkCore.Metadata; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
|
|||
#nullable disable |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.Migrations |
|||
{ |
|||
public partial class AddModuleWorkflowManagement : Migration |
|||
{ |
|||
protected override void Up(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.AlterDatabase() |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_Compensate", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
WorkflowId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
Name = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
StepType = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
CancelCondition = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ErrorBehavior = table.Column<int>(type: "int", nullable: true), |
|||
RetryInterval = table.Column<TimeSpan>(type: "time(6)", nullable: true), |
|||
Saga = table.Column<bool>(type: "tinyint(1)", nullable: false), |
|||
ParentId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
Inputs = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Outputs = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
SelectNextStep = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_Compensate", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_Definition", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
IsEnabled = table.Column<bool>(type: "tinyint(1)", nullable: false), |
|||
Name = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: false) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
DisplayName = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Description = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Version = table.Column<int>(type: "int", nullable: false), |
|||
ErrorBehavior = table.Column<int>(type: "int", nullable: false), |
|||
ErrorRetryInterval = table.Column<TimeSpan>(type: "time(6)", nullable: true), |
|||
ExtraProperties = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false), |
|||
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
|||
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_Definition", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_Event", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
EventName = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
EventKey = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
EventData = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
IsProcessed = table.Column<bool>(type: "tinyint(1)", nullable: false), |
|||
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false) |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_Event", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_ExecutionError", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<int>(type: "int", nullable: false) |
|||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
WorkflowId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
ExecutionPointerId = table.Column<Guid>(type: "char(50)", maxLength: 50, nullable: false, collation: "ascii_general_ci"), |
|||
ErrorTime = table.Column<DateTime>(type: "datetime(6)", nullable: false), |
|||
Message = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_ExecutionError", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_ScheduledCommand", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<long>(type: "bigint", nullable: false) |
|||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
CommandName = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Data = table.Column<string>(type: "varchar(500)", maxLength: 500, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ExecuteTime = table.Column<long>(type: "bigint", nullable: false) |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_ScheduledCommand", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_Step", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
WorkflowId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
Name = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
StepType = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
CancelCondition = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ErrorBehavior = table.Column<int>(type: "int", nullable: true), |
|||
RetryInterval = table.Column<TimeSpan>(type: "time(6)", nullable: true), |
|||
Saga = table.Column<bool>(type: "tinyint(1)", nullable: false), |
|||
ParentId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
Inputs = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Outputs = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
SelectNextStep = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_Step", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_Subscription", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
WorkflowId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
StepId = table.Column<int>(type: "int", nullable: false), |
|||
ExecutionPointerId = table.Column<Guid>(type: "char(50)", maxLength: 50, nullable: false, collation: "ascii_general_ci"), |
|||
EventName = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
EventKey = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
SubscribeAsOf = table.Column<DateTime>(type: "datetime(6)", nullable: false), |
|||
SubscriptionData = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ExternalToken = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ExternalWorkerId = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ExternalTokenExpiry = table.Column<DateTime>(type: "datetime(6)", nullable: true) |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_Subscription", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_Workflow", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
WorkflowDefinitionId = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Version = table.Column<int>(type: "int", nullable: false), |
|||
Description = table.Column<string>(type: "varchar(500)", maxLength: 500, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Reference = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
NextExecution = table.Column<long>(type: "bigint", nullable: true), |
|||
Status = table.Column<int>(type: "int", nullable: false), |
|||
Data = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
CompleteTime = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
|||
ExtraProperties = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false), |
|||
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
|||
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_Workflow", x => x.Id); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_ExecutionPointer", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(type: "char(50)", maxLength: 50, nullable: false, collation: "ascii_general_ci"), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
WorkflowId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"), |
|||
StepId = table.Column<int>(type: "int", nullable: false), |
|||
Active = table.Column<bool>(type: "tinyint(1)", nullable: false), |
|||
SleepUntil = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
|||
PersistenceData = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
StartTime = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
|||
EndTime = table.Column<DateTime>(type: "datetime(6)", nullable: true), |
|||
EventName = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
EventKey = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
EventPublished = table.Column<bool>(type: "tinyint(1)", nullable: false), |
|||
EventData = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
StepName = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
RetryCount = table.Column<int>(type: "int", nullable: false), |
|||
Children = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
ContextItem = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
PredecessorId = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Outcome = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Status = table.Column<int>(type: "int", nullable: false), |
|||
Scope = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_ExecutionPointer", x => x.Id); |
|||
table.ForeignKey( |
|||
name: "FK_WF_ExecutionPointer_WF_Workflow_WorkflowId", |
|||
column: x => x.WorkflowId, |
|||
principalTable: "WF_Workflow", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Cascade); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateTable( |
|||
name: "WF_ExtensionAttribute", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<long>(type: "bigint", nullable: false) |
|||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
|||
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"), |
|||
ExecutionPointerId = table.Column<Guid>(type: "char(50)", maxLength: 50, nullable: false, collation: "ascii_general_ci"), |
|||
Key = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4"), |
|||
Value = table.Column<string>(type: "longtext", nullable: true) |
|||
.Annotation("MySql:CharSet", "utf8mb4") |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_WF_ExtensionAttribute", x => x.Id); |
|||
table.ForeignKey( |
|||
name: "FK_WF_ExtensionAttribute_WF_ExecutionPointer_ExecutionPointerId", |
|||
column: x => x.ExecutionPointerId, |
|||
principalTable: "WF_ExecutionPointer", |
|||
principalColumn: "Id", |
|||
onDelete: ReferentialAction.Cascade); |
|||
}) |
|||
.Annotation("MySql:CharSet", "utf8mb4"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_Event_CreationTime", |
|||
table: "WF_Event", |
|||
column: "CreationTime"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_Event_EventName_EventKey", |
|||
table: "WF_Event", |
|||
columns: new[] { "EventName", "EventKey" }); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_Event_IsProcessed", |
|||
table: "WF_Event", |
|||
column: "IsProcessed"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_ExecutionPointer_WorkflowId", |
|||
table: "WF_ExecutionPointer", |
|||
column: "WorkflowId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_ExtensionAttribute_ExecutionPointerId", |
|||
table: "WF_ExtensionAttribute", |
|||
column: "ExecutionPointerId"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_ScheduledCommand_CommandName_Data", |
|||
table: "WF_ScheduledCommand", |
|||
columns: new[] { "CommandName", "Data" }, |
|||
unique: true); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_ScheduledCommand_ExecuteTime", |
|||
table: "WF_ScheduledCommand", |
|||
column: "ExecuteTime"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_Subscription_EventKey", |
|||
table: "WF_Subscription", |
|||
column: "EventKey"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_Subscription_EventName", |
|||
table: "WF_Subscription", |
|||
column: "EventName"); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_WF_Workflow_NextExecution", |
|||
table: "WF_Workflow", |
|||
column: "NextExecution"); |
|||
} |
|||
|
|||
protected override void Down(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropTable( |
|||
name: "WF_Compensate"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_Definition"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_Event"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_ExecutionError"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_ExtensionAttribute"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_ScheduledCommand"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_Step"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_Subscription"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_ExecutionPointer"); |
|||
|
|||
migrationBuilder.DropTable( |
|||
name: "WF_Workflow"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,555 @@ |
|||
// <auto-generated />
|
|||
using System; |
|||
using LY.MicroService.WorkflowManagement.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
#nullable disable |
|||
|
|||
namespace LY.MicroService.WorkflowManagement.Migrations |
|||
{ |
|||
[DbContext(typeof(WorkflowManagementMigrationsDbContext))] |
|||
partial class WorkflowManagementMigrationsDbContextModelSnapshot : ModelSnapshot |
|||
{ |
|||
protected override void BuildModel(ModelBuilder modelBuilder) |
|||
{ |
|||
#pragma warning disable 612, 618
|
|||
modelBuilder |
|||
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql) |
|||
.HasAnnotation("ProductVersion", "6.0.0") |
|||
.HasAnnotation("Relational:MaxIdentifierLength", 64); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedEvent", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<string>("EventData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("EventKey") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<bool>("IsProcessed") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("CreationTime"); |
|||
|
|||
b.HasIndex("IsProcessed"); |
|||
|
|||
b.HasIndex("EventName", "EventKey"); |
|||
|
|||
b.ToTable("WF_Event", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionError", b => |
|||
{ |
|||
b.Property<int>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<DateTime>("ErrorTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<Guid>("ExecutionPointerId") |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<string>("Message") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_ExecutionError", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<bool>("Active") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("Children") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("ContextItem") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<DateTime?>("EndTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("EventData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("EventKey") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<bool>("EventPublished") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("Outcome") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("PersistenceData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("PredecessorId") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<int>("RetryCount") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Scope") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<DateTime?>("SleepUntil") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<DateTime?>("StartTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<int>("Status") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<int>("StepId") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("StepName") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("WorkflowId"); |
|||
|
|||
b.ToTable("WF_ExecutionPointer", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExtensionAttribute", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid>("ExecutionPointerId") |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<string>("Key") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<string>("Value") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("ExecutionPointerId"); |
|||
|
|||
b.ToTable("WF_ExtensionAttribute", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedScheduledCommand", b => |
|||
{ |
|||
b.Property<long>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("CommandName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("Data") |
|||
.HasMaxLength(500) |
|||
.HasColumnType("varchar(500)"); |
|||
|
|||
b.Property<long>("ExecuteTime") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("ExecuteTime"); |
|||
|
|||
b.HasIndex("CommandName", "Data") |
|||
.IsUnique(); |
|||
|
|||
b.ToTable("WF_ScheduledCommand", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedSubscription", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("EventKey") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("EventName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<Guid>("ExecutionPointerId") |
|||
.HasMaxLength(50) |
|||
.HasColumnType("char(50)"); |
|||
|
|||
b.Property<string>("ExternalToken") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<DateTime?>("ExternalTokenExpiry") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("ExternalWorkerId") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int>("StepId") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<DateTime>("SubscribeAsOf") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("SubscriptionData") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("EventKey"); |
|||
|
|||
b.HasIndex("EventName"); |
|||
|
|||
b.ToTable("WF_Subscription", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<DateTime?>("CompleteTime") |
|||
.HasColumnType("datetime(6)"); |
|||
|
|||
b.Property<string>("ConcurrencyStamp") |
|||
.IsConcurrencyToken() |
|||
.HasMaxLength(40) |
|||
.HasColumnType("varchar(40)") |
|||
.HasColumnName("ConcurrencyStamp"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("CreatorId"); |
|||
|
|||
b.Property<string>("Data") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("Description") |
|||
.HasMaxLength(500) |
|||
.HasColumnType("varchar(500)"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.HasColumnType("longtext") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<DateTime?>("LastModificationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("LastModificationTime"); |
|||
|
|||
b.Property<Guid?>("LastModifierId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("LastModifierId"); |
|||
|
|||
b.Property<long?>("NextExecution") |
|||
.HasColumnType("bigint"); |
|||
|
|||
b.Property<string>("Reference") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int>("Status") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<int>("Version") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("WorkflowDefinitionId") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.HasIndex("NextExecution"); |
|||
|
|||
b.ToTable("WF_Workflow", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.CompensateNode", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("CancelCondition") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int?>("ErrorBehavior") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Inputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("Name") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<string>("Outputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("ParentId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<TimeSpan?>("RetryInterval") |
|||
.HasColumnType("time(6)"); |
|||
|
|||
b.Property<bool>("Saga") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("SelectNextStep") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("StepType") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_Compensate", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.StepNode", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("CancelCondition") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int?>("ErrorBehavior") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<string>("Inputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("Name") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<string>("Outputs") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<Guid?>("ParentId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<TimeSpan?>("RetryInterval") |
|||
.HasColumnType("time(6)"); |
|||
|
|||
b.Property<bool>("Saga") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<string>("SelectNextStep") |
|||
.HasColumnType("longtext"); |
|||
|
|||
b.Property<string>("StepType") |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<Guid>("WorkflowId") |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_Step", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.Workflow", b => |
|||
{ |
|||
b.Property<Guid>("Id") |
|||
.ValueGeneratedOnAdd() |
|||
.HasColumnType("char(36)"); |
|||
|
|||
b.Property<string>("ConcurrencyStamp") |
|||
.IsConcurrencyToken() |
|||
.HasMaxLength(40) |
|||
.HasColumnType("varchar(40)") |
|||
.HasColumnName("ConcurrencyStamp"); |
|||
|
|||
b.Property<DateTime>("CreationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("CreationTime"); |
|||
|
|||
b.Property<Guid?>("CreatorId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("CreatorId"); |
|||
|
|||
b.Property<string>("Description") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<string>("DisplayName") |
|||
.HasMaxLength(200) |
|||
.HasColumnType("varchar(200)"); |
|||
|
|||
b.Property<int>("ErrorBehavior") |
|||
.HasColumnType("int"); |
|||
|
|||
b.Property<TimeSpan?>("ErrorRetryInterval") |
|||
.HasColumnType("time(6)"); |
|||
|
|||
b.Property<string>("ExtraProperties") |
|||
.HasColumnType("longtext") |
|||
.HasColumnName("ExtraProperties"); |
|||
|
|||
b.Property<bool>("IsEnabled") |
|||
.HasColumnType("tinyint(1)"); |
|||
|
|||
b.Property<DateTime?>("LastModificationTime") |
|||
.HasColumnType("datetime(6)") |
|||
.HasColumnName("LastModificationTime"); |
|||
|
|||
b.Property<Guid?>("LastModifierId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("LastModifierId"); |
|||
|
|||
b.Property<string>("Name") |
|||
.IsRequired() |
|||
.HasMaxLength(100) |
|||
.HasColumnType("varchar(100)"); |
|||
|
|||
b.Property<Guid?>("TenantId") |
|||
.HasColumnType("char(36)") |
|||
.HasColumnName("TenantId"); |
|||
|
|||
b.Property<int>("Version") |
|||
.HasColumnType("int"); |
|||
|
|||
b.HasKey("Id"); |
|||
|
|||
b.ToTable("WF_Definition", (string)null); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => |
|||
{ |
|||
b.HasOne("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", "Workflow") |
|||
.WithMany("ExecutionPointers") |
|||
.HasForeignKey("WorkflowId") |
|||
.OnDelete(DeleteBehavior.Cascade) |
|||
.IsRequired(); |
|||
|
|||
b.Navigation("Workflow"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExtensionAttribute", b => |
|||
{ |
|||
b.HasOne("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", "ExecutionPointer") |
|||
.WithMany("ExtensionAttributes") |
|||
.HasForeignKey("ExecutionPointerId") |
|||
.OnDelete(DeleteBehavior.Cascade) |
|||
.IsRequired(); |
|||
|
|||
b.Navigation("ExecutionPointer"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => |
|||
{ |
|||
b.Navigation("ExtensionAttributes"); |
|||
}); |
|||
|
|||
modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", b => |
|||
{ |
|||
b.Navigation("ExecutionPointers"); |
|||
}); |
|||
#pragma warning restore 612, 618
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using Microsoft.AspNetCore.Hosting; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Serilog; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement |
|||
{ |
|||
public class Program |
|||
{ |
|||
public static int Main(string[] args) |
|||
{ |
|||
try |
|||
{ |
|||
var host = CreateHostBuilder(args).Build(); |
|||
Log.Information("Starting web host."); |
|||
host.Run(); |
|||
return 0; |
|||
} |
|||
finally |
|||
{ |
|||
Log.CloseAndFlush(); |
|||
} |
|||
} |
|||
|
|||
internal static IHostBuilder CreateHostBuilder(string[] args) => |
|||
Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) |
|||
.ConfigureWebHostDefaults(webBuilder => |
|||
{ |
|||
webBuilder.UseStartup<Startup>(); |
|||
}) |
|||
.ConfigureAppConfiguration((context, config) => |
|||
{ |
|||
var configuration = config.Build(); |
|||
if (configuration.GetSection("AgileConfig").Exists()) |
|||
{ |
|||
config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration)); |
|||
} |
|||
}) |
|||
.UseSerilog((context, config) => |
|||
{ |
|||
config.ReadFrom.Configuration(context.Configuration); |
|||
}) |
|||
.UseAutofac(); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:20890", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"LINGYUN.Abp.WorkflowManagement.HttpApi.Host": { |
|||
"commandName": "Project", |
|||
"launchBrowser": false, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://127.0.0.1:30035", |
|||
"dotnetRunMessages": "true" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement |
|||
{ |
|||
public class Startup |
|||
{ |
|||
public void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.AddApplication<WorkflowManagementHttpApiHostModule>(); |
|||
} |
|||
|
|||
public void Configure(IApplicationBuilder app) |
|||
{ |
|||
app.InitializeApplication(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using Microsoft.Extensions.Options; |
|||
using Microsoft.OpenApi.Models; |
|||
using Swashbuckle.AspNetCore.SwaggerGen; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement |
|||
{ |
|||
public class TenantHeaderParamter : IOperationFilter |
|||
{ |
|||
private readonly AbpMultiTenancyOptions _options; |
|||
public TenantHeaderParamter( |
|||
IOptions<AbpMultiTenancyOptions> options) |
|||
{ |
|||
_options = options.Value; |
|||
} |
|||
public void Apply(OpenApiOperation operation, OperationFilterContext context) |
|||
{ |
|||
if (_options.IsEnabled) |
|||
{ |
|||
operation.Parameters = operation.Parameters ?? new List<OpenApiParameter>(); |
|||
operation.Parameters.Add(new OpenApiParameter |
|||
{ |
|||
Name = TenantResolverConsts.DefaultTenantKey, |
|||
In = ParameterLocation.Header, |
|||
Description = "Tenant Id/Name", |
|||
Required = false |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,223 @@ |
|||
using LINGYUN.Abp.ExceptionHandling; |
|||
using LINGYUN.Abp.ExceptionHandling.Emailing; |
|||
using LINGYUN.Abp.Serilog.Enrichers.Application; |
|||
using Medallion.Threading; |
|||
using Medallion.Threading.Redis; |
|||
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|||
using Microsoft.AspNetCore.DataProtection; |
|||
using Microsoft.Extensions.Caching.StackExchangeRedis; |
|||
using Microsoft.Extensions.Configuration; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.OpenApi.Models; |
|||
using StackExchange.Redis; |
|||
using System; |
|||
using System.Text.Encodings.Web; |
|||
using System.Text.Unicode; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Auditing; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.Json; |
|||
using Volo.Abp.Json.SystemTextJson; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.Uow; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement |
|||
{ |
|||
public partial class WorkflowManagementHttpApiHostModule |
|||
{ |
|||
private void PreConfigureApp() |
|||
{ |
|||
AbpSerilogEnrichersConsts.ApplicationName = "WorkflowManagement"; |
|||
} |
|||
|
|||
private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration) |
|||
{ |
|||
var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); |
|||
services.AddSingleton<IDistributedLockProvider>(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); |
|||
} |
|||
|
|||
private void ConfigureDbContext() |
|||
{ |
|||
// 配置Ef
|
|||
Configure<AbpDbContextOptions>(options => |
|||
{ |
|||
options.UseMySQL(); |
|||
}); |
|||
|
|||
Configure<AbpUnitOfWorkOptions>(options => |
|||
{ |
|||
|
|||
}); |
|||
} |
|||
|
|||
private void ConfigureJsonSerializer() |
|||
{ |
|||
// 解决某些不支持类型的序列化
|
|||
Configure<AbpJsonOptions>(options => |
|||
{ |
|||
options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss"; |
|||
}); |
|||
// 中文序列化的编码问题
|
|||
Configure<AbpSystemTextJsonSerializerOptions>(options => |
|||
{ |
|||
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureExceptionHandling() |
|||
{ |
|||
// 自定义需要处理的异常
|
|||
Configure<AbpExceptionHandlingOptions>(options => |
|||
{ |
|||
// 加入需要处理的异常类型
|
|||
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>(); |
|||
options.Handlers.Add<AbpInitializationException>(); |
|||
options.Handlers.Add<OutOfMemoryException>(); |
|||
options.Handlers.Add<System.Data.Common.DbException>(); |
|||
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>(); |
|||
options.Handlers.Add<System.Data.DBConcurrencyException>(); |
|||
}); |
|||
// 自定义需要发送邮件通知的异常类型
|
|||
Configure<AbpEmailExceptionHandlingOptions>(options => |
|||
{ |
|||
// 是否发送堆栈信息
|
|||
options.SendStackTrace = true; |
|||
// 未指定异常接收者的默认接收邮件
|
|||
// 指定自己的邮件地址
|
|||
}); |
|||
} |
|||
|
|||
private void ConfigureAuditing(IConfiguration configuration) |
|||
{ |
|||
Configure<AbpAuditingOptions>(options => |
|||
{ |
|||
options.ApplicationName = "WorkflowManagement"; |
|||
// 是否启用实体变更记录
|
|||
var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); |
|||
if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get<bool>()) |
|||
{ |
|||
options |
|||
.EntityHistorySelectors |
|||
.AddAllEntities(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureCaching(IConfiguration configuration) |
|||
{ |
|||
Configure<AbpDistributedCacheOptions>(options => |
|||
{ |
|||
// 最好统一命名,不然某个缓存变动其他应用服务有例外发生
|
|||
options.KeyPrefix = "LINGYUN.Abp.Application"; |
|||
// 滑动过期30天
|
|||
options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30d); |
|||
// 绝对过期60天
|
|||
options.GlobalCacheEntryOptions.AbsoluteExpiration = DateTimeOffset.Now.AddDays(60d); |
|||
}); |
|||
|
|||
Configure<RedisCacheOptions>(options => |
|||
{ |
|||
var redisConfig = ConfigurationOptions.Parse(options.Configuration); |
|||
options.ConfigurationOptions = redisConfig; |
|||
options.InstanceName = configuration["Redis:InstanceName"]; |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureVirtualFileSystem() |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<WorkflowManagementHttpApiHostModule>("LINGYUN.Abp.WorkflowManagement"); |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureMultiTenancy(IConfiguration configuration) |
|||
{ |
|||
// 多租户
|
|||
Configure<AbpMultiTenancyOptions>(options => |
|||
{ |
|||
options.IsEnabled = true; |
|||
}); |
|||
|
|||
var tenantResolveCfg = configuration.GetSection("App:Domains"); |
|||
if (tenantResolveCfg.Exists()) |
|||
{ |
|||
Configure<AbpTenantResolveOptions>(options => |
|||
{ |
|||
var domains = tenantResolveCfg.Get<string[]>(); |
|||
foreach (var domain in domains) |
|||
{ |
|||
options.AddDomainTenantResolver(domain); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
private void ConfigureSwagger(IServiceCollection services) |
|||
{ |
|||
// Swagger
|
|||
services.AddSwaggerGen( |
|||
options => |
|||
{ |
|||
options.SwaggerDoc("v1", new OpenApiInfo { Title = "WorkflowManagement API", Version = "v1" }); |
|||
options.DocInclusionPredicate((docName, description) => true); |
|||
options.CustomSchemaIds(type => type.FullName); |
|||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|||
{ |
|||
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", |
|||
Name = "Authorization", |
|||
In = ParameterLocation.Header, |
|||
Scheme = "bearer", |
|||
Type = SecuritySchemeType.Http, |
|||
BearerFormat = "JWT" |
|||
}); |
|||
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
|||
{ |
|||
{ |
|||
new OpenApiSecurityScheme |
|||
{ |
|||
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } |
|||
}, |
|||
new string[] { } |
|||
} |
|||
}); |
|||
options.OperationFilter<TenantHeaderParamter>(); |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureLocalization() |
|||
{ |
|||
// 支持本地化语言类型
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
|||
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
|||
// 动态语言支持
|
|||
options.Resources.AddDynamic(); |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureSecurity(IServiceCollection services, IConfiguration configuration, bool isDevelopment = false) |
|||
{ |
|||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
|||
.AddJwtBearer(options => |
|||
{ |
|||
options.Authority = configuration["AuthServer:Authority"]; |
|||
options.RequireHttpsMetadata = false; |
|||
options.Audience = configuration["AuthServer:ApiName"]; |
|||
}); |
|||
|
|||
if (!isDevelopment) |
|||
{ |
|||
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); |
|||
services |
|||
.AddDataProtection() |
|||
.SetApplicationName("LINGYUN.Abp.Application") |
|||
.PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement |
|||
{ |
|||
public partial class WorkflowManagementHttpApiHostModule |
|||
{ |
|||
private void SeedData(ApplicationInitializationContext context) |
|||
{ |
|||
if (context.GetEnvironment().IsDevelopment()) |
|||
{ |
|||
AsyncHelper.RunSync(async () => |
|||
await context.ServiceProvider.GetRequiredService<IDataSeeder>() |
|||
.SeedAsync()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,124 @@ |
|||
using LINGYUN.Abp.AuditLogging.Elasticsearch; |
|||
using LINGYUN.Abp.ExceptionHandling.Emailing; |
|||
using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; |
|||
using LINGYUN.Abp.MultiTenancy.DbFinder; |
|||
using LINGYUN.Abp.Serilog.Enrichers.Application; |
|||
using LINGYUN.Abp.WorkflowCore.Components; |
|||
using LINGYUN.Abp.WorkflowCore.DistributedLock; |
|||
using LINGYUN.Abp.WorkflowCore.LifeCycleEvent; |
|||
using LINGYUN.Abp.WorkflowCore.Persistence.EntityFrameworkCore; |
|||
using LINGYUN.Abp.WorkflowCore.RabbitMQ; |
|||
using LINGYUN.Abp.WorkflowManagement; |
|||
using LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Hosting; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using System.Globalization; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Authentication.JwtBearer; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Serilog; |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Caching.StackExchangeRedis; |
|||
using Volo.Abp.EntityFrameworkCore.MySQL; |
|||
using Volo.Abp.EventBus.RabbitMq; |
|||
using Volo.Abp.FeatureManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Http.Client.IdentityModel.Web; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.PermissionManagement.EntityFrameworkCore; |
|||
using Volo.Abp.SettingManagement.EntityFrameworkCore; |
|||
using Volo.Abp.Swashbuckle; |
|||
using Volo.Abp.TenantManagement.EntityFrameworkCore; |
|||
|
|||
namespace LY.MicroService.WorkflowManagement |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpSerilogEnrichersApplicationModule), |
|||
typeof(AbpAuditLoggingElasticsearchModule), |
|||
typeof(AbpAspNetCoreSerilogModule), |
|||
typeof(AbpEventBusRabbitMqModule), |
|||
typeof(WorkflowManagementApplicationModule), |
|||
typeof(WorkflowManagementHttpApiModule), |
|||
typeof(WorkflowManagementEntityFrameworkCoreModule), |
|||
typeof(AbpWorkflowCoreComponentsModule), |
|||
typeof(AbpWorkflowCoreDistributedLockModule), |
|||
typeof(AbpWorkflowCoreLifeCycleEventModule), |
|||
typeof(AbpWorkflowCoreRabbitMQModule), |
|||
typeof(AbpWorkflowCorePersistenceEntityFrameworkCoreModule), |
|||
typeof(AbpEntityFrameworkCoreMySQLModule), |
|||
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), |
|||
typeof(AbpEmailingExceptionHandlingModule), |
|||
typeof(AbpHttpClientIdentityModelWebModule), |
|||
typeof(AbpAspNetCoreMultiTenancyModule), |
|||
typeof(AbpDbFinderMultiTenancyModule), |
|||
typeof(AbpFeatureManagementEntityFrameworkCoreModule), |
|||
typeof(AbpPermissionManagementEntityFrameworkCoreModule), |
|||
typeof(AbpSettingManagementEntityFrameworkCoreModule), |
|||
typeof(AbpTenantManagementEntityFrameworkCoreModule), |
|||
typeof(AbpLocalizationManagementEntityFrameworkCoreModule), |
|||
typeof(AbpCachingStackExchangeRedisModule), |
|||
typeof(AbpAspNetCoreMvcModule), |
|||
typeof(AbpSwashbuckleModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
public partial class WorkflowManagementHttpApiHostModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddAlwaysAllowAuthorization(); |
|||
|
|||
PreConfigureApp(); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = hostingEnvironment.BuildConfiguration(); |
|||
|
|||
ConfigureDbContext(); |
|||
ConfigureLocalization(); |
|||
ConfigureJsonSerializer(); |
|||
ConfigureExceptionHandling(); |
|||
ConfigureVirtualFileSystem(); |
|||
ConfigureCaching(configuration); |
|||
ConfigureAuditing(configuration); |
|||
ConfigureMultiTenancy(configuration); |
|||
ConfigureSwagger(context.Services); |
|||
ConfigureDistributedLock(context.Services, configuration); |
|||
ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); |
|||
} |
|||
|
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
var env = context.GetEnvironment(); |
|||
|
|||
app.UseStaticFiles(); |
|||
app.UseCorrelationId(); |
|||
app.UseRouting(); |
|||
app.UseCors(); |
|||
app.UseAuthentication(); |
|||
app.UseJwtTokenMiddleware(); |
|||
app.UseMultiTenancy(); |
|||
app.UseAbpRequestLocalization(options => options.SetDefaultCulture(CultureInfo.CurrentCulture.Name)); |
|||
app.UseAuthorization(); |
|||
app.UseSwagger(); |
|||
app.UseAbpSwaggerUI(options => |
|||
{ |
|||
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support APP API"); |
|||
|
|||
var configuration = context.GetConfiguration(); |
|||
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); |
|||
options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); |
|||
options.OAuthScopes("WorkflowManagement"); |
|||
}); |
|||
app.UseAuditing(); |
|||
app.UseAbpSerilogEnrichers(); |
|||
app.UseConfiguredEndpoints(); |
|||
|
|||
SeedData(context); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
{ |
|||
"AgileConfig": { |
|||
"env": "DEV", |
|||
"appId": "LINGYUN.Abp.WorkflowManagement", |
|||
"secret": "1q2w3E*", |
|||
"nodes": "http://127.0.0.1:15000", |
|||
"name": "LINGYUN.Abp.WorkflowManagement", |
|||
"tag": "LINGYUN.Abp.WorkflowManagement" |
|||
}, |
|||
"App": { |
|||
"TrackingEntitiesChanged": true |
|||
}, |
|||
"ConnectionStrings": { |
|||
"Default": "Server=127.0.0.1;Database=Workflow;User Id=root;Password=123456", |
|||
"WorkflowManagement": "Server=127.0.0.1;Database=Workflow;User Id=root;Password=123456", |
|||
"AbpWorkflowCore": "Server=127.0.0.1;Database=Workflow;User Id=root;Password=123456", |
|||
"AbpFeatureManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpPermissionManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpSettingManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456", |
|||
"AbpTenantManagement": "Server=127.0.0.1;Database=Platform;User Id=root;Password=123456" |
|||
}, |
|||
"RemoteServices": {}, |
|||
"IdentityClients": { |
|||
"InternalServiceClient": { |
|||
"Authority": "http://127.0.0.1:44385", |
|||
"RequireHttps": false, |
|||
"GrantType": "client_credentials", |
|||
"Scope": "lingyun-abp-application", |
|||
"ClientId": "InternalServiceClient", |
|||
"ClientSecret": "1q2w3E*" |
|||
} |
|||
}, |
|||
"RabbitMQ": { |
|||
"Connections": { |
|||
"AbpWorkflowCore": { |
|||
"HostName": "127.0.0.1", |
|||
"Port": 5672, |
|||
"UserName": "admin", |
|||
"Password": "123456", |
|||
"VirtualHost": "/" |
|||
} |
|||
}, |
|||
"EventBus": { |
|||
"ConnectionName": "AbpWorkflowCore", |
|||
"ClientName": "workflow.server", |
|||
"ExchangeName": "AbpWorkflowCore" |
|||
} |
|||
}, |
|||
"DistributedLock": { |
|||
"Redis": { |
|||
"Configuration": "127.0.0.1,defaultDatabase=15" |
|||
} |
|||
}, |
|||
"Redis": { |
|||
"Configuration": "127.0.0.1,defaultDatabase=10", |
|||
"InstanceName": "LINGYUN.Abp.Application" |
|||
}, |
|||
"AuthServer": { |
|||
"Authority": "http://127.0.0.1:44385/", |
|||
"ApiName": "lingyun-abp-application", |
|||
"SwaggerClientId": "InternalServiceClient", |
|||
"SwaggerClientSecret": "1q2w3E*" |
|||
}, |
|||
"Logging": { |
|||
"Serilog": { |
|||
"Elasticsearch": { |
|||
"IndexFormat": "abp.dev.logging-{0:yyyy.MM.dd}" |
|||
} |
|||
} |
|||
}, |
|||
"AuditLogging": { |
|||
"Elasticsearch": { |
|||
"IndexPrefix": "abp.dev.auditing" |
|||
} |
|||
}, |
|||
"Elasticsearch": { |
|||
"NodeUris": "http://127.0.0.1:9200" |
|||
}, |
|||
"Serilog": { |
|||
"MinimumLevel": { |
|||
"Default": "Debug", |
|||
"Override": { |
|||
"System": "Warning", |
|||
"Microsoft": "Warning", |
|||
"DotNetCore": "Debug" |
|||
} |
|||
}, |
|||
"WriteTo": [ |
|||
{ |
|||
"Name": "Console", |
|||
"Args": { |
|||
"restrictedToMinimumLevel": "Debug", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "Elasticsearch", |
|||
"Args": { |
|||
"nodeUris": "http://127.0.0.1:9200", |
|||
"indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}", |
|||
"autoRegisterTemplate": true, |
|||
"autoRegisterTemplateVersion": "ESv7" |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
{ |
|||
"StringEncryption": { |
|||
"DefaultPassPhrase": "s46c5q55nxpeS8Ra", |
|||
"InitVectorBytes": "s83ng0abvd02js84", |
|||
"DefaultSalt": "sf&5)s3#" |
|||
}, |
|||
"AllowedHosts": "*", |
|||
"Serilog": { |
|||
"MinimumLevel": { |
|||
"Default": "Debug", |
|||
"Override": { |
|||
"Microsoft.EntityFrameworkCore": "Debug", |
|||
"System": "Information", |
|||
"Microsoft": "Information" |
|||
} |
|||
}, |
|||
"Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName" ], |
|||
"WriteTo": [ |
|||
{ |
|||
"Name": "Console", |
|||
"Args": { |
|||
"initialMinimumLevel": "Verbose", |
|||
"standardErrorFromLevel": "Verbose", |
|||
"restrictedToMinimumLevel": "Verbose", |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Debug-.log", |
|||
"restrictedToMinimumLevel": "Debug", |
|||
"rollingInterval": "Day", |
|||
"fileSizeLimitBytes": 5242880, |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Info-.log", |
|||
"restrictedToMinimumLevel": "Information", |
|||
"rollingInterval": "Day", |
|||
"fileSizeLimitBytes": 5242880, |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Warn-.log", |
|||
"restrictedToMinimumLevel": "Warning", |
|||
"rollingInterval": "Day", |
|||
"fileSizeLimitBytes": 5242880, |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Error-.log", |
|||
"restrictedToMinimumLevel": "Error", |
|||
"rollingInterval": "Day", |
|||
"fileSizeLimitBytes": 5242880, |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
}, |
|||
{ |
|||
"Name": "File", |
|||
"Args": { |
|||
"path": "Logs/Fatal-.log", |
|||
"restrictedToMinimumLevel": "Fatal", |
|||
"rollingInterval": "Day", |
|||
"fileSizeLimitBytes": 5242880, |
|||
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
dapr run --app-id workflow --app-port 30035 -H 36550 -- dotnet run --no-build |
|||
Loading…
Reference in new issue