Browse Source

upgrade RulesEngine

pull/294/head
cKey 4 years ago
parent
commit
47a3add772
  1. 2
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN.Abp.Rules.RulesEngine.csproj
  2. 40
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs
  3. 209
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesResolveContributor.cs
  4. 20
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePhysicalFileResolveOptions.cs
  5. 88
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesResolveContributor.cs
  6. 163
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs
  7. 108
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md
  8. 36
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RulesInitializationContext.cs
  9. 42
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineTestModule.cs
  10. 235
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestInputRuleTests.cs

2
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN.Abp.Rules.RulesEngine.csproj

@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RulesEngine" Version="3.1.0" /> <PackageReference Include="RulesEngine" Version="3.3.0" />
<PackageReference Include="Volo.Abp.Json" Version="4.4.0" /> <PackageReference Include="Volo.Abp.Json" Version="4.4.0" />
</ItemGroup> </ItemGroup>

40
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs

@ -1,16 +1,24 @@
using Volo.Abp.Collections; using RulesEngine.Models;
namespace LINGYUN.Abp.Rules.RulesEngine namespace LINGYUN.Abp.Rules.RulesEngine
{ {
public class AbpRulesEngineOptions public class AbpRulesEngineOptions
{ {
/// <summary> /// <summary>
/// 是否忽略租户 /// 是否忽略租户
/// </summary> /// </summary>
public bool IgnoreMultiTenancy { get; set; } public bool IgnoreMultiTenancy { get; set; }
/// <summary>
public AbpRulesEngineOptions() /// 规则引擎可配置
{ /// </summary>
} public ReSettings Settings { get; set; }
}
} public AbpRulesEngineOptions()
{
Settings = new ReSettings
{
NestedRuleExecutionMode = NestedRuleExecutionMode.Performance
};
}
}
}

209
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesResolveContributor.cs

@ -1,105 +1,104 @@
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using RulesEngine.Models; using RulesEngine.Models;
using System; using System;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Json; using Volo.Abp.Json;
namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders
{ {
public abstract class FileProviderWorkflowRulesResolveContributor : WorkflowRulesResolveContributorBase public abstract class FileProviderWorkflowRulesResolveContributor : WorkflowRulesResolveContributorBase
{ {
protected IMemoryCache RulesCache { get; private set; } protected IMemoryCache RulesCache { get; private set; }
protected IJsonSerializer JsonSerializer { get; private set; } protected IJsonSerializer JsonSerializer { get; private set; }
protected IFileProvider FileProvider { get; private set; } protected IFileProvider FileProvider { get; private set; }
protected FileProviderWorkflowRulesResolveContributor()
protected FileProviderWorkflowRulesResolveContributor() {
{ }
}
public override void Initialize(RulesInitializationContext context)
public override void Initialize(RulesInitializationContext context) {
{ Initialize(context.ServiceProvider);
Initialize(context.ServiceProvider);
RulesCache = context.GetRequiredService<IMemoryCache>();
RulesCache = context.ServiceProvider.GetRequiredService<IMemoryCache>(); JsonSerializer = context.GetRequiredService<IJsonSerializer>();
JsonSerializer = context.ServiceProvider.GetRequiredService<IJsonSerializer>();
FileProvider = BuildFileProvider(context);
FileProvider = BuildFileProvider(context); }
}
protected virtual void Initialize(IServiceProvider serviceProvider)
protected virtual void Initialize(IServiceProvider serviceProvider) {
{ }
}
protected abstract IFileProvider BuildFileProvider(RulesInitializationContext context);
protected abstract IFileProvider BuildFileProvider(RulesInitializationContext context);
public override async Task ResolveAsync(IWorkflowRulesResolveContext context)
public override async Task ResolveAsync(IWorkflowRulesResolveContext context) {
{ if (FileProvider != null)
if (FileProvider != null) {
{ context.WorkflowRules = await GetCachedRulesAsync(context.Type);
context.WorkflowRules = await GetCachedRulesAsync(context.Type); }
} context.Handled = true;
context.Handled = true; }
}
public override void Shutdown()
public override void Shutdown() {
{ if (FileProvider != null && FileProvider is IDisposable resource)
if (FileProvider != null && FileProvider is IDisposable resource) {
{ resource.Dispose();
resource.Dispose(); }
} }
}
private async Task<WorkflowRules[]> GetCachedRulesAsync(Type type, CancellationToken cancellationToken = default)
private async Task<WorkflowRules[]> GetCachedRulesAsync(Type type, CancellationToken cancellationToken = default) {
{ cancellationToken.ThrowIfCancellationRequested();
cancellationToken.ThrowIfCancellationRequested();
var ruleId = GetRuleId(type);
var ruleId = GetRuleId(type);
return await RulesCache.GetOrCreateAsync(ruleId,
return await RulesCache.GetOrCreateAsync(ruleId, async (entry) =>
async (entry) => {
{ entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(30));
entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(30));
return await GetFileSystemRulesAsync(type, cancellationToken);
return await GetFileSystemRulesAsync(type, cancellationToken); });
}); }
} protected abstract int GetRuleId(Type type);
protected abstract int GetRuleId(Type type);
protected abstract string GetRuleName(Type type);
protected abstract string GetRuleName(Type type);
protected virtual async Task<WorkflowRules[]> GetFileSystemRulesAsync(Type type, CancellationToken cancellationToken = default)
protected virtual async Task<WorkflowRules[]> GetFileSystemRulesAsync(Type type, CancellationToken cancellationToken = default) {
{ var ruleId = GetRuleId(type);
var ruleId = GetRuleId(type); var ruleFile = GetRuleName(type);
var ruleFile = GetRuleName(type); var fileInfo = FileProvider.GetFileInfo(ruleFile);
var fileInfo = FileProvider.GetFileInfo(ruleFile); if (fileInfo != null && fileInfo.Exists)
if (fileInfo != null && fileInfo.Exists) {
{ // 规则文件监控
// 规则文件监控 ChangeToken.OnChange(
// TODO: 删除模块的规则缓存还需要删除RulesEngine中rulesCache已编译的规则缓存 () => FileProvider.Watch(ruleFile),
ChangeToken.OnChange( (int ruleId) =>
() => FileProvider.Watch(ruleFile), {
(int ruleId) => // 清除规则缓存
{ RulesCache.Remove(ruleId);
RulesCache.Remove(ruleId); }, ruleId);
}, ruleId);
// 打开文本流
// 打开文本流 using (var stream = fileInfo.CreateReadStream())
using (var stream = fileInfo.CreateReadStream()) {
{ var result = new byte[stream.Length];
var result = new byte[stream.Length]; await stream.ReadAsync(result, 0, (int)stream.Length);
await stream.ReadAsync(result, 0, (int)stream.Length); var ruleDsl = Encoding.UTF8.GetString(result);
var ruleDsl = Encoding.UTF8.GetString(result); // 解析
// 解析 return JsonSerializer.Deserialize<WorkflowRules[]>(ruleDsl);
return JsonSerializer.Deserialize<WorkflowRules[]>(ruleDsl); }
} }
} return new WorkflowRules[0];
return new WorkflowRules[0]; }
} }
} }
}

20
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePthsicalFileResolveOptions.cs → aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/AbpRulesEnginePhysicalFileResolveOptions.cs

@ -1,10 +1,10 @@
namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical
{ {
public class AbpRulesEnginePthsicalFileResolveOptions public class AbpRulesEnginePhysicalFileResolveOptions
{ {
/// <summary> /// <summary>
/// 本地文件路径 /// 本地文件路径
/// </summary> /// </summary>
public string PhysicalPath { get; set; } public string PhysicalPath { get; set; }
} }
} }

88
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesResolveContributor.cs

@ -1,44 +1,44 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System; using System;
using System.IO; using System.IO;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical namespace LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical
{ {
public class PhysicalFileWorkflowRulesResolveContributor : FileProviderWorkflowRulesResolveContributor, ISingletonDependency public class PhysicalFileWorkflowRulesResolveContributor : FileProviderWorkflowRulesResolveContributor, ISingletonDependency
{ {
public override string Name => "PhysicalFile"; public override string Name => "PhysicalFile";
private RuleIdGenerator _ruleIdGenerator; private RuleIdGenerator _ruleIdGenerator;
private AbpRulesEngineOptions _rulesEngineOptions; private AbpRulesEngineOptions _rulesEngineOptions;
private AbpRulesEnginePthsicalFileResolveOptions _fileResolveOptions; private AbpRulesEnginePhysicalFileResolveOptions _fileResolveOptions;
public PhysicalFileWorkflowRulesResolveContributor() public PhysicalFileWorkflowRulesResolveContributor()
{ {
} }
protected override void Initialize(IServiceProvider serviceProvider) protected override void Initialize(IServiceProvider serviceProvider)
{ {
_ruleIdGenerator = serviceProvider.GetRequiredService<RuleIdGenerator>(); _ruleIdGenerator = serviceProvider.GetRequiredService<RuleIdGenerator>();
_rulesEngineOptions = serviceProvider.GetRequiredService<IOptions<AbpRulesEngineOptions>>().Value; _rulesEngineOptions = serviceProvider.GetRequiredService<IOptions<AbpRulesEngineOptions>>().Value;
_fileResolveOptions = serviceProvider.GetRequiredService<IOptions<AbpRulesEnginePthsicalFileResolveOptions>>().Value; _fileResolveOptions = serviceProvider.GetRequiredService<IOptions<AbpRulesEnginePhysicalFileResolveOptions>>().Value;
} }
protected override IFileProvider BuildFileProvider(RulesInitializationContext context) protected override IFileProvider BuildFileProvider(RulesInitializationContext context)
{ {
// 未指定路径不启用 // 未指定路径不启用
if (!_fileResolveOptions.PhysicalPath.IsNullOrWhiteSpace() && if (!_fileResolveOptions.PhysicalPath.IsNullOrWhiteSpace() &&
Directory.Exists(_fileResolveOptions.PhysicalPath)) Directory.Exists(_fileResolveOptions.PhysicalPath))
{ {
return new PhysicalFileProvider(_fileResolveOptions.PhysicalPath); return new PhysicalFileProvider(_fileResolveOptions.PhysicalPath);
} }
return null; return null;
} }
protected override int GetRuleId(Type type) => _ruleIdGenerator.CreateRuleId(type, _rulesEngineOptions.IgnoreMultiTenancy); protected override int GetRuleId(Type type) => _ruleIdGenerator.CreateRuleId(type, _rulesEngineOptions.IgnoreMultiTenancy);
protected override string GetRuleName(Type type) => $"{_ruleIdGenerator.CreateRuleName(type, _rulesEngineOptions.IgnoreMultiTenancy)}.json"; protected override string GetRuleName(Type type) => $"{_ruleIdGenerator.CreateRuleName(type, _rulesEngineOptions.IgnoreMultiTenancy)}.json";
} }
} }

163
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs

@ -1,82 +1,81 @@
using RulesEngine; using Microsoft.Extensions.Options;
using RulesEngine.Interfaces; using RulesEngine;
using RulesEngine.Models; using RulesEngine.Interfaces;
using System.Collections.Generic; using RulesEngine.Models;
using System.Linq; using System.Collections.Generic;
using System.Threading; using System.Linq;
using System.Threading.Tasks; using System.Threading;
using Volo.Abp.DependencyInjection; using System.Threading.Tasks;
using Engine = RulesEngine.RulesEngine; using Volo.Abp.DependencyInjection;
using Engine = RulesEngine.RulesEngine;
namespace LINGYUN.Abp.Rules.RulesEngine
{ namespace LINGYUN.Abp.Rules.RulesEngine
public class RulesEngineContributor : RuleContributorBase, ISingletonDependency {
{ public class RulesEngineContributor : RuleContributorBase, ISingletonDependency
private IRulesEngine _ruleEngine; {
private readonly IWorkflowRulesResolver _workflowRulesResolver; private IRulesEngine _ruleEngine;
private readonly AbpRulesEngineOptions _options;
public RulesEngineContributor( private readonly IWorkflowRulesResolver _workflowRulesResolver;
IWorkflowRulesResolver workflowRulesResolver)
{ public RulesEngineContributor(
_workflowRulesResolver = workflowRulesResolver; IWorkflowRulesResolver workflowRulesResolver,
} IOptions<AbpRulesEngineOptions> options)
{
public override void Initialize(RulesInitializationContext context) _options = options.Value;
{ _workflowRulesResolver = workflowRulesResolver;
_ruleEngine = CreateRulesEngine(); }
_workflowRulesResolver.Initialize(context); public override void Initialize(RulesInitializationContext context)
} {
_ruleEngine = CreateRulesEngine();
public override async Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default) _workflowRulesResolver.Initialize(context);
{ }
var result = await _workflowRulesResolver.ResolveWorkflowRulesAsync(typeof(T));
public override async Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default)
if (result.WorkflowRules.Any()) {
{ var result = await _workflowRulesResolver.ResolveWorkflowRulesAsync(typeof(T));
await ExecuteRulesAsync(input, result.WorkflowRules.ToArray(), @params);
} if (result.WorkflowRules.Any())
} {
await ExecuteRulesAsync(input, result.WorkflowRules.ToArray(), @params);
public override void Shutdown() }
{ }
}
/// <summary> public override void Shutdown()
/// 重写自行构建规则引擎 {
/// </summary> }
/// <returns></returns> /// <summary>
protected virtual Engine CreateRulesEngine() /// 重写自行构建规则引擎
{ /// </summary>
var reSetting = new ReSettings /// <returns></returns>
{ protected virtual Engine CreateRulesEngine()
NestedRuleExecutionMode = NestedRuleExecutionMode.Performance {
}; return new Engine(Logger, _options.Settings);
}
return new Engine(Logger, reSetting);
} protected virtual async Task ExecuteRulesAsync<T>(T input, WorkflowRules[] workflowRules, object[] @params = null)
{
protected virtual async Task ExecuteRulesAsync<T>(T input, WorkflowRules[] workflowRules, object[] @params = null) // TODO: 性能缺陷 规则文件每一次调用都会重复编译
{ _ruleEngine.AddOrUpdateWorkflow(workflowRules);
_ruleEngine.AddWorkflow(workflowRules);
// 传入参与验证的实体参数
// 传入参与验证的实体参数 var inputs = new List<object>()
var inputs = new List<object>() {
{ input
input };
}; if (@params != null && @params.Any())
if (@params != null && @params.Any()) {
{ inputs.AddRange(@params);
inputs.AddRange(@params); }
} // 其他参数以此类推
// 其他参数以此类推
foreach (var workflowRule in workflowRules)
foreach (var workflowRule in workflowRules) {
{ // 执行当前的规则
// 执行当前的规则 var ruleResult = await _ruleEngine.ExecuteAllRulesAsync(workflowRule.WorkflowName, inputs.ToArray());
var ruleResult = await _ruleEngine.ExecuteAllRulesAsync(workflowRule.WorkflowName, inputs.ToArray()); // 用户自定义扩展方法,规则校验错误抛出异常
// 用户自定义扩展方法,规则校验错误抛出异常 ruleResult.ThrowOfFaildExecute();
ruleResult.ThrowOfFaildExecute(); }
} }
} }
} }
}

108
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md

@ -1,54 +1,54 @@
# LINGYUN.Abp.Rules.RulesEngine # LINGYUN.Abp.Rules.RulesEngine
## 模块说明 ## 模块说明
集成微软规则引擎的实现 集成微软规则引擎的实现
默认实现一个本地文件系统规则提供者,根据用户配置的 **AbpRulesEnginePthsicalFileResolveOptions.PhysicalPath** 路径检索规则文件 默认实现一个本地文件系统规则提供者,根据用户配置的 **AbpRulesEnginePthsicalFileResolveOptions.PhysicalPath** 路径检索规则文件
文件名如下: 文件名如下:
PhysicalPath/CurrentTenant.Id[如果存在]/验证规则实体类型名称[typeof(Input).Name].json PhysicalPath/CurrentTenant.Id[如果存在]/验证规则实体类型名称[typeof(Input).Name].json
自定义的规则提供者需要实现 **IWorkflowRulesResolveContributor** 接口,可能不需要实现初始化与释放资源,因此提供了一个抽象的 **WorkflowRulesResolveContributorBase** 自定义的规则提供者需要实现 **IWorkflowRulesResolveContributor** 接口,可能不需要实现初始化与释放资源,因此提供了一个抽象的 **WorkflowRulesResolveContributorBase**
并添加到 **AbpRulesEngineResolveOptions.WorkflowRulesResolvers** 并添加到 **AbpRulesEngineResolveOptions.WorkflowRulesResolvers**
### 基础模块 ### 基础模块
### 高阶模块 ### 高阶模块
### 权限定义 ### 权限定义
### 功能定义 ### 功能定义
### 配置定义 ### 配置定义
### 如何使用 ### 如何使用
```csharp ```csharp
[DependsOn( [DependsOn(
typeof(AbpRulesEngineModule))] typeof(AbpRulesEngineModule))]
public class YouProjectModule : AbpModule public class YouProjectModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
Configure<AbpRulesEngineResolveOptions>(options => Configure<AbpRulesEngineResolveOptions>(options =>
{ {
// 添加自行实现的规则解析提供者 // 添加自行实现的规则解析提供者
options.WorkflowRulesResolvers.Add(new FakeWorkflowRulesResolveContributor()); options.WorkflowRulesResolvers.Add(new FakeWorkflowRulesResolveContributor());
}); });
Configure<AbpRulesEnginePthsicalFileResolveOptions>(options => Configure<AbpRulesEnginePhysicalFileResolveOptions>(options =>
{ {
// 指定真实存在的本地文件路径, 否则将不会检索本地规则文件 // 指定真实存在的本地文件路径, 否则将不会检索本地规则文件
options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules"); options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules");
}); });
} }
} }
``` ```
### 更新日志 ### 更新日志

36
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RulesInitializationContext.cs

@ -1,16 +1,20 @@
using System; using System;
using Volo.Abp.Data;
namespace LINGYUN.Abp.Rules
{ namespace LINGYUN.Abp.Rules
public class RulesInitializationContext : IServiceProvider {
{ public class RulesInitializationContext : IServiceProvider, IHasExtraProperties
public IServiceProvider ServiceProvider { get; } {
public IServiceProvider ServiceProvider { get; }
internal RulesInitializationContext(IServiceProvider serviceProvider)
{ public ExtraPropertyDictionary ExtraProperties { get; }
ServiceProvider = serviceProvider;
} internal RulesInitializationContext(IServiceProvider serviceProvider)
{
public object GetService(Type serviceType) => ServiceProvider.GetService(serviceType); ServiceProvider = serviceProvider;
} ExtraProperties = new ExtraPropertyDictionary();
} }
public object GetService(Type serviceType) => ServiceProvider.GetService(serviceType);
}
}

42
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineTestModule.cs

@ -1,21 +1,21 @@
using LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical; using LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical;
using LINGYUN.Abp.Tests; using LINGYUN.Abp.Tests;
using System.IO; using System.IO;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Rules.RulesEngine namespace LINGYUN.Abp.Rules.RulesEngine
{ {
[DependsOn( [DependsOn(
typeof(AbpRulesEngineModule), typeof(AbpRulesEngineModule),
typeof(AbpTestsBaseModule))] typeof(AbpTestsBaseModule))]
public class AbpRulesEngineTestModule : AbpModule public class AbpRulesEngineTestModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
Configure<AbpRulesEnginePthsicalFileResolveOptions>(options => Configure<AbpRulesEnginePhysicalFileResolveOptions>(options =>
{ {
options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules"); options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules");
}); });
} }
} }
} }

235
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestInputRuleTests.cs

@ -1,117 +1,118 @@
using Shouldly; using Shouldly;
using System.Threading.Tasks; using System;
using Volo.Abp.Validation; using System.Threading.Tasks;
using Xunit; using Volo.Abp.Validation;
using Xunit;
namespace LINGYUN.Abp.Rules.RulesEngine
{ namespace LINGYUN.Abp.Rules.RulesEngine
public class TestInputRuleTests : AbpRulesEngineTestBase {
{ public class TestInputRuleTests : AbpRulesEngineTestBase
private readonly IRuleProvider _ruleProvider; {
private readonly IRuleProvider _ruleProvider;
public TestInputRuleTests()
{ public TestInputRuleTests()
_ruleProvider = GetRequiredService<IRuleProvider>(); {
} _ruleProvider = GetRequiredService<IRuleProvider>();
}
[Fact]
public async Task Input_Required_Should_Required() [Fact]
{ public async Task Input_Required_Should_Required()
var input = new TestInput {
{ var input = new TestInput
Integer1 = 101, {
Integer2 = 99, Integer1 = 101,
Length = "123456" Integer2 = 99,
} Length = "123456"
; }
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () => ;
{ var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
await _ruleProvider.ExecuteAsync(input); {
}); await _ruleProvider.ExecuteAsync(input);
});
exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors.Count.ShouldBe(1); exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Required 必须输入!"); exception.ValidationErrors.Count.ShouldBe(1);
} exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Required 必须输入!");
}
[Fact]
public async Task Input_Integer1_Should_MustBeGreaterThan100() [Fact]
{ public async Task Input_Integer1_Should_MustBeGreaterThan100()
var input = new TestInput {
{ var input = new TestInput
Required = "123456", {
Integer1 = 99, Required = "123456",
Integer2 = 99, Integer1 = 99,
Length = "123456" Integer2 = 99,
}; Length = "123456"
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () => };
{ var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
await _ruleProvider.ExecuteAsync(input); {
}); await _ruleProvider.ExecuteAsync(input);
});
exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors.Count.ShouldBe(1); exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Integer1 必须大于100!"); exception.ValidationErrors.Count.ShouldBe(1);
} exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Integer1 必须大于100!");
}
[Fact]
public async Task Input_Integer2_Should_MustBeLessThan100() [Fact]
{ public async Task Input_Integer2_Should_MustBeLessThan100()
var input = new TestInput {
{ var input = new TestInput
Required = "123456", {
Integer1 = 101, Required = "123456",
Integer2 = 100, Integer1 = 101,
Length = "123456" Integer2 = 100,
}; Length = "123456"
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () => };
{ var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
await _ruleProvider.ExecuteAsync(input); {
}); await _ruleProvider.ExecuteAsync(input);
});
exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors.Count.ShouldBe(1); exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Integer2 必须小于100!"); exception.ValidationErrors.Count.ShouldBe(1);
} exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Integer2 必须小于100!");
}
[Fact]
public async Task Input_Sum_Integer1_And_Integer2_Should_MustBeGreaterThan150() [Fact]
{ public async Task Input_Sum_Integer1_And_Integer2_Should_MustBeGreaterThan150()
var input = new TestInput {
{ var input = new TestInput
Required = "1", {
Integer1 = 101, Required = "1",
Integer2 = 48, Integer1 = 101,
Length = "123456" Integer2 = 48,
}; Length = "123456"
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () => };
{ var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
await _ruleProvider.ExecuteAsync(input); {
}); await _ruleProvider.ExecuteAsync(input);
});
exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors.Count.ShouldBe(1); exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Integer1 与 Integer2 之和 必须大于150!"); exception.ValidationErrors.Count.ShouldBe(1);
} exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Integer1 与 Integer2 之和 必须大于150!");
}
[Fact]
public async Task Input_Required_Length_Should_MustBeGreaterThan5() [Fact]
{ public async Task Input_Required_Length_Should_MustBeGreaterThan5()
var input = new TestInput {
{ var input = new TestInput
Required = "1", {
Integer1 = 101, Required = "1",
Integer2 = 50, Integer1 = 101,
Length = "12345" Integer2 = 50,
}; Length = "12345"
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () => };
{ var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
await _ruleProvider.ExecuteAsync(input); {
}); await _ruleProvider.ExecuteAsync(input);
});
exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors.Count.ShouldBe(1); exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Length 长度必须大于5!"); exception.ValidationErrors.Count.ShouldBe(1);
} exception.ValidationErrors[0].ErrorMessage.ShouldBe("字段 Length 长度必须大于5!");
} }
} }
}

Loading…
Cancel
Save