23 changed files with 391 additions and 156 deletions
@ -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>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical |
|||
{ |
|||
public class AbpRulesEnginePthsicalFileResolveOptions |
|||
{ |
|||
/// <summary>
|
|||
/// 本地文件路径
|
|||
/// </summary>
|
|||
public string PhysicalPath { get; set; } |
|||
} |
|||
} |
|||
@ -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"; |
|||
} |
|||
} |
|||
@ -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"; |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -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>(); |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue