Browse Source

Refactoring RulesEngine integration

pull/259/head
cKey 5 years ago
parent
commit
628f36d6bd
  1. 7
      aspnet-core/LINGYUN.MicroService.All.sln
  2. 9
      aspnet-core/LINGYUN.MicroService.Common.sln
  3. 8
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs
  4. 9
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs
  5. 27
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineResolveOptions.cs
  6. 52
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesResolveContributor.cs
  7. 10
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePthsicalFileResolveOptions.cs
  8. 42
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesContributor.cs
  9. 44
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesResolveContributor.cs
  10. 15
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesContributor.cs
  11. 19
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContext.cs
  12. 15
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolveContributor.cs
  13. 16
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesResolver.cs
  14. 25
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/NullWorkflowRulesContributor.cs
  15. 16
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/IWorkflowRuleStore.cs
  16. 19
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/NullWorkflowRuleStore.cs
  17. 31
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/Persistent/PersistentWorkflowRulesResolveContributor.cs
  18. 36
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs
  19. 30
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContext.cs
  20. 18
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveContributorBase.cs
  21. 18
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolveResult.cs
  22. 67
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/WorkflowRulesResolver.cs
  23. 14
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md

7
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}

9
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}

8
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<RulesEngineContributor>();
});
Configure<AbpRulesEngineOptions>(options =>
Configure<AbpRulesEngineResolveOptions>(options =>
{
// 加入防止空引用
options.Contributors.Add<NullWorkflowRulesContributor>();
options.Contributors.Add<PhysicalFileWorkflowRulesContributor>();
options.WorkflowRulesResolvers.Add(new PersistentWorkflowRulesResolveContributor());
options.WorkflowRulesResolvers.Add(new PhysicalFileWorkflowRulesResolveContributor());
});
}
}

9
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
{
/// <summary>
/// 本地文件路径
/// </summary>
public string PhysicalPath { get; set; }
/// <summary>
/// 是否忽略租户
/// </summary>
public bool IgnoreMultiTenancy { get; set; }
/// <summary>
/// 规则提供者类型
/// </summary>
public ITypeList<IWorkflowRulesContributor> Contributors { get; }
public AbpRulesEngineOptions()
{
Contributors = new TypeList<IWorkflowRulesContributor>();
}
}
}

27
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
{
/// <summary>
/// 合并规则
/// 如果为 true,在上一个提供者解析规则之后继续执行下一个提供者
/// 如果为 false,在上一个提供者解析规则之后立即执行规则
/// 默认:false
/// </summary>
public bool MergingRuels { get; set; }
/// <summary>
/// 规则解析提供者
/// </summary>
[NotNull]
public List<IWorkflowRulesResolveContributor> WorkflowRulesResolvers { get; }
public AbpRulesEngineResolveOptions()
{
MergingRuels = false;
WorkflowRulesResolvers = new List<IWorkflowRulesResolveContributor>();
}
}
}

52
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesContributor.cs → 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<IMemoryCache>();
JsonSerializer = context.ServiceProvider.GetRequiredService<IJsonSerializer>();
FileProvider = BuildFileProvider(context);
}
protected virtual void Initialize(IServiceProvider serviceProvider)
{
FileProvider = BuildFileProvider();
}
protected abstract IFileProvider BuildFileProvider();
protected abstract IFileProvider BuildFileProvider(RulesInitializationContext context);
public async Task<WorkflowRules[]> LoadAsync<T>(CancellationToken cancellationToken = default)
public override async Task ResolveAsync(IWorkflowRulesResolveContext context)
{
if (FileProvider != null)
{
return await GetCachedRulesAsync<T>(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<WorkflowRules[]> GetCachedRulesAsync<T>(CancellationToken cancellationToken = default)
private async Task<WorkflowRules[]> GetCachedRulesAsync(Type type, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var ruleId = GetRuleId<T>();
var ruleId = GetRuleId(type);
return await RulesCache.GetOrCreateAsync(ruleId,
async (entry) =>
{
entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(30));
return await GetFileSystemRulesAsync<T>(cancellationToken);
return await GetFileSystemRulesAsync(type, cancellationToken);
});
}
protected abstract int GetRuleId<T>();
protected abstract int GetRuleId(Type type);
protected abstract string GetRuleName<T>();
protected abstract string GetRuleName(Type type);
protected virtual async Task<WorkflowRules[]> GetFileSystemRulesAsync<T>(CancellationToken cancellationToken = default)
protected virtual async Task<WorkflowRules[]> GetFileSystemRulesAsync(Type type, CancellationToken cancellationToken = default)
{
var ruleId = GetRuleId<T>();
var ruleFile = GetRuleName<T>();
var ruleId = GetRuleId(type);
var ruleFile = GetRuleName(type);
var fileInfo = FileProvider.GetFileInfo(ruleFile);
if (fileInfo != null && fileInfo.Exists)
{

10
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
{
/// <summary>
/// 本地文件路径
/// </summary>
public string PhysicalPath { get; set; }
}
}

42
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesContributor.cs

@ -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<AbpRulesEngineOptions> 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<T>() => _ruleIdGenerator.CreateRuleId(typeof(T), _options.IgnoreMultiTenancy);
protected override string GetRuleName<T>() => $"{_ruleIdGenerator.CreateRuleName(typeof(T), _options.IgnoreMultiTenancy)}.json";
}
}

44
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<RuleIdGenerator>();
_rulesEngineOptions = serviceProvider.GetRequiredService<IOptions<AbpRulesEngineOptions>>().Value;
_fileResolveOptions = serviceProvider.GetRequiredService<IOptions<AbpRulesEnginePthsicalFileResolveOptions>>().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";
}
}

15
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesContributor.cs

@ -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<WorkflowRules[]> LoadAsync<T>(CancellationToken cancellationToken = default);
void Shutdown();
}
}

19
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> WorkflowRules { get; set; }
[NotNull]
Type Type { get; }
bool Handled { get; set; }
}
}

15
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();
}
}

16
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<WorkflowRulesResolveResult> ResolveWorkflowRulesAsync(Type type);
void Shutdown();
}
}

25
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/NullWorkflowRulesContributor.cs

@ -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<WorkflowRules[]> LoadAsync<T>(CancellationToken cancellationToken = default)
{
return Task.FromResult(new WorkflowRules[0]);
}
public void Shutdown()
{
}
}
}

16
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
{
/// <summary>
/// 实现此接口以用于从其他持久化存储中获取规则
/// </summary>
public interface IWorkflowRuleStore
{
Task<IEnumerable<WorkflowRules>> GetRulesAsync(Type inputType, CancellationToken cancellationToken = default);
}
}

19
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<IEnumerable<WorkflowRules>> GetRulesAsync(Type inputType, CancellationToken cancellationToken = default)
{
IEnumerable<WorkflowRules> rules = new WorkflowRules[0];
return Task.FromResult(rules);
}
}
}

31
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<IWorkflowRuleStore>();
}
public override async Task ResolveAsync(IWorkflowRulesResolveContext context)
{
var rules = await Store.GetRulesAsync(context.Type);
context.Handled = true;
context.WorkflowRules = rules;
}
}
}

36
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<IWorkflowRulesContributor> _workflowRulesContributors;
private readonly IWorkflowRulesResolver _workflowRulesResolver;
public RulesEngineContributor(
IServiceProvider serviceProvider,
IOptions<AbpRulesEngineOptions> options)
IWorkflowRulesResolver workflowRulesResolver)
{
_workflowRulesContributors = options.Value
.Contributors
.Select(serviceProvider.GetRequiredService)
.Cast<IWorkflowRulesContributor>()
.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>(T input, object[] @params = null, CancellationToken cancellationToken = default)
{
List<WorkflowRules> workflowRules = new();
var result = await _workflowRulesResolver.ResolveWorkflowRulesAsync(typeof(T));
foreach (var contributor in _workflowRulesContributors)
if (result.WorkflowRules.Any())
{
workflowRules.AddRange(await contributor.LoadAsync<T>(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();
}
}
/// <summary>
/// 重写自行构建规则引擎

30
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> 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;
}
}
}

18
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()
{
}
}
}

18
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> WorkflowRules { get; set; }
public List<string> AppliedResolvers { get; }
public WorkflowRulesResolveResult()
{
AppliedResolvers = new List<string>();
WorkflowRules = new List<WorkflowRules>();
}
}
}

67
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<AbpRulesEngineResolveOptions> 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<WorkflowRulesResolveResult> 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();
}
}
}
}

14
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<AbpRulesEngineOptions>(options =>
Configure<AbpRulesEngineResolveOptions>(options =>
{
// 添加自行实现的规则解析提供者
options.WorkflowRulesResolvers.Add(new FakeWorkflowRulesResolveContributor());
});
Configure<AbpRulesEnginePthsicalFileResolveOptions>(options =>
{
// 指定真实存在的本地文件路径, 否则将不会检索本地规则文件
options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules");

Loading…
Cancel
Save