diff --git a/aspnet-core/LINGYUN.MicroService.Workflow.sln b/aspnet-core/LINGYUN.MicroService.Workflow.sln index 18d1a7cf1..0e6d1504e 100644 --- a/aspnet-core/LINGYUN.MicroService.Workflow.sln +++ b/aspnet-core/LINGYUN.MicroService.Workflow.sln @@ -43,6 +43,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{6CB521FC-A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LY.MicroService.WorkflowManagement.HttpApi.Host", "services\LY.MicroService.WorkflowManagement.HttpApi.Host\LY.MicroService.WorkflowManagement.HttpApi.Host.csproj", "{D5ED348D-D6F0-4093-BD7D-20E05AA1EB7B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflow-tests", "workflow-tests", "{57CB3446-B825-4C55-A24A-E15EB2CAA80D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.WorkflowCore.Tests", "tests\LINGYUN.Abp.WorkflowCore.Tests\LINGYUN.Abp.WorkflowCore.Tests.csproj", "{0A21C843-4175-42F2-A95D-A75ED1DC1E05}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -113,6 +117,10 @@ Global {D5ED348D-D6F0-4093-BD7D-20E05AA1EB7B}.Debug|Any CPU.Build.0 = Debug|Any CPU {D5ED348D-D6F0-4093-BD7D-20E05AA1EB7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5ED348D-D6F0-4093-BD7D-20E05AA1EB7B}.Release|Any CPU.Build.0 = Release|Any CPU + {0A21C843-4175-42F2-A95D-A75ED1DC1E05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A21C843-4175-42F2-A95D-A75ED1DC1E05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A21C843-4175-42F2-A95D-A75ED1DC1E05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A21C843-4175-42F2-A95D-A75ED1DC1E05}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -134,6 +142,7 @@ Global {C4B1160A-BF25-4868-B962-342ABA4A96EF} = {C4496993-41F5-4821-829E-B80A8B3BC260} {9F9453F3-7124-4C22-91E3-0DC41A4FD8AB} = {A2963E0D-D290-40B2-9B36-75F4A5922ABF} {D5ED348D-D6F0-4093-BD7D-20E05AA1EB7B} = {6CB521FC-AC40-49A6-B9A5-91399CAA59AB} + {0A21C843-4175-42F2-A95D-A75ED1DC1E05} = {57CB3446-B825-4C55-A24A-E15EB2CAA80D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6BB7A5DE-DA12-44DC-BC9B-0F6CA524346F} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.RabbitMQ/LINGYUN/Abp/WorkflowCore/RabbitMQ/AbpRabbitMqQueueProvider.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.RabbitMQ/LINGYUN/Abp/WorkflowCore/RabbitMQ/AbpRabbitMqQueueProvider.cs index a604fcf94..5bd6ed5ae 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.RabbitMQ/LINGYUN/Abp/WorkflowCore/RabbitMQ/AbpRabbitMqQueueProvider.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore.RabbitMQ/LINGYUN/Abp/WorkflowCore/RabbitMQ/AbpRabbitMqQueueProvider.cs @@ -43,6 +43,7 @@ namespace LINGYUN.Abp.WorkflowCore.RabbitMQ public async Task DequeueWork(QueueType queue, CancellationToken cancellationToken) { + // TODO: 存在已知的问题,在多租户情况下, 从队列获取的工作流标识将无法查询到工作流实例 CheckDisposed(); using (await SyncObj.LockAsync(cancellationToken)) @@ -76,7 +77,7 @@ namespace LINGYUN.Abp.WorkflowCore.RabbitMQ await EnsureInitializedAsync(); var body = Encoding.UTF8.GetBytes(id); - + ChannelAccessor.Channel.BasicPublish( exchange: "", routingKey: QueueNameNormalizer.NormalizeKey(queue), diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN.Abp.WorkflowCore.csproj b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN.Abp.WorkflowCore.csproj index 9be2ef017..758428432 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN.Abp.WorkflowCore.csproj +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN.Abp.WorkflowCore.csproj @@ -10,6 +10,7 @@ + diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreModule.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreModule.cs index 7ed821f8a..97a49d442 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreModule.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using LINGYUN.Abp.WorkflowCore.Middleware; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; @@ -40,6 +41,10 @@ namespace LINGYUN.Abp.WorkflowCore context.Services.ExecutePreConfiguredActions(options); }); context.Services.AddWorkflowDSL(); + + context.Services.AddWorkflowMiddleware(); + + context.Services.AddWorkflowStepMiddleware(); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreOptions.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreOptions.cs index ff2e7a6fc..4bb0dfeab 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreOptions.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/AbpWorkflowCoreOptions.cs @@ -3,6 +3,7 @@ public class AbpWorkflowCoreOptions { public bool IsEnabled { get; set; } + public AbpWorkflowCoreOptions() { IsEnabled = true; diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/ExceptionHandling/ExceptionNotifierHandler.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/ExceptionHandling/ExceptionNotifierHandler.cs new file mode 100644 index 000000000..a6d5224a0 --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/ExceptionHandling/ExceptionNotifierHandler.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using Volo.Abp.ExceptionHandling; +using WorkflowCore.Interface; +using WorkflowCore.Models; + +namespace LINGYUN.Abp.WorkflowCore.ExceptionHandling +{ + /// + /// 不会自动注册到容器 + /// 需要时手动注册 + /// + public class ExceptionNotifierHandler : IWorkflowErrorHandler + { + public WorkflowErrorHandling Type => WorkflowErrorHandling.Terminate; + + private readonly IExceptionNotifier _exceptionNotifier; + + public ExceptionNotifierHandler(IExceptionNotifier exceptionNotifier) + { + _exceptionNotifier = exceptionNotifier; + } + + public void Handle(WorkflowInstance workflow, WorkflowDefinition def, ExecutionPointer pointer, WorkflowStep step, Exception exception, Queue bubbleUpQueue) + { + _ = _exceptionNotifier.NotifyAsync( + new ExceptionNotificationContext( + exception, + LogLevel.Warning)); + } + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/IStepMultiTenant.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/IStepMultiTenant.cs new file mode 100644 index 000000000..ac3c5e7ce --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/IStepMultiTenant.cs @@ -0,0 +1,9 @@ +namespace LINGYUN.Abp.WorkflowCore +{ + /// + /// 实现接口用于启动多租户 + /// + public interface IStepMultiTenant + { + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/Middleware/FeatureCheckWorkflowMiddleware.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/Middleware/FeatureCheckWorkflowMiddleware.cs new file mode 100644 index 000000000..5e0aef738 --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/Middleware/FeatureCheckWorkflowMiddleware.cs @@ -0,0 +1,43 @@ +using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Features; +using WorkflowCore.Interface; +using WorkflowCore.Models; + +namespace LINGYUN.Abp.WorkflowCore.Middleware +{ + public class FeatureCheckWorkflowMiddleware : IWorkflowMiddleware + { + private readonly IFeatureChecker _featureChecker; + private readonly ILogger _logger; + public WorkflowMiddlewarePhase Phase => WorkflowMiddlewarePhase.PreWorkflow; + + public FeatureCheckWorkflowMiddleware( + IFeatureChecker featureChecker, + ILogger logger) + { + _featureChecker = featureChecker; + _logger = logger; + } + + public async Task HandleAsync(WorkflowInstance workflow, WorkflowDelegate next) + { + if (workflow.Data is IDictionary dictionary && + dictionary.TryGetValue(WorkflowCoreConsts.FeatureField, out var defFeatures)) + { + var requiresFeatures = defFeatures.ToString().Split(';'); + var passed = await _featureChecker.IsEnabledAsync(requiresAll: true, requiresFeatures); + if (!passed) + { + _logger.LogWarning("Workflow {0} was forcibly terminated for the following reasons: These required functions must be enabled: {1}", + workflow.Id, + requiresFeatures); + workflow.Status = WorkflowStatus.Terminated; + } + } + + await next(); + } + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/Middleware/MultiTenancyStepMiddleware.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/Middleware/MultiTenancyStepMiddleware.cs new file mode 100644 index 000000000..002049e3b --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/Middleware/MultiTenancyStepMiddleware.cs @@ -0,0 +1,65 @@ +using Microsoft.Extensions.Options; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; +using WorkflowCore.Interface; +using WorkflowCore.Models; + +namespace LINGYUN.Abp.WorkflowCore.Middleware +{ + public class MultiTenancyStepMiddleware : IWorkflowStepMiddleware + { + private readonly AbpMultiTenancyOptions _multiTenancyOptions; + private readonly ICurrentTenant _currentTenant; + + public MultiTenancyStepMiddleware( + ICurrentTenant currentTenant, + IOptions options) + { + _currentTenant = currentTenant; + _multiTenancyOptions = options.Value; + } + + public async Task HandleAsync(IStepExecutionContext context, IStepBody body, WorkflowStepDelegate next) + { + // 触发多租户中间件条件 + // 1、需要启用多租户 + // 2、步骤需要实现接口 IStepMultiTenant + // 3.1、传递的工作流实现接口 IMultiTenant + // 3.2、传递的工作流数据包含 TenantId 字段 + + if (!_multiTenancyOptions.IsEnabled) + { + return await next(); + } + + if (typeof(IStepMultiTenant).IsAssignableFrom(body.GetType())) + { + if (context.Workflow.Data != null) + { + if (context.Workflow.Data is IMultiTenant tenant) + { + using (_currentTenant.Change(tenant.TenantId)) + { + return await next(); + } + } + + var dataObj = JObject.FromObject(context.Workflow.Data); + var tenantToken = dataObj.GetOrDefault(nameof(IMultiTenant.TenantId)); + if (tenantToken?.HasValues == true) + { + using (_currentTenant.Change(tenantToken.Value())) + { + return await next(); + } + } + } + } + + return await next(); + } + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyAsyncBase.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyAsyncBase.cs index be01a966f..7d44be262 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyAsyncBase.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyAsyncBase.cs @@ -2,7 +2,7 @@ namespace LINGYUN.Abp.WorkflowCore { - public abstract class StepBodyAsyncBase : StepBodyAsync + public abstract class StepBodyAsyncBase : StepBodyAsync, IStepMultiTenant { } } diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyBase.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyBase.cs index 87d9b942d..2bdb268fb 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyBase.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/StepBodyBase.cs @@ -2,7 +2,7 @@ namespace LINGYUN.Abp.WorkflowCore { - public abstract class StepBodyBase : StepBody + public abstract class StepBodyBase : StepBody, IStepMultiTenant { } } diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/WorkflowCoreConsts.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/WorkflowCoreConsts.cs new file mode 100644 index 000000000..58070cd74 --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowCore/LINGYUN/Abp/WorkflowCore/WorkflowCoreConsts.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.WorkflowCore +{ + public static class WorkflowCoreConsts + { + public const string FeatureField = "Feature"; + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDataDto.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDataDto.cs new file mode 100644 index 000000000..3f53a1060 --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDataDto.cs @@ -0,0 +1,29 @@ +namespace LINGYUN.Abp.WorkflowManagement.Workflows +{ + public class WorkflowDataDto + { + /// + /// 名称 + /// + public string Name { get; set; } + /// + /// 显示名称 + /// + public string DisplayName { get; set; } + /// + /// 数据类型 + /// + public DataType DataType { get; set; } + /// + /// 是否必输 + /// 默认: false + /// + public bool IsRequired { get; set; } + /// + /// 是否区分大小写 + /// 默认: false + /// 暂无用 + /// + public bool IsCaseSensitive { get; set; } + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDefinitionCreateDto.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDefinitionCreateDto.cs index 307ae0b09..57b9ab835 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDefinitionCreateDto.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/Dto/WorkflowDefinitionCreateDto.cs @@ -34,6 +34,11 @@ namespace LINGYUN.Abp.WorkflowManagement.Workflows [Range(1, 100)] public int Version { get; set; } + /// + /// 输入数据约束 + /// + public List Datas { get; set; } = new List(); + [Required] [MinLength(1)] public List Steps { get; set; } = new List(); diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/IWorkflowAppService.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/IWorkflowAppService.cs index e5b81a542..871aa8d5e 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/IWorkflowAppService.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application.Contracts/LINGYUN/Abp/WorkflowManagement/Workflows/IWorkflowAppService.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Volo.Abp.Application.Services; namespace LINGYUN.Abp.WorkflowManagement.Workflows @@ -7,7 +8,7 @@ namespace LINGYUN.Abp.WorkflowManagement.Workflows { Task GetAsync(string id); - Task StartAsync(string id, WorkflowStartInput input); + Task StartAsync(Guid id, WorkflowStartInput input); Task SuspendAsync(string id); diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowAppService.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowAppService.cs index d23e68124..8bbb98c6d 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowAppService.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowAppService.cs @@ -1,9 +1,11 @@ using Microsoft.AspNetCore.Authorization; using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.MultiTenancy; using WorkflowCore.Interface; using WorkflowCore.Models; @@ -14,13 +16,16 @@ namespace LINGYUN.Abp.WorkflowManagement.Workflows { private readonly IWorkflowController _controller; private readonly IPersistenceProvider _persistence; + private readonly IWorkflowRepository _workflowRepository; public WorkflowAppService( IWorkflowController controller, - IPersistenceProvider persistence) + IPersistenceProvider persistence, + IWorkflowRepository workflowRepository) { _controller = controller; _persistence = persistence; + _workflowRepository = workflowRepository; } public virtual async Task GetAsync(string id) @@ -41,22 +46,53 @@ namespace LINGYUN.Abp.WorkflowManagement.Workflows } } - public virtual async Task StartAsync(string id, WorkflowStartInput input) + public virtual async Task StartAsync(Guid id, WorkflowStartInput input) { - var workflowData = new Dictionary(); + var workflowDef = await _workflowRepository.GetAsync(id); + + var workflowData = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (var data in input.Data) { + object inputValue = data.Value; if (data.Value is JsonElement element) { - workflowData.TryAdd(data.Key, JsonConvert.DeserializeObject(element.ToString())); + inputValue = JsonConvert.DeserializeObject(element.ToString()); } else { - workflowData.TryAdd(data.Key, data.Value); + var defData = workflowDef.FindData(data.Key); + if (defData != null) + { + if (defData.TryParse(inputValue, out inputValue)) + { + workflowData.TryAdd(data.Key, inputValue); + continue; + } + + throw new BusinessException(WorkflowManagementErrorCodes.InvalidInputDataType) + .WithData("Property", defData.DisplayName) + .WithData("DataType", defData.DataType.ToString()); + } + } + + workflowData.TryAdd(data.Key, inputValue); + } + + if (CurrentTenant.IsAvailable) + { + workflowData.TryAdd(nameof(IMultiTenant.TenantId), CurrentTenant.GetId()); + } + + foreach (var data in workflowDef.Datas) + { + if (data.IsRequired && !workflowData.ContainsKey(data.Name)) + { + throw new BusinessException(WorkflowManagementErrorCodes.MissingRequiredProperty) + .WithData("Property", data.DisplayName); } } - var instanceId = await _controller.StartWorkflow(id, workflowData); + var instanceId = await _controller.StartWorkflow(workflowDef.Id.ToString(), workflowData); var result = await _persistence.GetWorkflowInstance(instanceId); return ObjectMapper.Map(result); diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowDefinitionAppService.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowDefinitionAppService.cs index ee48cb78f..8a986411d 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowDefinitionAppService.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Application/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowDefinitionAppService.cs @@ -47,6 +47,17 @@ namespace LINGYUN.Abp.WorkflowManagement.Workflows IsEnabled = input.IsEnabled, }; + foreach (var data in input.Datas) + { + workflowDef.AddData( + GuidGenerator, + data.Name, + data.DisplayName, + data.DataType, + data.IsRequired, + data.IsCaseSensitive); + } + var stepDefNodes = new List(); var stepCompensateDefNodes = new List(); diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/DataType.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/DataType.cs new file mode 100644 index 000000000..f70c65fdd --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/DataType.cs @@ -0,0 +1,12 @@ +namespace LINGYUN.Abp.WorkflowManagement +{ + public enum DataType + { + Object, + String, + Number, + Date, + DateTime, + Booleaen + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/en.json b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/en.json index aa07505ee..fb0e6995e 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/en.json +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/en.json @@ -12,6 +12,9 @@ "Workflow:10100": "Unable to restart workflow temporarily, please check log.", "Workflow:10101": "Unable to suspend workflow, please check log.", "Workflow:10102": "Unable to terminate workflow temporarily, please check log.", + "Workflow:10110": "Missing required Property {Property}.", + "Workflow:10111": "The mandatory {Property} field cannot be null.", + "Workflow:10112": "The field {Property} is not a valid {DataType} type.", "DisplayName:IsEnabled": "Is Enabled", "DisplayName:Name": "Name", "DisplayName:DisplayName": "DisplayName", diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/zh-Hans.json b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/zh-Hans.json index 2a74d4086..6d5b14852 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/Localization/Resources/zh-Hans.json @@ -12,6 +12,9 @@ "Workflow:10100": "暂时无法重启工作流,请检查日志.", "Workflow:10101": "暂时无法暂停工作流,请检查日志.", "Workflow:10102": "暂时无法终止工作流,请检查日志.", + "Workflow:10110": "缺失必要的属性 {Property}.", + "Workflow:10111": "必输字段 {Property} 不能为空.", + "Workflow:10112": "字段 {Property} 不是有效的 {DataType} 类型.", "DisplayName:IsEnabled": "是否启用", "DisplayName:Name": "名称", "DisplayName:DisplayName": "显示名称", diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowDataConsts.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowDataConsts.cs new file mode 100644 index 000000000..c35b2299b --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowDataConsts.cs @@ -0,0 +1,8 @@ +namespace LINGYUN.Abp.WorkflowManagement +{ + public static class WorkflowDataConsts + { + public static int MaxNameLength { get; set; } = 100; + public static int MaxDisplayNameLength { get; set; } = 100; + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowManagementErrorCodes.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowManagementErrorCodes.cs index c0d826271..e9949fddb 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowManagementErrorCodes.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain.Shared/LINGYUN/Abp/WorkflowManagement/WorkflowManagementErrorCodes.cs @@ -7,5 +7,18 @@ public const string ResumeError = Namespace + ":10100"; public const string SuspendError = Namespace + ":10101"; public const string TerminateError = Namespace + ":10102"; + + /// + /// 缺失必要的属性 {Property} + /// + public const string MissingRequiredProperty = Namespace + ":10110"; + /// + /// 必输字段 {Property} 不能为空 + /// + public const string InvalidInputNullable = Namespace + ":10111"; + /// + /// 字段 {Property} 不是有效的 {DataType} 类型 + /// + public const string InvalidInputDataType = Namespace + ":10112"; } } diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/Workflow.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/Workflow.cs index 18e082d47..55e0aac79 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/Workflow.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/Workflow.cs @@ -1,5 +1,9 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using WorkflowCore.Models; @@ -39,8 +43,11 @@ namespace LINGYUN.Abp.WorkflowManagement public virtual TimeSpan? ErrorRetryInterval { get; set; } + public virtual ICollection Datas { get; protected set; } + protected Workflow() { + Datas = new Collection(); } public Workflow( @@ -60,6 +67,35 @@ namespace LINGYUN.Abp.WorkflowManagement ErrorBehavior = errorBehavior; ErrorRetryInterval = errorRetryInterval; TenantId = tenantId; + + Datas = new Collection(); + } + + public void AddData( + IGuidGenerator guidGenerator, + string name, + string displayName, + DataType dataType, + bool isRequired = false, + bool isCaseSensitive = false) + { + if (FindData(name) == null) + { + Datas.Add(new WorkflowData( + guidGenerator.Create(), + Id, + name, + displayName, + dataType, + isRequired, + isCaseSensitive, + TenantId)); + } + } + + public WorkflowData FindData(string name) + { + return Datas.FirstOrDefault(x => x.Name.Equals(name)); } } } diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/WorkflowData.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/WorkflowData.cs new file mode 100644 index 000000000..a1247dbee --- /dev/null +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.Domain/LINGYUN/Abp/WorkflowManagement/WorkflowData.cs @@ -0,0 +1,108 @@ +using System; +using Volo.Abp; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.WorkflowManagement +{ + public class WorkflowData : Entity, IMultiTenant + { + public virtual Guid? TenantId { get; protected set; } + public virtual Guid WorkflowId { get; protected set; } + /// + /// 名称 + /// + public virtual string Name { get; protected set; } + /// + /// 显示名称 + /// + public virtual string DisplayName { get; protected set; } + /// + /// 数据类型 + /// + public virtual DataType DataType { get; protected set; } + /// + /// 是否必输 + /// 默认: false + /// + public virtual bool IsRequired { get; protected set; } + /// + /// 是否区分大小写 + /// 默认: false + /// 暂无用 + /// + public virtual bool IsCaseSensitive { get; protected set; } + protected WorkflowData() { } + public WorkflowData( + Guid id, + Guid workflowId, + string name, + string displayName, + DataType dataType = DataType.String, + bool isRequired = false, + bool isCaseSensitive = false, + Guid? tenantId = null) : base(id) + { + WorkflowId = workflowId; + Name = name; + DisplayName = displayName; + DataType = dataType; + IsRequired = isRequired; + IsCaseSensitive = isCaseSensitive; + TenantId = tenantId; + } + + public bool TryParse(object input, out object value) + { + if (input == null) + { + if (IsRequired) + { + throw new BusinessException(WorkflowManagementErrorCodes.InvalidInputNullable) + .WithData("Property", DisplayName); + } + // 字典类型不能为空 + value = new { }; + return true; + } + + switch (DataType) + { + case DataType.String: + value = input.ToString(); + return true; + case DataType.Booleaen: + if (input is bool boValue) + { + value = boValue; + return true; + } + value = input.ToString().ToLower() == "true"; + return true; + case DataType.Date: + case DataType.DateTime: + if (input is DateTime dateValue) + { + value = DataType == DataType.Date + ? dateValue.Date + : dateValue; + return true; + } + value = DateTime.Parse(input.ToString()); + return true; + case DataType.Number: + if (int.TryParse(input.ToString(), out int intValue)) + { + value = intValue; + return true; + } + value = 0; + return false; + case DataType.Object: + default: + value = input; + return true; + } + } + } +} diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/EfCoreWorkflowRepository.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/EfCoreWorkflowRepository.cs index aff26025c..e26001568 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/EfCoreWorkflowRepository.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/EfCoreWorkflowRepository.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; @@ -21,5 +22,12 @@ namespace LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore .AnyAsync(x => x.Name.Equals(name) && x.Version == version, GetCancellationToken(cancellationToken)); } + + public override async Task> WithDetailsAsync() + { + var queryable = await base.WithDetailsAsync(); + + return queryable.Include(x => x.Datas); + } } } diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/WorkflowManagementDbContextModelCreatingExtensions.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/WorkflowManagementDbContextModelCreatingExtensions.cs index 519c03fb8..6482a0138 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/WorkflowManagementDbContextModelCreatingExtensions.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore/LINGYUN/Abp/WorkflowManagement/EntityFrameworkCore/WorkflowManagementDbContextModelCreatingExtensions.cs @@ -30,6 +30,20 @@ namespace LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore b.Property(p => p.Name).HasMaxLength(WorkflowConsts.MaxNameLength).IsRequired(); b.Property(p => p.Description).HasMaxLength(WorkflowConsts.MaxDescriptionLength); + b.HasMany(u => u.Datas).WithOne().HasForeignKey(uc => uc.WorkflowId).IsRequired(); + + b.ConfigureByConvention(); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "DefinitionData", options.Schema); + + b.Property(p => p.DisplayName).HasMaxLength(WorkflowDataConsts.MaxDisplayNameLength).IsRequired(); + b.Property(p => p.Name).HasMaxLength(WorkflowDataConsts.MaxNameLength).IsRequired(); + + b.HasIndex(p => p.WorkflowId); + b.ConfigureByConvention(); }); diff --git a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.HttpApi/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowController.cs b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.HttpApi/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowController.cs index ed89507ae..8fd0656ca 100644 --- a/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.HttpApi/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowController.cs +++ b/aspnet-core/modules/workflow/LINGYUN.Abp.WorkflowManagement.HttpApi/LINGYUN/Abp/WorkflowManagement/Workflows/WorkflowController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using System; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.AspNetCore.Mvc; @@ -33,7 +34,7 @@ namespace LINGYUN.Abp.WorkflowManagement.Workflows [HttpPost] [Route("{id}/start")] - public virtual async Task StartAsync(string id, WorkflowStartInput input) + public virtual async Task StartAsync(Guid id, WorkflowStartInput input) { return await _service.StartAsync(id, input); } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Controllers/HomeController.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Controllers/HomeController.cs index 2c1d4b35f..e1e61391a 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Controllers/HomeController.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Controllers/HomeController.cs @@ -1,13 +1,12 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; -namespace LY.MicroService.WorkflowManagement.Controllers +namespace LY.MicroService.WorkflowManagement.Controllers; + +public class HomeController : AbpController { - public class HomeController : AbpController + public IActionResult Index() { - public IActionResult Index() - { - return Redirect("/swagger/index.html"); - } + return Redirect("/swagger/index.html"); } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Dockerfile b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Dockerfile index b7b9dc6cf..9fe768091 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Dockerfile +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Dockerfile @@ -4,9 +4,9 @@ WORKDIR /app COPY . /app -#�Ϻ�ʱ�� -#ENV TZ=Asia/Shanghai -#RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone +#东8区 +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone EXPOSE 80/tcp VOLUME [ "./app/Logs" ] diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContext.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContext.cs index 9428da377..44bbb3b19 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContext.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContext.cs @@ -3,22 +3,21 @@ using LINGYUN.Abp.WorkflowManagement.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; -namespace LY.MicroService.WorkflowManagement.EntityFrameworkCore +namespace LY.MicroService.WorkflowManagement.EntityFrameworkCore; + +public class WorkflowManagementMigrationsDbContext : AbpDbContext { - public class WorkflowManagementMigrationsDbContext : AbpDbContext + public WorkflowManagementMigrationsDbContext(DbContextOptions options) + : base(options) { - public WorkflowManagementMigrationsDbContext(DbContextOptions options) - : base(options) - { - } + } - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); - modelBuilder.ConfigureWorkflow(); - modelBuilder.ConfigureWorkflowManagement(); - } + modelBuilder.ConfigureWorkflow(); + modelBuilder.ConfigureWorkflowManagement(); } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContextFactory.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContextFactory.cs index 4c461c150..fbb81a49c 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContextFactory.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EntityFrameworkCore/WorkflowManagementMigrationsDbContextFactory.cs @@ -3,29 +3,28 @@ using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using System.IO; -namespace LY.MicroService.WorkflowManagement.EntityFrameworkCore +namespace LY.MicroService.WorkflowManagement.EntityFrameworkCore; + +public class WorkflowManagementMigrationsDbContextFactory : IDesignTimeDbContextFactory { - public class WorkflowManagementMigrationsDbContextFactory : IDesignTimeDbContextFactory + public WorkflowManagementMigrationsDbContext CreateDbContext(string[] args) { - public WorkflowManagementMigrationsDbContext CreateDbContext(string[] args) - { - var configuration = BuildConfiguration(); - var connectionString = configuration.GetConnectionString("WorkflowManagement"); + var configuration = BuildConfiguration(); + var connectionString = configuration.GetConnectionString("WorkflowManagement"); - var builder = new DbContextOptionsBuilder() - .UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); + var builder = new DbContextOptionsBuilder() + .UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); - return new WorkflowManagementMigrationsDbContext(builder.Options); - } + 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); + 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(); - } + return builder.Build(); } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs index 84bdf5918..02037aa6b 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs @@ -10,60 +10,59 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Uow; -namespace LY.MicroService.WorkflowManagement.EventBus.Handlers -{ - public class TenantSynchronizer : +namespace LY.MicroService.WorkflowManagement.EventBus.Handlers; + +public class TenantSynchronizer : IDistributedEventHandler, ITransientDependency - { - protected IDataSeeder DataSeeder { get; } - protected ICurrentTenant CurrentTenant { get; } - protected IDbSchemaMigrator DbSchemaMigrator { get; } - protected IUnitOfWorkManager UnitOfWorkManager { get; } +{ + protected IDataSeeder DataSeeder { get; } + protected ICurrentTenant CurrentTenant { get; } + protected IDbSchemaMigrator DbSchemaMigrator { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } - protected ILogger Logger { get; } + protected ILogger Logger { get; } - public TenantSynchronizer( - IDataSeeder dataSeeder, - ICurrentTenant currentTenant, - IDbSchemaMigrator dbSchemaMigrator, - IUnitOfWorkManager unitOfWorkManager, - ILogger logger) - { - DataSeeder = dataSeeder; - CurrentTenant = currentTenant; - DbSchemaMigrator = dbSchemaMigrator; - UnitOfWorkManager = unitOfWorkManager; + public TenantSynchronizer( + IDataSeeder dataSeeder, + ICurrentTenant currentTenant, + IDbSchemaMigrator dbSchemaMigrator, + IUnitOfWorkManager unitOfWorkManager, + ILogger logger) + { + DataSeeder = dataSeeder; + CurrentTenant = currentTenant; + DbSchemaMigrator = dbSchemaMigrator; + UnitOfWorkManager = unitOfWorkManager; - Logger = logger; - } + Logger = logger; + } - /// - /// 租户创建之后需要预置种子数据 - /// - /// - /// - public virtual async Task HandleEventAsync(CreateEventData eventData) + /// + /// 租户创建之后需要预置种子数据 + /// + /// + /// + public virtual async Task HandleEventAsync(CreateEventData eventData) + { + using (var unitOfWork = UnitOfWorkManager.Begin()) { - using (var unitOfWork = UnitOfWorkManager.Begin()) + using (CurrentTenant.Change(eventData.Id, eventData.Name)) { - using (CurrentTenant.Change(eventData.Id, eventData.Name)) - { - Logger.LogInformation("Migrating the new tenant database with WorkflowManagement..."); - // 迁移租户数据 - await DbSchemaMigrator.MigrateAsync( - (connectionString, builder) => - { - builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); + Logger.LogInformation("Migrating the new tenant database with WorkflowManagement..."); + // 迁移租户数据 + await DbSchemaMigrator.MigrateAsync( + (connectionString, builder) => + { + builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); - return new WorkflowManagementDbContext(builder.Options); - }); - Logger.LogInformation("Migrated the new tenant database with WorkflowManagement..."); + return new WorkflowManagementDbContext(builder.Options); + }); + Logger.LogInformation("Migrated the new tenant database with WorkflowManagement..."); - await DataSeeder.SeedAsync(new DataSeedContext(eventData.Id)); + await DataSeeder.SeedAsync(new DataSeedContext(eventData.Id)); - await unitOfWork.SaveChangesAsync(); - } + await unitOfWork.SaveChangesAsync(); } } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/20211214085456_Add-Entity-Workflow-Data-With-WF-Management.Designer.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/20211214085456_Add-Entity-Workflow-Data-With-WF-Management.Designer.cs new file mode 100644 index 000000000..5214e38aa --- /dev/null +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/20211214085456_Add-Entity-Workflow-Data-With-WF-Management.Designer.cs @@ -0,0 +1,610 @@ +// +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("20211214085456_Add-Entity-Workflow-Data-With-WF-Management")] + partial class AddEntityWorkflowDataWithWFManagement + { + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("EventData") + .HasColumnType("longtext"); + + b.Property("EventKey") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("EventName") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("IsProcessed") + .HasColumnType("tinyint(1)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ErrorTime") + .HasColumnType("datetime(6)"); + + b.Property("ExecutionPointerId") + .HasMaxLength(50) + .HasColumnType("char(50)"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("WorkflowId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("WF_ExecutionError", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasMaxLength(50) + .HasColumnType("char(50)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Children") + .HasColumnType("longtext"); + + b.Property("ContextItem") + .HasColumnType("longtext"); + + b.Property("EndTime") + .HasColumnType("datetime(6)"); + + b.Property("EventData") + .HasColumnType("longtext"); + + b.Property("EventKey") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("EventName") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("EventPublished") + .HasColumnType("tinyint(1)"); + + b.Property("Outcome") + .HasColumnType("longtext"); + + b.Property("PersistenceData") + .HasColumnType("longtext"); + + b.Property("PredecessorId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("RetryCount") + .HasColumnType("int"); + + b.Property("Scope") + .HasColumnType("longtext"); + + b.Property("SleepUntil") + .HasColumnType("datetime(6)"); + + b.Property("StartTime") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("StepId") + .HasColumnType("int"); + + b.Property("StepName") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("ExecutionPointerId") + .HasMaxLength(50) + .HasColumnType("char(50)"); + + b.Property("Key") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CommandName") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Data") + .HasMaxLength(500) + .HasColumnType("varchar(500)"); + + b.Property("ExecuteTime") + .HasColumnType("bigint"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("EventKey") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("EventName") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExecutionPointerId") + .HasMaxLength(50) + .HasColumnType("char(50)"); + + b.Property("ExternalToken") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExternalTokenExpiry") + .HasColumnType("datetime(6)"); + + b.Property("ExternalWorkerId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("StepId") + .HasColumnType("int"); + + b.Property("SubscribeAsOf") + .HasColumnType("datetime(6)"); + + b.Property("SubscriptionData") + .HasColumnType("longtext"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CompleteTime") + .HasColumnType("datetime(6)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("varchar(500)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("NextExecution") + .HasColumnType("bigint"); + + b.Property("Reference") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CancelCondition") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ErrorBehavior") + .HasColumnType("int"); + + b.Property("Inputs") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Outputs") + .HasColumnType("longtext"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("RetryInterval") + .HasColumnType("time(6)"); + + b.Property("Saga") + .HasColumnType("tinyint(1)"); + + b.Property("SelectNextStep") + .HasColumnType("longtext"); + + b.Property("StepType") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("WorkflowId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("WF_Compensate", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.StepNode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CancelCondition") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ErrorBehavior") + .HasColumnType("int"); + + b.Property("Inputs") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Outputs") + .HasColumnType("longtext"); + + b.Property("ParentId") + .HasColumnType("char(36)"); + + b.Property("RetryInterval") + .HasColumnType("time(6)"); + + b.Property("Saga") + .HasColumnType("tinyint(1)"); + + b.Property("SelectNextStep") + .HasColumnType("longtext"); + + b.Property("StepType") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("WorkflowId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("WF_Step", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.Workflow", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("varchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("char(36)") + .HasColumnName("CreatorId"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("DisplayName") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ErrorBehavior") + .HasColumnType("int"); + + b.Property("ErrorRetryInterval") + .HasColumnType("time(6)"); + + b.Property("ExtraProperties") + .HasColumnType("longtext") + .HasColumnName("ExtraProperties"); + + b.Property("IsEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("char(36)") + .HasColumnName("LastModifierId"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("WF_Definition", (string)null); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.WorkflowData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DataType") + .HasColumnType("int"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("IsCaseSensitive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("WorkflowId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("WorkflowId"); + + b.ToTable("WF_DefinitionData", (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.WorkflowManagement.WorkflowData", b => + { + b.HasOne("LINGYUN.Abp.WorkflowManagement.Workflow", null) + .WithMany("Datas") + .HasForeignKey("WorkflowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => + { + b.Navigation("ExtensionAttributes"); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", b => + { + b.Navigation("ExecutionPointers"); + }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.Workflow", b => + { + b.Navigation("Datas"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/20211214085456_Add-Entity-Workflow-Data-With-WF-Management.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/20211214085456_Add-Entity-Workflow-Data-With-WF-Management.cs new file mode 100644 index 000000000..07ee32061 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/20211214085456_Add-Entity-Workflow-Data-With-WF-Management.cs @@ -0,0 +1,147 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace LY.MicroService.WorkflowManagement.Migrations +{ + public partial class AddEntityWorkflowDataWithWFManagement : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "ExecutionPointerId", + table: "WF_Subscription", + type: "char(50)", + maxLength: 50, + nullable: false, + collation: "ascii_general_ci", + oldClrType: typeof(string), + oldType: "char(50)", + oldMaxLength: 50) + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ExecutionPointerId", + table: "WF_ExtensionAttribute", + type: "char(50)", + maxLength: 50, + nullable: false, + collation: "ascii_general_ci", + oldClrType: typeof(string), + oldType: "char(50)", + oldMaxLength: 50) + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "Id", + table: "WF_ExecutionPointer", + type: "char(50)", + maxLength: 50, + nullable: false, + collation: "ascii_general_ci", + oldClrType: typeof(string), + oldType: "char(50)", + oldMaxLength: 50) + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "ExecutionPointerId", + table: "WF_ExecutionError", + type: "char(50)", + maxLength: 50, + nullable: false, + collation: "ascii_general_ci", + oldClrType: typeof(string), + oldType: "char(50)", + oldMaxLength: 50) + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "WF_DefinitionData", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + TenantId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + WorkflowId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Name = table.Column(type: "varchar(100)", maxLength: 100, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + DisplayName = table.Column(type: "varchar(100)", maxLength: 100, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + DataType = table.Column(type: "int", nullable: false), + IsRequired = table.Column(type: "tinyint(1)", nullable: false), + IsCaseSensitive = table.Column(type: "tinyint(1)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WF_DefinitionData", x => x.Id); + table.ForeignKey( + name: "FK_WF_DefinitionData_WF_Definition_WorkflowId", + column: x => x.WorkflowId, + principalTable: "WF_Definition", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_WF_DefinitionData_WorkflowId", + table: "WF_DefinitionData", + column: "WorkflowId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "WF_DefinitionData"); + + migrationBuilder.AlterColumn( + name: "ExecutionPointerId", + table: "WF_Subscription", + type: "char(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(Guid), + oldType: "char(50)", + oldMaxLength: 50) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("Relational:Collation", "ascii_general_ci"); + + migrationBuilder.AlterColumn( + name: "ExecutionPointerId", + table: "WF_ExtensionAttribute", + type: "char(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(Guid), + oldType: "char(50)", + oldMaxLength: 50) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("Relational:Collation", "ascii_general_ci"); + + migrationBuilder.AlterColumn( + name: "Id", + table: "WF_ExecutionPointer", + type: "char(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(Guid), + oldType: "char(50)", + oldMaxLength: 50) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("Relational:Collation", "ascii_general_ci"); + + migrationBuilder.AlterColumn( + name: "ExecutionPointerId", + table: "WF_ExecutionError", + type: "char(50)", + maxLength: 50, + nullable: false, + oldClrType: typeof(Guid), + oldType: "char(50)", + oldMaxLength: 50) + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("Relational:Collation", "ascii_general_ci"); + } + } +} diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/WorkflowManagementMigrationsDbContextModelSnapshot.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/WorkflowManagementMigrationsDbContextModelSnapshot.cs index b99116af3..f39be2376 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/WorkflowManagementMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Migrations/WorkflowManagementMigrationsDbContextModelSnapshot.cs @@ -518,6 +518,45 @@ namespace LY.MicroService.WorkflowManagement.Migrations b.ToTable("WF_Definition", (string)null); }); + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.WorkflowData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("DataType") + .HasColumnType("int"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("IsCaseSensitive") + .HasColumnType("tinyint(1)"); + + b.Property("IsRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TenantId") + .HasColumnType("char(36)") + .HasColumnName("TenantId"); + + b.Property("WorkflowId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("WorkflowId"); + + b.ToTable("WF_DefinitionData", (string)null); + }); + modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => { b.HasOne("LINGYUN.Abp.WorkflowCore.Persistence.PersistedWorkflow", "Workflow") @@ -540,6 +579,15 @@ namespace LY.MicroService.WorkflowManagement.Migrations b.Navigation("ExecutionPointer"); }); + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.WorkflowData", b => + { + b.HasOne("LINGYUN.Abp.WorkflowManagement.Workflow", null) + .WithMany("Datas") + .HasForeignKey("WorkflowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("LINGYUN.Abp.WorkflowCore.Persistence.PersistedExecutionPointer", b => { b.Navigation("ExtensionAttributes"); @@ -549,6 +597,11 @@ namespace LY.MicroService.WorkflowManagement.Migrations { b.Navigation("ExecutionPointers"); }); + + modelBuilder.Entity("LINGYUN.Abp.WorkflowManagement.Workflow", b => + { + b.Navigation("Datas"); + }); #pragma warning restore 612, 618 } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Program.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Program.cs index 59bc1aec9..0ce7dd299 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Program.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Program.cs @@ -3,43 +3,42 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Serilog; -namespace LY.MicroService.WorkflowManagement +namespace LY.MicroService.WorkflowManagement; + +public class Program { - public class Program + public static int Main(string[] args) { - public static int Main(string[] args) + try { - try - { - var host = CreateHostBuilder(args).Build(); - Log.Information("Starting web host."); - host.Run(); - return 0; - } - finally - { - Log.CloseAndFlush(); - } + 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(); - }) - .ConfigureAppConfiguration((context, config) => - { - var configuration = config.Build(); - if (configuration.GetSection("AgileConfig").Exists()) - { - config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration)); - } - }) - .UseSerilog((context, config) => + internal static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .ConfigureAppConfiguration((context, config) => + { + var configuration = config.Build(); + if (configuration.GetSection("AgileConfig").Exists()) { - config.ReadFrom.Configuration(context.Configuration); - }) - .UseAutofac(); - } + config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration)); + } + }) + .UseSerilog((context, config) => + { + config.ReadFrom.Configuration(context.Configuration); + }) + .UseAutofac(); } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Startup.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Startup.cs index 43b1a77fb..cc0619d01 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Startup.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/Startup.cs @@ -1,18 +1,30 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; +using System.IO; +using Volo.Abp.IO; +using Volo.Abp.Modularity.PlugIns; -namespace LY.MicroService.WorkflowManagement +namespace LY.MicroService.WorkflowManagement; + +public class Startup { - public class Startup + public void ConfigureServices(IServiceCollection services) { - public void ConfigureServices(IServiceCollection services) + services.AddApplication(options => { - services.AddApplication(); - } + // 搜索 Modules 目录下所有文件作为插件 + // 取消显示引用所有其他项目的模块,改为通过插件的形式引用 + var pluginFolder = Path.Combine( + Directory.GetCurrentDirectory(), "Modules"); + DirectoryHelper.CreateIfNotExists(pluginFolder); + options.PlugInSources.AddFolder( + pluginFolder, + SearchOption.AllDirectories); + }); + } - public void Configure(IApplicationBuilder app) - { - app.InitializeApplication(); - } + public void Configure(IApplicationBuilder app) + { + app.InitializeApplication(); } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/TenantHeaderParamter.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/TenantHeaderParamter.cs index b183313fa..4b2ac7acc 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/TenantHeaderParamter.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/TenantHeaderParamter.cs @@ -4,29 +4,28 @@ using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Generic; using Volo.Abp.MultiTenancy; -namespace LY.MicroService.WorkflowManagement +namespace LY.MicroService.WorkflowManagement; + +public class TenantHeaderParamter : IOperationFilter { - public class TenantHeaderParamter : IOperationFilter + private readonly AbpMultiTenancyOptions _options; + public TenantHeaderParamter( + IOptions options) { - private readonly AbpMultiTenancyOptions _options; - public TenantHeaderParamter( - IOptions options) - { - _options = options.Value; - } - public void Apply(OpenApiOperation operation, OperationFilterContext context) + _options = options.Value; + } + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + if (_options.IsEnabled) { - if (_options.IsEnabled) + operation.Parameters = operation.Parameters ?? new List(); + operation.Parameters.Add(new OpenApiParameter { - operation.Parameters = operation.Parameters ?? new List(); - operation.Parameters.Add(new OpenApiParameter - { - Name = TenantResolverConsts.DefaultTenantKey, - In = ParameterLocation.Header, - Description = "Tenant Id/Name", - Required = false - }); - } + Name = TenantResolverConsts.DefaultTenantKey, + In = ParameterLocation.Header, + Description = "Tenant Id/Name", + Required = false + }); } } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs index 05ba245fb..d8e359749 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.Configure.cs @@ -27,168 +27,168 @@ using Volo.Abp.Uow; using Volo.Abp.VirtualFileSystem; using LINGYUN.Abp.WorkflowCore.Components; -namespace LY.MicroService.WorkflowManagement +namespace LY.MicroService.WorkflowManagement; + +public partial class WorkflowManagementHttpApiHostModule { - public partial class WorkflowManagementHttpApiHostModule + private void PreConfigureApp() { - private void PreConfigureApp() - { - AbpSerilogEnrichersConsts.ApplicationName = "WorkflowManagement"; - } + AbpSerilogEnrichersConsts.ApplicationName = "WorkflowManagement"; + } - private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration) - { - var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); - services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); - } + private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } - private void ConfigureBlobStoring(IServiceCollection services, IConfiguration configuration) + private void ConfigureBlobStoring(IServiceCollection services, IConfiguration configuration) + { + Configure(options => { - Configure(options => + services.ExecutePreConfiguredActions(options); + options.Containers.Configure((containerConfiguration) => { - services.ExecutePreConfiguredActions(options); - options.Containers.Configure((containerConfiguration) => + containerConfiguration.UseOssManagement(config => { - containerConfiguration.UseOssManagement(config => - { - config.Bucket = configuration[OssManagementBlobProviderConfigurationNames.Bucket] ?? "workflow"; - }); + config.Bucket = configuration[OssManagementBlobProviderConfigurationNames.Bucket] ?? "workflow"; }); }); - } + }); + } - private void ConfigureDbContext() + private void ConfigureDbContext() + { + // 配置Ef + Configure(options => { - // 配置Ef - Configure(options => - { - options.UseMySQL(); - }); - } + options.UseMySQL(); + }); + } - private void ConfigureJsonSerializer() + private void ConfigureJsonSerializer() + { + // 解决某些不支持类型的序列化 + Configure(options => { - // 解决某些不支持类型的序列化 - Configure(options => - { - options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss"; - }); - // 中文序列化的编码问题 - Configure(options => - { - options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); - }); - } + options.DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss"; + }); + // 中文序列化的编码问题 + Configure(options => + { + options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + }); + } - private void ConfigureExceptionHandling() + private void ConfigureExceptionHandling() + { + // 自定义需要处理的异常 + Configure(options => { - // 自定义需要处理的异常 - Configure(options => - { - // 加入需要处理的异常类型 - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - options.Handlers.Add(); - }); - // 自定义需要发送邮件通知的异常类型 - Configure(options => - { - // 是否发送堆栈信息 - options.SendStackTrace = true; - // 未指定异常接收者的默认接收邮件 - // 指定自己的邮件地址 - }); - } + // 加入需要处理的异常类型 + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + }); + // 自定义需要发送邮件通知的异常类型 + Configure(options => + { + // 是否发送堆栈信息 + options.SendStackTrace = true; + // 未指定异常接收者的默认接收邮件 + // 指定自己的邮件地址 + }); + } - private void ConfigureAuditing(IConfiguration configuration) + private void ConfigureAuditing(IConfiguration configuration) + { + Configure(options => { - Configure(options => + options.ApplicationName = "WorkflowManagement"; + // 是否启用实体变更记录 + var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); + if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get()) { - options.ApplicationName = "WorkflowManagement"; - // 是否启用实体变更记录 - var entitiesChangedConfig = configuration.GetSection("App:TrackingEntitiesChanged"); - if (entitiesChangedConfig.Exists() && entitiesChangedConfig.Get()) - { - options - .EntityHistorySelectors - .AddAllEntities(); - } - }); - } + options + .EntityHistorySelectors + .AddAllEntities(); + } + }); + } - private void ConfigureCaching(IConfiguration configuration) + private void ConfigureCaching(IConfiguration configuration) + { + Configure(options => { - Configure(options => - { - // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 - options.KeyPrefix = "LINGYUN.Abp.Application"; - // 滑动过期30天 - options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30d); - // 绝对过期60天 - options.GlobalCacheEntryOptions.AbsoluteExpiration = DateTimeOffset.Now.AddDays(60d); - }); + // 最好统一命名,不然某个缓存变动其他应用服务有例外发生 + options.KeyPrefix = "LINGYUN.Abp.Application"; + // 滑动过期30天 + options.GlobalCacheEntryOptions.SlidingExpiration = TimeSpan.FromDays(30d); + // 绝对过期60天 + options.GlobalCacheEntryOptions.AbsoluteExpiration = DateTimeOffset.Now.AddDays(60d); + }); + + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + } - Configure(options => - { - var redisConfig = ConfigurationOptions.Parse(options.Configuration); - options.ConfigurationOptions = redisConfig; - options.InstanceName = configuration["Redis:InstanceName"]; - }); - } + private void ConfigureVirtualFileSystem() + { + Configure(options => + { + options.FileSets.AddEmbedded("LINGYUN.Abp.WorkflowManagement"); + }); + } - private void ConfigureVirtualFileSystem() + private void ConfigureMultiTenancy(IConfiguration configuration) + { + // 多租户 + Configure(options => { - Configure(options => - { - options.FileSets.AddEmbedded("LINGYUN.Abp.WorkflowManagement"); - }); - } + options.IsEnabled = true; + }); - private void ConfigureMultiTenancy(IConfiguration configuration) + var tenantResolveCfg = configuration.GetSection("App:Domains"); + if (tenantResolveCfg.Exists()) { - // 多租户 - Configure(options => + Configure(options => { - options.IsEnabled = true; + var domains = tenantResolveCfg.Get(); + foreach (var domain in domains) + { + options.AddDomainTenantResolver(domain); + } }); + } + } - var tenantResolveCfg = configuration.GetSection("App:Domains"); - if (tenantResolveCfg.Exists()) + private void ConfigureSwagger(IServiceCollection services) + { + // Swagger + services.AddSwaggerGen( + options => { - Configure(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 { - var domains = tenantResolveCfg.Get(); - foreach (var domain in domains) - { - options.AddDomainTenantResolver(domain); - } + Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", + Name = "Authorization", + In = ParameterLocation.Header, + Scheme = "bearer", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT" }); - } - } - - private void ConfigureSwagger(IServiceCollection services) - { - // Swagger - services.AddSwaggerGen( - options => + options.AddSecurityRequirement(new OpenApiSecurityRequirement { - 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 { @@ -196,41 +196,40 @@ namespace LY.MicroService.WorkflowManagement }, new string[] { } } - }); - options.OperationFilter(); }); - } + options.OperationFilter(); + }); + } - private void ConfigureLocalization() + private void ConfigureLocalization() + { + // 支持本地化语言类型 + Configure(options => { - // 支持本地化语言类型 - Configure(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.Languages.Add(new LanguageInfo("en", "en", "English")); - options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); - // 动态语言支持 - options.Resources.AddDynamic(); + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = false; + options.Audience = configuration["AuthServer:ApiName"]; }); - } - private void ConfigureSecurity(IServiceCollection services, IConfiguration configuration, bool isDevelopment = false) + if (!isDevelopment) { - 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"); - } + var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + services + .AddDataProtection() + .SetApplicationName("LINGYUN.Abp.Application") + .PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); } } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.DataSeeder.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.DataSeeder.cs index a7d79401e..d9b9f2ac6 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.DataSeeder.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.DataSeeder.cs @@ -4,18 +4,17 @@ using Volo.Abp; using Volo.Abp.Data; using Volo.Abp.Threading; -namespace LY.MicroService.WorkflowManagement +namespace LY.MicroService.WorkflowManagement; + +public partial class WorkflowManagementHttpApiHostModule { - public partial class WorkflowManagementHttpApiHostModule + private void SeedData(ApplicationInitializationContext context) { - private void SeedData(ApplicationInitializationContext context) + if (context.GetEnvironment().IsDevelopment()) { - if (context.GetEnvironment().IsDevelopment()) - { - AsyncHelper.RunSync(async () => - await context.ServiceProvider.GetRequiredService() - .SeedAsync()); - } + AsyncHelper.RunSync(async () => + await context.ServiceProvider.GetRequiredService() + .SeedAsync()); } } } diff --git a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs index 044149d28..ce629ca57 100644 --- a/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs +++ b/aspnet-core/services/LY.MicroService.WorkflowManagement.HttpApi.Host/WorkflowManagementHttpApiHostModule.cs @@ -34,9 +34,9 @@ using Volo.Abp.SettingManagement.EntityFrameworkCore; using Volo.Abp.Swashbuckle; using Volo.Abp.TenantManagement.EntityFrameworkCore; -namespace LY.MicroService.WorkflowManagement -{ - [DependsOn( +namespace LY.MicroService.WorkflowManagement; + +[DependsOn( typeof(AbpSerilogEnrichersApplicationModule), typeof(AbpAuditLoggingElasticsearchModule), typeof(AbpAspNetCoreSerilogModule), @@ -67,64 +67,63 @@ namespace LY.MicroService.WorkflowManagement typeof(AbpSwashbuckleModule), typeof(AbpAutofacModule) )] - public partial class WorkflowManagementHttpApiHostModule : AbpModule +public partial class WorkflowManagementHttpApiHostModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) { - public override void PreConfigureServices(ServiceConfigurationContext context) - { - PreConfigureApp(); - } + PreConfigureApp(); + } - public override void ConfigureServices(ServiceConfigurationContext context) - { - var hostingEnvironment = context.Services.GetHostingEnvironment(); - var configuration = context.Services.GetConfiguration(); + public override void ConfigureServices(ServiceConfigurationContext context) + { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); - ConfigureDbContext(); - ConfigureLocalization(); - ConfigureJsonSerializer(); - ConfigureExceptionHandling(); - ConfigureVirtualFileSystem(); - ConfigureCaching(configuration); - ConfigureAuditing(configuration); - ConfigureMultiTenancy(configuration); - ConfigureSwagger(context.Services); - ConfigureBlobStoring(context.Services, configuration); - ConfigureDistributedLock(context.Services, configuration); - ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); + ConfigureDbContext(); + ConfigureLocalization(); + ConfigureJsonSerializer(); + ConfigureExceptionHandling(); + ConfigureVirtualFileSystem(); + ConfigureCaching(configuration); + ConfigureAuditing(configuration); + ConfigureMultiTenancy(configuration); + ConfigureSwagger(context.Services); + ConfigureBlobStoring(context.Services, configuration); + ConfigureDistributedLock(context.Services, configuration); + ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); - // 开发取消权限检查 - // context.Services.AddAlwaysAllowAuthorization(); - } + // 开发取消权限检查 + // context.Services.AddAlwaysAllowAuthorization(); + } - public override void OnApplicationInitialization(ApplicationInitializationContext context) - { - var app = context.GetApplicationBuilder(); - var env = context.GetEnvironment(); + 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"); + 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(); + 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); - } + SeedData(context); } } diff --git a/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN.Abp.WorkflowCore.Tests.csproj b/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN.Abp.WorkflowCore.Tests.csproj index 248440a29..8aca85f09 100644 --- a/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN.Abp.WorkflowCore.Tests.csproj +++ b/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN.Abp.WorkflowCore.Tests.csproj @@ -1,18 +1,19 @@  - - net6.0 - - false - + + net6.0 + + false + - - - + + + + - - - - + + + + diff --git a/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN/Abp/WorkflowCore/Middleware/MultiTenancyStepMiddleware_Tests.cs b/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN/Abp/WorkflowCore/Middleware/MultiTenancyStepMiddleware_Tests.cs new file mode 100644 index 000000000..e1dfad767 --- /dev/null +++ b/aspnet-core/tests/LINGYUN.Abp.WorkflowCore.Tests/LINGYUN/Abp/WorkflowCore/Middleware/MultiTenancyStepMiddleware_Tests.cs @@ -0,0 +1,72 @@ +using Shouldly; +using System; +using System.Threading.Tasks; +using Volo.Abp.MultiTenancy; +using WorkflowCore.Interface; +using WorkflowCore.Models; +using Xunit; + +namespace LINGYUN.Abp.WorkflowCore.Middleware +{ + public class MultiTenancyStepMiddleware_Tests : AbpWorkflowCoreTestBase + { + public static bool IsCompleted = false; + public static readonly Guid TenantId = Guid.NewGuid(); + private readonly IWorkflowController _controller; + public MultiTenancyStepMiddleware_Tests() + { + _controller = GetRequiredService(); + } + + [Fact] + public async Task Should_Be_Resolved_Multi_Tenant_Id_On_Step() + { + await _controller.StartWorkflow( + "MiddlewareWorkflow", + new MiddlewareWorkflowData + { + TenantId = TenantId + }); + + } + } + + public class MiddlewareWorkflowData : IMultiTenant + { + public Guid? TenantId { get; set; } + } + + public class MiddlewareWorkflow : IWorkflow + { + public string Id => "MiddlewareWorkflow"; + + public int Version => 1; + + public void Build(IWorkflowBuilder builder) + { + builder.StartWith((_) => Console.WriteLine("Start Workflow")) + .Then() + .Then((_) => MultiTenancyStepMiddleware_Tests.IsCompleted = true) + .EndWorkflow(); + } + } + + public class MessageStep : StepBodyBase + { + private readonly ICurrentTenant _currentTenant; + + public MessageStep(ICurrentTenant currentTenant) + { + _currentTenant = currentTenant; + } + + public override ExecutionResult Run(IStepExecutionContext context) + { + MultiTenancyStepMiddleware_Tests.TenantId.ShouldBe(_currentTenant.Id.Value); + + Console.WriteLine("Current Tenant Id: {0}", _currentTenant.Id?.ToString() ?? "Null"); + + return ExecutionResult.Next(); + } + } +}