diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index 4efb91e18..d690d53c1 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -327,6 +327,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.NRules", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.RulesEngine", "modules\rules\LINGYUN.Abp.Rules.RulesEngine\LINGYUN.Abp.Rules.RulesEngine.csproj", "{4D83BDA7-2059-41C7-85AE-FEFAD5CD9498}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.RulesEngine.Tests", "tests\LINGYUN.Abp.Rules.RulesEngine.Tests\LINGYUN.Abp.Rules.RulesEngine.Tests.csproj", "{8EF31071-3521-409D-9740-BBFBFC04C50E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -853,6 +855,10 @@ Global {4D83BDA7-2059-41C7-85AE-FEFAD5CD9498}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D83BDA7-2059-41C7-85AE-FEFAD5CD9498}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D83BDA7-2059-41C7-85AE-FEFAD5CD9498}.Release|Any CPU.Build.0 = Release|Any CPU + {8EF31071-3521-409D-9740-BBFBFC04C50E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EF31071-3521-409D-9740-BBFBFC04C50E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EF31071-3521-409D-9740-BBFBFC04C50E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EF31071-3521-409D-9740-BBFBFC04C50E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1014,6 +1020,7 @@ Global {D60EFB8E-F168-4EF2-8D8F-ED42EB6FB8CF} = {6084D52D-775B-4A39-8CD5-AA2F362B5A61} {34BB9810-2983-4E55-A96A-132D32310145} = {6084D52D-775B-4A39-8CD5-AA2F362B5A61} {4D83BDA7-2059-41C7-85AE-FEFAD5CD9498} = {6084D52D-775B-4A39-8CD5-AA2F362B5A61} + {8EF31071-3521-409D-9740-BBFBFC04C50E} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/LINGYUN.MicroService.Common.sln b/aspnet-core/LINGYUN.MicroService.Common.sln index 871b875b8..e48c2a542 100644 --- a/aspnet-core/LINGYUN.MicroService.Common.sln +++ b/aspnet-core/LINGYUN.MicroService.Common.sln @@ -119,8 +119,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Mvc. EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "localization", "localization", "{E73A0F8B-2B4B-4CED-82A4-1EE5E0B89744}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.Json", "modules\localization\LINGYUN.Abp.Localization.Json\LINGYUN.Abp.Localization.Json.csproj", "{DADD5D6E-F09A-4563-A659-7922E26C40AB}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.Xml", "modules\localization\LINGYUN.Abp.Localization.Xml\LINGYUN.Abp.Localization.Xml.csproj", "{8CC72F4E-F134-4A43-9037-5D4D1F29B68A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Localization.Xml.Tests", "tests\LINGYUN.Abp.Localization.Xml.Tests\LINGYUN.Abp.Localization.Xml.Tests.csproj", "{94FEA59E-3B6D-41A0-9E44-BA5D6477244F}" @@ -156,7 +154,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Tests", "t EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.AspNetCore.TestHost", "tests\LINGYUN.Abp.Dapr.AspNetCore.TestHost\LINGYUN.Abp.Dapr.AspNetCore.TestHost.csproj", "{8968EDAF-9F5C-4786-AF2A-D3928B70C3EC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Dapr.Actors.Tests", "tests\LINGYUN.Abp.Dapr.Actors.Tests\LINGYUN.Abp.Dapr.Actors.Tests.csproj", "{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.Tests", "tests\LINGYUN.Abp.Dapr.Actors.Tests\LINGYUN.Abp.Dapr.Actors.Tests.csproj", "{CF30221B-CA7A-42CD-B91A-B7224AB2F38B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -348,10 +346,6 @@ Global {7F767ACF-754A-4EBC-8936-3C1402B6EF82}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F767ACF-754A-4EBC-8936-3C1402B6EF82}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F767ACF-754A-4EBC-8936-3C1402B6EF82}.Release|Any CPU.Build.0 = Release|Any CPU - {DADD5D6E-F09A-4563-A659-7922E26C40AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DADD5D6E-F09A-4563-A659-7922E26C40AB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DADD5D6E-F09A-4563-A659-7922E26C40AB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DADD5D6E-F09A-4563-A659-7922E26C40AB}.Release|Any CPU.Build.0 = Release|Any CPU {8CC72F4E-F134-4A43-9037-5D4D1F29B68A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8CC72F4E-F134-4A43-9037-5D4D1F29B68A}.Debug|Any CPU.Build.0 = Debug|Any CPU {8CC72F4E-F134-4A43-9037-5D4D1F29B68A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -473,7 +467,6 @@ Global {1B494EA1-28CF-4A61-B0BE-70BBA425C316} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {7F767ACF-754A-4EBC-8936-3C1402B6EF82} = {086BE5BE-8594-4DA7-8819-935FEF76DABD} {E73A0F8B-2B4B-4CED-82A4-1EE5E0B89744} = {02EA4E78-5891-43BC-944F-3E52FEE032E4} - {DADD5D6E-F09A-4563-A659-7922E26C40AB} = {E73A0F8B-2B4B-4CED-82A4-1EE5E0B89744} {8CC72F4E-F134-4A43-9037-5D4D1F29B68A} = {E73A0F8B-2B4B-4CED-82A4-1EE5E0B89744} {94FEA59E-3B6D-41A0-9E44-BA5D6477244F} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} {BA2F4EC9-BC2C-482A-9123-BDACB8B15295} = {B86C21A4-73B7-471E-B73A-B4B905EC9435} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs index 0487d113d..89f980747 100644 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical; +using LINGYUN.Abp.Rules.RulesEngine.Persistent; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Json; using Volo.Abp.Modularity; @@ -19,11 +20,10 @@ namespace LINGYUN.Abp.Rules.RulesEngine options.Contributors.Add(); }); - Configure(options => + Configure(options => { - // 加入防止空引用 - options.Contributors.Add(); - options.Contributors.Add(); + options.WorkflowRulesResolvers.Add(new PersistentWorkflowRulesResolveContributor()); + options.WorkflowRulesResolvers.Add(new PhysicalFileWorkflowRulesResolveContributor()); }); } } diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs index 176358fee..0c57ff987 100644 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs @@ -4,22 +4,13 @@ namespace LINGYUN.Abp.Rules.RulesEngine { public class AbpRulesEngineOptions { - /// - /// 本地文件路径 - /// - public string PhysicalPath { get; set; } /// /// 是否忽略租户 /// public bool IgnoreMultiTenancy { get; set; } - /// - /// 规则提供者类型 - /// - public ITypeList Contributors { get; } public AbpRulesEngineOptions() { - Contributors = new TypeList(); } } } diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineResolveOptions.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineResolveOptions.cs new file mode 100644 index 000000000..681a4449e --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineResolveOptions.cs @@ -0,0 +1,27 @@ +using JetBrains.Annotations; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public class AbpRulesEngineResolveOptions + { + /// + /// 合并规则 + /// 如果为 true,在上一个提供者解析规则之后继续执行下一个提供者 + /// 如果为 false,在上一个提供者解析规则之后立即执行规则 + /// 默认:false + /// + public bool MergingRuels { get; set; } + /// + /// 规则解析提供者 + /// + [NotNull] + public List WorkflowRulesResolvers { get; } + + public AbpRulesEngineResolveOptions() + { + MergingRuels = false; + WorkflowRulesResolvers = new List(); + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesResolveContributor.cs similarity index 55% rename from aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesContributor.cs rename to aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesResolveContributor.cs index b578c31dd..488d14f36 100644 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesContributor.cs +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesResolveContributor.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using RulesEngine.Models; @@ -10,38 +11,43 @@ using Volo.Abp.Json; namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders { - public abstract class FileProviderWorkflowRulesContributor : IWorkflowRulesContributor + public abstract class FileProviderWorkflowRulesResolveContributor : WorkflowRulesResolveContributorBase { - protected IMemoryCache RulesCache { get; } - protected IJsonSerializer JsonSerializer { get; } + protected IMemoryCache RulesCache { get; private set; } + protected IJsonSerializer JsonSerializer { get; private set; } protected IFileProvider FileProvider { get; private set; } - protected FileProviderWorkflowRulesContributor( - IMemoryCache ruleCache, - IJsonSerializer jsonSerializer) + protected FileProviderWorkflowRulesResolveContributor() { - RulesCache = ruleCache; - JsonSerializer = jsonSerializer; } - public void Initialize() + public override void Initialize(RulesInitializationContext context) + { + Initialize(context.ServiceProvider); + + RulesCache = context.ServiceProvider.GetRequiredService(); + JsonSerializer = context.ServiceProvider.GetRequiredService(); + + FileProvider = BuildFileProvider(context); + } + + protected virtual void Initialize(IServiceProvider serviceProvider) { - FileProvider = BuildFileProvider(); } - protected abstract IFileProvider BuildFileProvider(); + protected abstract IFileProvider BuildFileProvider(RulesInitializationContext context); - public async Task LoadAsync(CancellationToken cancellationToken = default) + public override async Task ResolveAsync(IWorkflowRulesResolveContext context) { if (FileProvider != null) { - return await GetCachedRulesAsync(cancellationToken); + context.WorkflowRules = await GetCachedRulesAsync(context.Type); } - return new WorkflowRules[0]; + context.Handled = true; } - public void Shutdown() + public override void Shutdown() { if (FileProvider != null && FileProvider is IDisposable resource) { @@ -49,28 +55,28 @@ namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders } } - private async Task GetCachedRulesAsync(CancellationToken cancellationToken = default) + private async Task GetCachedRulesAsync(Type type, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); - var ruleId = GetRuleId(); + var ruleId = GetRuleId(type); return await RulesCache.GetOrCreateAsync(ruleId, async (entry) => { entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(30)); - return await GetFileSystemRulesAsync(cancellationToken); + return await GetFileSystemRulesAsync(type, cancellationToken); }); } - protected abstract int GetRuleId(); + protected abstract int GetRuleId(Type type); - protected abstract string GetRuleName(); + protected abstract string GetRuleName(Type type); - protected virtual async Task GetFileSystemRulesAsync(CancellationToken cancellationToken = default) + protected virtual async Task GetFileSystemRulesAsync(Type type, CancellationToken cancellationToken = default) { - var ruleId = GetRuleId(); - var ruleFile = GetRuleName(); + var ruleId = GetRuleId(type); + var ruleFile = GetRuleName(type); var fileInfo = FileProvider.GetFileInfo(ruleFile); if (fileInfo != null && fileInfo.Exists) { diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePthsicalFileResolveOptions.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePthsicalFileResolveOptions.cs new file mode 100644 index 000000000..9e87a88ab --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePthsicalFileResolveOptions.cs @@ -0,0 +1,10 @@ +namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical +{ + public class AbpRulesEnginePthsicalFileResolveOptions + { + /// + /// 本地文件路径 + /// + public string PhysicalPath { get; set; } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesContributor.cs deleted file mode 100644 index 1060e2631..000000000 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesContributor.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Options; -using System; -using System.IO; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Json; - -namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical -{ - public class PhysicalFileWorkflowRulesContributor : FileProviderWorkflowRulesContributor, ISingletonDependency - { - private readonly RuleIdGenerator _ruleIdGenerator; - private readonly AbpRulesEngineOptions _options; - public PhysicalFileWorkflowRulesContributor( - IMemoryCache ruleCache, - RuleIdGenerator ruleIdGenerator, - IJsonSerializer jsonSerializer, - IOptions options) - : base(ruleCache, jsonSerializer) - { - _ruleIdGenerator = ruleIdGenerator; - - _options = options.Value; - } - - protected override IFileProvider BuildFileProvider() - { - // 未指定路径不启用 - if (!_options.PhysicalPath.IsNullOrWhiteSpace() && - Directory.Exists(_options.PhysicalPath)) - { - return new PhysicalFileProvider(_options.PhysicalPath); - } - return null; - } - - protected override int GetRuleId() => _ruleIdGenerator.CreateRuleId(typeof(T), _options.IgnoreMultiTenancy); - - protected override string GetRuleName() => $"{_ruleIdGenerator.CreateRuleName(typeof(T), _options.IgnoreMultiTenancy)}.json"; - } -} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesResolveContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesResolveContributor.cs new file mode 100644 index 000000000..b63ad2d86 --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesResolveContributor.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Options; +using System; +using System.IO; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical +{ + public class PhysicalFileWorkflowRulesResolveContributor : FileProviderWorkflowRulesResolveContributor, ISingletonDependency + { + public override string Name => "PhysicalFile"; + + private RuleIdGenerator _ruleIdGenerator; + private AbpRulesEngineOptions _rulesEngineOptions; + private AbpRulesEnginePthsicalFileResolveOptions _fileResolveOptions; + + public PhysicalFileWorkflowRulesResolveContributor() + { + } + + protected override void Initialize(IServiceProvider serviceProvider) + { + _ruleIdGenerator = serviceProvider.GetRequiredService(); + _rulesEngineOptions = serviceProvider.GetRequiredService>().Value; + _fileResolveOptions = serviceProvider.GetRequiredService>().Value; + } + + protected override IFileProvider BuildFileProvider(RulesInitializationContext context) + { + // 未指定路径不启用 + if (!_fileResolveOptions.PhysicalPath.IsNullOrWhiteSpace() && + Directory.Exists(_fileResolveOptions.PhysicalPath)) + { + return new PhysicalFileProvider(_fileResolveOptions.PhysicalPath); + } + return null; + } + + protected override int GetRuleId(Type type) => _ruleIdGenerator.CreateRuleId(type, _rulesEngineOptions.IgnoreMultiTenancy); + + protected override string GetRuleName(Type type) => $"{_ruleIdGenerator.CreateRuleName(type, _rulesEngineOptions.IgnoreMultiTenancy)}.json"; + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesContributor.cs deleted file mode 100644 index b13da479d..000000000 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesContributor.cs +++ /dev/null @@ -1,15 +0,0 @@ -using RulesEngine.Models; -using System.Threading; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.Rules.RulesEngine -{ - public interface IWorkflowRulesContributor - { - void Initialize(); - - Task LoadAsync(CancellationToken cancellationToken = default); - - void Shutdown(); - } -} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContext.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContext.cs new file mode 100644 index 000000000..cc811cbef --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContext.cs @@ -0,0 +1,19 @@ +using JetBrains.Annotations; +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public interface IWorkflowRulesResolveContext : IServiceProviderAccessor + { + [CanBeNull] + IEnumerable WorkflowRules { get; set; } + + [NotNull] + Type Type { get; } + + bool Handled { get; set; } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContributor.cs new file mode 100644 index 000000000..66649ba1d --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContributor.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public interface IWorkflowRulesResolveContributor + { + string Name { get; } + + Task ResolveAsync(IWorkflowRulesResolveContext context); + + void Initialize(RulesInitializationContext context); + + void Shutdown(); + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolver.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolver.cs new file mode 100644 index 000000000..8fdca6fee --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolver.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public interface IWorkflowRulesResolver + { + void Initialize(RulesInitializationContext context); + + [NotNull] + Task ResolveWorkflowRulesAsync(Type type); + + void Shutdown(); + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/NullWorkflowRulesContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/NullWorkflowRulesContributor.cs deleted file mode 100644 index c80dca944..000000000 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/NullWorkflowRulesContributor.cs +++ /dev/null @@ -1,25 +0,0 @@ -using RulesEngine.Models; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace LINGYUN.Abp.Rules.RulesEngine -{ - public class NullWorkflowRulesContributor : IWorkflowRulesContributor, ISingletonDependency - { - public void Initialize() - { - - } - - public Task LoadAsync(CancellationToken cancellationToken = default) - { - return Task.FromResult(new WorkflowRules[0]); - } - - public void Shutdown() - { - - } - } -} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/IWorkflowRuleStore.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/IWorkflowRuleStore.cs new file mode 100644 index 000000000..682069ae7 --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/IWorkflowRuleStore.cs @@ -0,0 +1,16 @@ +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Rules.RulesEngine.Persistent +{ + /// + /// 实现此接口以用于从其他持久化存储中获取规则 + /// + public interface IWorkflowRuleStore + { + Task> GetRulesAsync(Type inputType, CancellationToken cancellationToken = default); + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/NullWorkflowRuleStore.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/NullWorkflowRuleStore.cs new file mode 100644 index 000000000..b51efb69d --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/NullWorkflowRuleStore.cs @@ -0,0 +1,19 @@ +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Rules.RulesEngine.Persistent +{ + [Dependency(TryRegister = true)] + public class NullWorkflowRuleStore : IWorkflowRuleStore, ISingletonDependency + { + public Task> GetRulesAsync(Type inputType, CancellationToken cancellationToken = default) + { + IEnumerable rules = new WorkflowRules[0]; + return Task.FromResult(rules); + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/PersistentWorkflowRulesResolveContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/PersistentWorkflowRulesResolveContributor.cs new file mode 100644 index 000000000..c66763d91 --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/PersistentWorkflowRulesResolveContributor.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Rules.RulesEngine.Persistent +{ + public class PersistentWorkflowRulesResolveContributor : WorkflowRulesResolveContributorBase, ITransientDependency + { + private IWorkflowRuleStore _store; + public override string Name => "Persistent"; + + protected IWorkflowRuleStore Store => _store; + + public PersistentWorkflowRulesResolveContributor() + { + } + + public override void Initialize(RulesInitializationContext context) + { + _store = context.ServiceProvider.GetRequiredService(); + } + + public override async Task ResolveAsync(IWorkflowRulesResolveContext context) + { + var rules = await Store.GetRulesAsync(context.Type); + + context.Handled = true; + context.WorkflowRules = rules; + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs index 72534d926..1c8aaa997 100644 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs @@ -1,9 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using RulesEngine; +using RulesEngine; using RulesEngine.Interfaces; using RulesEngine.Models; -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -16,50 +13,33 @@ namespace LINGYUN.Abp.Rules.RulesEngine public class RulesEngineContributor : RuleContributorBase, ISingletonDependency { private IRulesEngine _ruleEngine; - private readonly IEnumerable _workflowRulesContributors; + private readonly IWorkflowRulesResolver _workflowRulesResolver; public RulesEngineContributor( - IServiceProvider serviceProvider, - IOptions options) + IWorkflowRulesResolver workflowRulesResolver) { - _workflowRulesContributors = options.Value - .Contributors - .Select(serviceProvider.GetRequiredService) - .Cast() - .ToArray(); + _workflowRulesResolver = workflowRulesResolver; } public override void Initialize(RulesInitializationContext context) { _ruleEngine = CreateRulesEngine(); - foreach (var contributor in _workflowRulesContributors) - { - contributor.Initialize(); - } + _workflowRulesResolver.Initialize(context); } public override async Task ExecuteAsync(T input, object[] @params = null, CancellationToken cancellationToken = default) { - List workflowRules = new(); + var result = await _workflowRulesResolver.ResolveWorkflowRulesAsync(typeof(T)); - foreach (var contributor in _workflowRulesContributors) + if (result.WorkflowRules.Any()) { - workflowRules.AddRange(await contributor.LoadAsync(cancellationToken)); - } - - if (workflowRules.Any()) - { - await ExecuteRulesAsync(input, workflowRules.ToArray(), @params); + await ExecuteRulesAsync(input, result.WorkflowRules.ToArray(), @params); } } public override void Shutdown() { - foreach (var contributor in _workflowRulesContributors) - { - contributor.Shutdown(); - } } /// /// 重写自行构建规则引擎 diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContext.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContext.cs new file mode 100644 index 000000000..8c5f1bdaf --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContext.cs @@ -0,0 +1,30 @@ +using JetBrains.Annotations; +using RulesEngine.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public class WorkflowRulesResolveContext : IWorkflowRulesResolveContext + { + public Type Type { get; } + public IServiceProvider ServiceProvider { get; } + public IEnumerable WorkflowRules { get; set; } + public bool Handled { get; set; } + + public bool HasResolved() + { + return Handled && WorkflowRules?.Any() == true; + } + + public WorkflowRulesResolveContext( + [NotNull] Type type, + IServiceProvider serviceProvider) + { + Type = Check.NotNull(type, nameof(type)); + ServiceProvider = serviceProvider; + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContributorBase.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContributorBase.cs new file mode 100644 index 000000000..d670bd342 --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContributorBase.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public abstract class WorkflowRulesResolveContributorBase : IWorkflowRulesResolveContributor + { + public abstract string Name { get; } + + public virtual void Initialize(RulesInitializationContext context) + { + } + public abstract Task ResolveAsync(IWorkflowRulesResolveContext context); + + public virtual void Shutdown() + { + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveResult.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveResult.cs new file mode 100644 index 000000000..fda3c07ea --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveResult.cs @@ -0,0 +1,18 @@ +using RulesEngine.Models; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public class WorkflowRulesResolveResult + { + public List WorkflowRules { get; set; } + + public List AppliedResolvers { get; } + + public WorkflowRulesResolveResult() + { + AppliedResolvers = new List(); + WorkflowRules = new List(); + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolver.cs b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolver.cs new file mode 100644 index 000000000..cb3a5add8 --- /dev/null +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolver.cs @@ -0,0 +1,67 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Rules.RulesEngine +{ + public class WorkflowRulesResolver : IWorkflowRulesResolver, ITransientDependency + { + private readonly IServiceProvider _serviceProvider; + private readonly AbpRulesEngineResolveOptions _options; + + public WorkflowRulesResolver( + IServiceProvider serviceProvider, + IOptions options) + { + _options = options.Value; + _serviceProvider = serviceProvider; + } + + public virtual void Initialize(RulesInitializationContext context) + { + foreach (var workflowRulesResolver in _options.WorkflowRulesResolvers) + { + workflowRulesResolver.Initialize(context); + } + } + + public virtual async Task ResolveWorkflowRulesAsync(Type type) + { + var result = new WorkflowRulesResolveResult(); + + using (var serviceScope = _serviceProvider.CreateScope()) + { + var context = new WorkflowRulesResolveContext(type, serviceScope.ServiceProvider); + + foreach (var workflowRulesResolver in _options.WorkflowRulesResolvers) + { + await workflowRulesResolver.ResolveAsync(context); + + result.AppliedResolvers.Add(workflowRulesResolver.Name); + + if (context.HasResolved()) + { + result.WorkflowRules.AddRange(context.WorkflowRules); + + if (!_options.MergingRuels) + { + break; + } + } + } + } + + return result; + } + + public virtual void Shutdown() + { + foreach (var workflowRulesResolver in _options.WorkflowRulesResolvers) + { + workflowRulesResolver.Shutdown(); + } + } + } +} diff --git a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md index 603c4787b..fcfc5862a 100644 --- a/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md +++ b/aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md @@ -4,12 +4,16 @@ 集成微软规则引擎的实现 -默认实现一个本地文件系统规则提供者,根据用户配置的 **PhysicalPath** 路径检索规则文件 +默认实现一个本地文件系统规则提供者,根据用户配置的 **AbpRulesEnginePthsicalFileResolveOptions.PhysicalPath** 路径检索规则文件 文件名如下: PhysicalPath/CurrentTenant.Id[如果存在]/验证规则实体类型名称[typeof(Input).Name].json +自定义的规则提供者需要实现 **IWorkflowRulesResolveContributor** 接口,可能不需要实现初始化与释放资源,因此提供了一个抽象的 **WorkflowRulesResolveContributorBase** + +并添加到 **AbpRulesEngineResolveOptions.WorkflowRulesResolvers** 中 + ### 基础模块 ### 高阶模块 @@ -31,7 +35,13 @@ PhysicalPath/CurrentTenant.Id[如果存在]/验证规则实体类型名称[typeo { public override void ConfigureServices(ServiceConfigurationContext context) { - Configure(options => + Configure(options => + { + // 添加自行实现的规则解析提供者 + options.WorkflowRulesResolvers.Add(new FakeWorkflowRulesResolveContributor()); + }); + + Configure(options => { // 指定真实存在的本地文件路径, 否则将不会检索本地规则文件 options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules");