Browse Source

add rules sopport

pull/252/head
cKey 5 years ago
parent
commit
cc1ee93c88
  1. 31
      aspnet-core/LINGYUN.MicroService.Common.sln
  2. 27
      aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors.IdentityModel.Web/Properties/launchSettings.json
  3. 18
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi.Client/LINGYUN.Abp.OssManagement.HttpApi.Client.csproj
  4. 20
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi.Client/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiClientModule.cs
  5. 162
      aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi.Client/LINGYUN/Abp/OssManagement/LINGYUNApiDescriptionFinder.cs
  6. 18
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN.Abp.Rules.NRules.csproj
  7. 22
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/AbpNRulesModule.cs
  8. 14
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/DefaultActionInterceptor.cs
  9. 21
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/DefaultDependencyResolver.cs
  10. 39
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/NRulesContributor.cs
  11. 19
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN.Abp.Rules.RulesEngine.csproj
  12. 30
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs
  13. 25
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineOptions.cs
  14. 99
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesContributor.cs
  15. 42
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/Physical/PhysicalFileWorkflowRulesContributor.cs
  16. 15
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/IWorkflowRulesContributor.cs
  17. 25
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/NullWorkflowRulesContributor.cs
  18. 94
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/RulesEngineContributor.cs
  19. 44
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/README.md
  20. 76
      aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/RulesEngine/ListofRuleResultTreeExtension.cs
  21. 14
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN.Abp.Rules.csproj
  22. 26
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/AbpRulesModule.cs
  23. 14
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/AbpRulesOptions.cs
  24. 14
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/IRuleContributor.cs
  25. 10
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/IRuleProvider.cs
  26. 31
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RuleContributorBase.cs
  27. 45
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RuleIdGenerator.cs
  28. 65
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RuleProvider.cs
  29. 16
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RulesInitializationContext.cs
  30. 54
      aspnet-core/modules/rules/LINGYUN.Abp.Rules/README.md
  31. 27
      aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests.csproj
  32. 13
      aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiClientTestBase.cs
  33. 24
      aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiClientTestModule.cs
  34. 35
      aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/OssObjectAppServiceTests.cs
  35. 35
      aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/StaticFilesAppServiceTests.cs
  36. 36
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj
  37. 8
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineTestBase.cs
  38. 23
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineTestModule.cs
  39. 24
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestInput.cs
  40. 117
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestInputRuleTests.cs
  41. 38
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestMultipleRuleInputTests.cs
  42. 42
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/Rules/TestInput.json
  43. 58
      aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/Rules/TestMultipleRuleInput.json

31
aspnet-core/LINGYUN.MicroService.Common.sln

@ -142,6 +142,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Actors.Asp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dapr.Client", "modules\dapr\LINGYUN.Abp.Dapr.Client\LINGYUN.Abp.Dapr.Client.csproj", "{879791A3-BD69-42E4-A3BC-9878EFAADDD1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rules", "rules", "{C8891F1A-E6E5-448A-B527-EBFA44D20808}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules", "modules\rules\LINGYUN.Abp.Rules\LINGYUN.Abp.Rules.csproj", "{5133D83C-9B23-491C-8780-3F9BBDBD0351}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.NRules", "modules\rules\LINGYUN.Abp.Rules.NRules\LINGYUN.Abp.Rules.NRules.csproj", "{B8E5026B-188F-422F-A1EA-502C4A394585}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.RulesEngine", "modules\rules\LINGYUN.Abp.Rules.RulesEngine\LINGYUN.Abp.Rules.RulesEngine.csproj", "{E861BE01-689D-4637-A5DC-E78E234F83FB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Rules.RulesEngine.Tests", "tests\LINGYUN.Abp.Rules.RulesEngine.Tests\LINGYUN.Abp.Rules.RulesEngine.Tests.csproj", "{CF253F0A-3A45-40EE-875F-0E57C8968C48}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -368,6 +378,22 @@ Global
{879791A3-BD69-42E4-A3BC-9878EFAADDD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{879791A3-BD69-42E4-A3BC-9878EFAADDD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{879791A3-BD69-42E4-A3BC-9878EFAADDD1}.Release|Any CPU.Build.0 = Release|Any CPU
{5133D83C-9B23-491C-8780-3F9BBDBD0351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5133D83C-9B23-491C-8780-3F9BBDBD0351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5133D83C-9B23-491C-8780-3F9BBDBD0351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5133D83C-9B23-491C-8780-3F9BBDBD0351}.Release|Any CPU.Build.0 = Release|Any CPU
{B8E5026B-188F-422F-A1EA-502C4A394585}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8E5026B-188F-422F-A1EA-502C4A394585}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8E5026B-188F-422F-A1EA-502C4A394585}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8E5026B-188F-422F-A1EA-502C4A394585}.Release|Any CPU.Build.0 = Release|Any CPU
{E861BE01-689D-4637-A5DC-E78E234F83FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E861BE01-689D-4637-A5DC-E78E234F83FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E861BE01-689D-4637-A5DC-E78E234F83FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E861BE01-689D-4637-A5DC-E78E234F83FB}.Release|Any CPU.Build.0 = Release|Any CPU
{CF253F0A-3A45-40EE-875F-0E57C8968C48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF253F0A-3A45-40EE-875F-0E57C8968C48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF253F0A-3A45-40EE-875F-0E57C8968C48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF253F0A-3A45-40EE-875F-0E57C8968C48}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -439,6 +465,11 @@ Global
{E263A9ED-D5DB-4495-A0C7-6268ED92EB92} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{E74FF671-6E5E-430C-9211-ED910634DDBE} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{879791A3-BD69-42E4-A3BC-9878EFAADDD1} = {7FDFB22F-1BFF-4E05-9427-78B7A8461D50}
{C8891F1A-E6E5-448A-B527-EBFA44D20808} = {02EA4E78-5891-43BC-944F-3E52FEE032E4}
{5133D83C-9B23-491C-8780-3F9BBDBD0351} = {C8891F1A-E6E5-448A-B527-EBFA44D20808}
{B8E5026B-188F-422F-A1EA-502C4A394585} = {C8891F1A-E6E5-448A-B527-EBFA44D20808}
{E861BE01-689D-4637-A5DC-E78E234F83FB} = {C8891F1A-E6E5-448A-B527-EBFA44D20808}
{CF253F0A-3A45-40EE-875F-0E57C8968C48} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8}

27
aspnet-core/modules/dapr/LINGYUN.Abp.Dapr.Actors.IdentityModel.Web/Properties/launchSettings.json

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:25348/",
"sslPort": 44377
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"LINGYUN.Abp.Dapr.Actors.IdentityModel.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

18
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi.Client/LINGYUN.Abp.OssManagement.HttpApi.Client.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Http.Client" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.OssManagement.Application.Contracts\LINGYUN.Abp.OssManagement.Application.Contracts.csproj" />
</ItemGroup>
</Project>

20
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi.Client/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiClientModule.cs

@ -0,0 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpOssManagementApplicationContractsModule),
typeof(AbpHttpClientModule))]
public class AbpOssManagementHttpApiClientModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(
typeof(AbpOssManagementApplicationContractsModule).Assembly,
OssManagementRemoteServiceConsts.RemoteServiceName
);
}
}
}

162
aspnet-core/modules/oss-management/LINGYUN.Abp.OssManagement.HttpApi.Client/LINGYUN/Abp/OssManagement/LINGYUNApiDescriptionFinder.cs

@ -0,0 +1,162 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.DynamicProxying;
using Volo.Abp.Http.Modeling;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Tracing;
namespace LINGYUN.Abp.OssManagement
{
public class LINGYUNApiDescriptionFinder : IApiDescriptionFinder, ITransientDependency
{
public ICancellationTokenProvider CancellationTokenProvider { get; set; }
protected IApiDescriptionCache Cache { get; }
protected AbpCorrelationIdOptions AbpCorrelationIdOptions { get; }
protected ICorrelationIdProvider CorrelationIdProvider { get; }
protected ICurrentTenant CurrentTenant { get; }
public LINGYUNApiDescriptionFinder(
IApiDescriptionCache cache,
IOptions<AbpCorrelationIdOptions> abpCorrelationIdOptions,
ICorrelationIdProvider correlationIdProvider,
ICurrentTenant currentTenant)
{
Cache = cache;
AbpCorrelationIdOptions = abpCorrelationIdOptions.Value;
CorrelationIdProvider = correlationIdProvider;
CurrentTenant = currentTenant;
CancellationTokenProvider = NullCancellationTokenProvider.Instance;
}
public async Task<ActionApiDescriptionModel> FindActionAsync(HttpClient client, string baseUrl, Type serviceType, MethodInfo method)
{
var apiDescription = await GetApiDescriptionAsync(client, baseUrl);
//TODO: Cache finding?
var methodParameters = method.GetParameters().ToArray();
foreach (var module in apiDescription.Modules.Values)
{
foreach (var controller in module.Controllers.Values)
{
if (!controller.Implements(serviceType))
{
continue;
}
foreach (var action in controller.Actions.Values)
{
if (action.Name == method.Name && action.ParametersOnMethod.Count == methodParameters.Length)
{
var found = true;
for (int i = 0; i < methodParameters.Length; i++)
{
if (!TypeMatches(action.ParametersOnMethod[i], methodParameters[i]))
{
found = false;
break;
}
}
if (found)
{
return action;
}
}
}
}
}
throw new AbpException($"Could not found remote action for method: {method} on the URL: {baseUrl}");
}
public virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionAsync(HttpClient client, string baseUrl)
{
return await Cache.GetAsync(baseUrl, () => GetApiDescriptionFromServerAsync(client, baseUrl));
}
protected virtual async Task<ApplicationApiDescriptionModel> GetApiDescriptionFromServerAsync(
HttpClient client,
string baseUrl)
{
var requestMessage = new HttpRequestMessage(
HttpMethod.Get,
baseUrl.EnsureEndsWith('/') + "api/abp/api-definition"
);
AddHeaders(requestMessage);
var response = await client.SendAsync(
requestMessage,
CancellationTokenProvider.Token
);
if (!response.IsSuccessStatusCode)
{
throw new AbpException("Remote service returns error! StatusCode = " + response.StatusCode);
}
var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApplicationApiDescriptionModel>(content, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
return (ApplicationApiDescriptionModel)result;
}
protected virtual void AddHeaders(HttpRequestMessage requestMessage)
{
//CorrelationId
requestMessage.Headers.Add(AbpCorrelationIdOptions.HttpHeaderName, CorrelationIdProvider.Get());
//TenantId
if (CurrentTenant.Id.HasValue)
{
//TODO: Use AbpAspNetCoreMultiTenancyOptions to get the key
requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
}
//Culture
//TODO: Is that the way we want? Couldn't send the culture (not ui culture)
var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
if (!currentCulture.IsNullOrEmpty())
{
requestMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(currentCulture));
}
//X-Requested-With
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest");
}
protected virtual bool TypeMatches(MethodParameterApiDescriptionModel actionParameter, ParameterInfo methodParameter)
{
return NormalizeTypeName(actionParameter.TypeAsString) ==
NormalizeTypeName(methodParameter.ParameterType.GetFullNameWithAssemblyName());
}
protected virtual string NormalizeTypeName(string typeName)
{
const string placeholder = "%COREFX%";
const string netCoreLib = "System.Private.CoreLib";
const string netFxLib = "mscorlib";
return typeName.Replace(netCoreLib, placeholder).Replace(netFxLib, placeholder);
}
}
}

18
aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN.Abp.Rules.NRules.csproj

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NRules" Version="0.9.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Rules\LINGYUN.Abp.Rules.csproj" />
</ItemGroup>
</Project>

22
aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/AbpNRulesModule.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using NRules.Fluent;
using NRules.RuleModel;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Rules.NRules
{
[DependsOn(
typeof(AbpRulesModule))]
public class AbpNRulesModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IRuleRepository, RuleRepository>();
Configure<AbpRulesOptions>(options =>
{
options.Contributors.Add<NRulesContributor>();
});
}
}
}

14
aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/DefaultActionInterceptor.cs

@ -0,0 +1,14 @@
using NRules.Extensibility;
using NRules.RuleModel;
using System.Collections.Generic;
namespace LINGYUN.Abp.Rules.NRules
{
public class DefaultActionInterceptor : IActionInterceptor
{
public void Intercept(IContext context, IEnumerable<IActionInvocation> actions)
{
}
}
}

21
aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/DefaultDependencyResolver.cs

@ -0,0 +1,21 @@
using NRules.Extensibility;
using System;
namespace LINGYUN.Abp.Rules.NRules
{
public class DefaultDependencyResolver : IDependencyResolver
{
private readonly IServiceProvider _serviceProvider;
public DefaultDependencyResolver(
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public object Resolve(IResolutionContext context, Type serviceType)
{
return _serviceProvider.GetService(serviceType);
}
}
}

39
aspnet-core/modules/rules/LINGYUN.Abp.Rules.NRules/LINGYUN/Abp/Rules/NRules/NRulesContributor.cs

@ -0,0 +1,39 @@
using Microsoft.Extensions.DependencyInjection;
using NRules;
using NRules.RuleModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Rules.NRules
{
public class NRulesContributor : RuleContributorBase, ISingletonDependency
{
private ISessionFactory _sessionFactory;
public override void Initialize(RulesInitializationContext context)
{
var repository = context.GetRequiredService<IRuleRepository>();
_sessionFactory = repository.Compile();
_sessionFactory.DependencyResolver = new DefaultDependencyResolver(context.ServiceProvider);
_sessionFactory.ActionInterceptor = new DefaultActionInterceptor();
}
public override Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default)
{
var session = _sessionFactory.CreateSession();
session.Insert(input);
if (@params != null && @params.Any())
{
session.InsertAll(@params);
}
// TODO: 需要研究源码
session.Fire(cancellationToken);
return Task.CompletedTask;
}
}
}

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

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="RulesEngine" Version="3.1.0" />
<PackageReference Include="Volo.Abp.Json" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Rules\LINGYUN.Abp.Rules.csproj" />
</ItemGroup>
</Project>

30
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineModule.cs

@ -0,0 +1,30 @@
using LINGYUN.Abp.Rules.RulesEngine.FileProviders.Physical;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Json;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.Rules.RulesEngine
{
[DependsOn(
typeof(AbpRulesModule),
typeof(AbpJsonModule))]
public class AbpRulesEngineModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMemoryCache();
Configure<AbpRulesOptions>(options =>
{
options.Contributors.Add<RulesEngineContributor>();
});
Configure<AbpRulesEngineOptions>(options =>
{
// 加入防止空引用
options.Contributors.Add<NullWorkflowRulesContributor>();
options.Contributors.Add<PhysicalFileWorkflowRulesContributor>();
});
}
}
}

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

@ -0,0 +1,25 @@
using Volo.Abp.Collections;
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>();
}
}
}

99
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/LINGYUN/Abp/Rules/RulesEngine/FileProviders/FileProviderWorkflowRulesContributor.cs

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

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

@ -0,0 +1,42 @@
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";
}
}

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

@ -0,0 +1,15 @@
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();
}
}

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

@ -0,0 +1,25 @@
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()
{
}
}
}

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

@ -0,0 +1,94 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using RulesEngine;
using RulesEngine.Interfaces;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Engine = RulesEngine.RulesEngine;
namespace LINGYUN.Abp.Rules.RulesEngine
{
public class RulesEngineContributor : RuleContributorBase, ISingletonDependency
{
private IRulesEngine _ruleEngine;
private readonly IEnumerable<IWorkflowRulesContributor> _workflowRulesContributors;
public RulesEngineContributor(
IServiceProvider serviceProvider,
IOptions<AbpRulesEngineOptions> options)
{
_workflowRulesContributors = options.Value
.Contributors
.Select(serviceProvider.GetRequiredService)
.Cast<IWorkflowRulesContributor>()
.ToArray();
}
public override void Initialize(RulesInitializationContext context)
{
var reSetting = new ReSettings
{
NestedRuleExecutionMode = NestedRuleExecutionMode.Performance
};
_ruleEngine = new Engine(Logger, reSetting);
foreach (var contributor in _workflowRulesContributors)
{
contributor.Initialize();
}
}
public override async Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default)
{
List<WorkflowRules> workflowRules = new();
foreach (var contributor in _workflowRulesContributors)
{
workflowRules.AddRange(await contributor.LoadAsync<T>(cancellationToken));
}
if (workflowRules.Any())
{
await ExecuteRulesAsync(input, workflowRules.ToArray(), @params);
}
}
public override void Shutdown()
{
foreach (var contributor in _workflowRulesContributors)
{
contributor.Shutdown();
}
}
protected virtual async Task ExecuteRulesAsync<T>(T input, WorkflowRules[] workflowRules, object[] @params = null)
{
_ruleEngine.AddWorkflow(workflowRules);
// 传入参与验证的实体参数
var inputs = new List<object>()
{
input
};
if (@params != null && @params.Any())
{
inputs.AddRange(@params);
}
// 其他参数以此类推
foreach (var workflowRule in workflowRules)
{
// 执行当前的规则
var ruleResult = await _ruleEngine.ExecuteAllRulesAsync(workflowRule.WorkflowName, inputs.ToArray());
// 用户自定义扩展方法,规则校验错误抛出异常
ruleResult.ThrowOfFaildExecute();
}
}
}
}

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

@ -0,0 +1,44 @@
# LINGYUN.Abp.Rules.RulesEngine
## 模块说明
集成微软规则引擎的实现
默认实现一个本地文件系统规则提供者,根据用户配置的 **PhysicalPath** 路径检索规则文件
文件名如下:
PhysicalPath/CurrentTenant.Id[如果存在]/验证规则实体类型名称[typeof(Input).Name].json
### 基础模块
### 高阶模块
### 权限定义
### 功能定义
### 配置定义
### 如何使用
```csharp
[DependsOn(
typeof(AbpRulesEngineModule))]
public class YouProjectModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpRulesEngineOptions>(options =>
{
// 指定真实存在的本地文件路径, 否则将不会检索本地规则文件
options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules");
});
}
}
```
### 更新日志

76
aspnet-core/modules/rules/LINGYUN.Abp.Rules.RulesEngine/RulesEngine/ListofRuleResultTreeExtension.cs

@ -0,0 +1,76 @@
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using Volo.Abp.Validation;
namespace RulesEngine
{
public static class ListofRuleResultTreeExtension
{
public static void ThrowOfFaildExecute(this IEnumerable<RuleResultTree> ruleResultTrees)
{
List<ValidationResult> validationResults = new List<ValidationResult>();
ruleResultTrees.WrapValidationResult(validationResults);
if (validationResults.Any())
{
throw new AbpValidationException("一个或多个规则未通过", validationResults);
}
}
private static void WrapValidationResult(this IEnumerable<RuleResultTree> ruleResultTrees, List<ValidationResult> validationResults)
{
var failedResults = ruleResultTrees.Where(rule => !rule.IsSuccess).ToArray();
foreach (var failedResult in failedResults)
{
string member = null;
var errorBuilder = new StringBuilder(36);
if (!failedResult.ExceptionMessage.IsNullOrWhiteSpace())
{
errorBuilder.AppendLine(failedResult.ExceptionMessage);
}
// TODO: 需要修改源代码, ChildResults的验证错误个人认为有必要展示出来
if (failedResult.ChildResults != null && failedResult.ChildResults.Any())
{
errorBuilder.Append(failedResult.ChildResults.GetErrorMessage(out member));
}
validationResults.Add(new ValidationResult(
errorBuilder.ToString().TrimEnd(),
new string[] { member ?? failedResult.Rule?.Properties?.GetOrDefault("Property")?.ToString() ?? "input" }));
}
}
private static string GetErrorMessage(this IEnumerable<RuleResultTree> ruleResultTrees, out string member)
{
member = null;
var errorBuilder = new StringBuilder(36);
var failedResults = ruleResultTrees.Where(rule => !rule.IsSuccess).ToArray();
for (int index = 0; index < failedResults.Length; index++)
{
member = failedResults[index].Rule?.Properties?.GetOrDefault("Property")?.ToString();
if (!failedResults[index].ExceptionMessage.IsNullOrWhiteSpace())
{
errorBuilder.AppendLine(failedResults[index].ExceptionMessage);
}
if (failedResults[index].ChildResults != null && failedResults[index].ChildResults.Any())
{
errorBuilder.Append(failedResults[index].ChildResults.GetErrorMessage(out member));
}
}
return errorBuilder.ToString();
}
}
}

14
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN.Abp.Rules.csproj

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.MultiTenancy" Version="4.3.0" />
</ItemGroup>
</Project>

26
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/AbpRulesModule.cs

@ -0,0 +1,26 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Rules
{
[DependsOn(
typeof(AbpMultiTenancyModule))]
public class AbpRulesModule : AbpModule
{
public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
{
context.ServiceProvider
.GetRequiredService<RuleProvider>()
.Initialize();
}
public override void OnApplicationShutdown(ApplicationShutdownContext context)
{
context.ServiceProvider
.GetRequiredService<RuleProvider>()
.Shutdown();
}
}
}

14
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/AbpRulesOptions.cs

@ -0,0 +1,14 @@
using Volo.Abp.Collections;
namespace LINGYUN.Abp.Rules
{
public class AbpRulesOptions
{
public ITypeList<IRuleContributor> Contributors { get; }
public AbpRulesOptions()
{
Contributors = new TypeList<IRuleContributor>();
}
}
}

14
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/IRuleContributor.cs

@ -0,0 +1,14 @@
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Rules
{
public interface IRuleContributor
{
void Initialize(RulesInitializationContext context);
Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default);
void Shutdown();
}
}

10
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/IRuleProvider.cs

@ -0,0 +1,10 @@
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Rules
{
public interface IRuleProvider
{
Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default);
}
}

31
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RuleContributorBase.cs

@ -0,0 +1,31 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Threading;
using System.Threading.Tasks;
namespace LINGYUN.Abp.Rules
{
public abstract class RuleContributorBase : IRuleContributor
{
public ILogger Logger { get; protected set; }
protected RuleContributorBase()
{
Logger = NullLogger<RuleContributorBase>.Instance;
}
public virtual void Initialize(RulesInitializationContext context)
{
}
public virtual Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
public virtual void Shutdown()
{
}
}
}

45
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RuleIdGenerator.cs

@ -0,0 +1,45 @@
using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.Rules
{
public class RuleIdGenerator : ISingletonDependency
{
private readonly ICurrentTenant _currentTenant;
public RuleIdGenerator(
ICurrentTenant currentTenant)
{
_currentTenant = currentTenant;
}
public virtual int CreateRuleId(Type type, bool ignoreMultiTenancy = false)
{
var typeId = type.GetHashCode();
if (!ignoreMultiTenancy)
{
if (_currentTenant.Id.HasValue)
{
return _currentTenant.Id.GetHashCode() & typeId;
}
}
return typeId;
}
public virtual string CreateRuleName(Type type, bool ignoreMultiTenancy = false)
{
var ruleName = type.Name;
if (!ignoreMultiTenancy)
{
if (_currentTenant.Id.HasValue)
{
return $"{_currentTenant.Id.Value:D}/{ruleName}";
}
}
return ruleName;
}
}
}

65
aspnet-core/modules/rules/LINGYUN.Abp.Rules/LINGYUN/Abp/Rules/RuleProvider.cs

@ -0,0 +1,65 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.Rules
{
public class RuleProvider : IRuleProvider, ISingletonDependency
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<RuleProvider> _logger;
private readonly IEnumerable<IRuleContributor> _rulesEngineContributors;
public RuleProvider(
IServiceProvider serviceProvider,
IOptions<AbpRulesOptions> options,
ILogger<RuleProvider> logger)
{
_rulesEngineContributors = options.Value
.Contributors
.Select(serviceProvider.GetRequiredService)
.Cast<IRuleContributor>()
.ToArray();
_logger = logger;
_serviceProvider = serviceProvider;
}
public virtual async Task ExecuteAsync<T>(T input, object[] @params = null, CancellationToken cancellationToken = default)
{
_logger.LogDebug("Starting all typed rules engine.");
foreach (var contributor in _rulesEngineContributors)
{
await contributor.ExecuteAsync(input, @params, cancellationToken);
}
_logger.LogDebug("Executed all typed rules engine.");
}
internal void Initialize()
{
var context = new RulesInitializationContext(_serviceProvider);
foreach (var contributor in _rulesEngineContributors)
{
contributor.Initialize(context);
}
}
internal void Shutdown()
{
foreach (var contributor in _rulesEngineContributors)
{
contributor.Shutdown();
}
}
}
}

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

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

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

@ -0,0 +1,54 @@
# LINGYUN.Abp.Rules
## 模块说明
规则引擎基础模块
### 基础模块
### 高阶模块
### 权限定义
### 功能定义
### 配置定义
### 如何使用
```csharp
[DependsOn(
typeof(AbpRulesModule))]
public class YouProjectModule : AbpModule
{
}
public class YouService
{
private readonly IRuleProvider _ruleProvider;
public YouService(IRuleProvider ruleProvider)
{
_ruleProvider = ruleProvider;
}
public async Task DoAsync()
{
var input = new YouInput();
// 规则校验
await _ruleProvider.ExecuteAsync(input);
var inputParams = new object[1]
{
new InputParam()
};
// 带参数规则校验
await _ruleProvider.ExecuteAsync(input, inputParams);
}
}
```
### 更新日志

27
aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests.csproj

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\oss-management\LINGYUN.Abp.OssManagement.HttpApi.Client\LINGYUN.Abp.OssManagement.HttpApi.Client.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" />
</ItemGroup>
</Project>

13
aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiClientTestBase.cs

@ -0,0 +1,13 @@
using LINGYUN.Abp.Tests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LINGYUN.Abp.OssManagement
{
public class AbpOssManagementHttpApiClientTestBase : AbpTestsBase<AbpOssManagementHttpApiClientTestModule>
{
}
}

24
aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/AbpOssManagementHttpApiClientTestModule.cs

@ -0,0 +1,24 @@
using LINGYUN.Abp.Tests;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.OssManagement
{
[DependsOn(
typeof(AbpTestsBaseModule),
typeof(AbpOssManagementHttpApiClientModule))]
public class AbpOssManagementHttpApiClientTestModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.ReplaceConfiguration(
ConfigurationHelper.BuildConfiguration(
new AbpConfigurationBuilderOptions
{
BasePath = @"D:\Projects\Development\Abp\OssManagement",
EnvironmentName = "Development"
}));
}
}
}

35
aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/OssObjectAppServiceTests.cs

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Http.Client.DynamicProxying;
using Xunit;
namespace LINGYUN.Abp.OssManagement
{
public class OssObjectAppServiceTests : AbpOssManagementHttpApiClientTestBase
{
private readonly IOssObjectAppService _service;
public OssObjectAppServiceTests()
{
_service = GetRequiredService<IOssObjectAppService>();
}
[Fact]
public async Task Get_By_Bucket_And_Object_Shouldly_Not_Null()
{
var ossObject = await _service
.GetAsync(
new GetOssObjectInput
{
Bucket = "abp-file-management",
Object = "123.png"
});
ossObject.ShouldNotBeNull();
}
}
}

35
aspnet-core/tests/LINGYUN.Abp.OssManagement.HttpApi.Client.Tests/LINGYUN/Abp/OssManagement/StaticFilesAppServiceTests.cs

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Http.Client.DynamicProxying;
using Xunit;
namespace LINGYUN.Abp.OssManagement
{
public class OssObjectAppServiceTests : AbpOssManagementHttpApiClientTestBase
{
private readonly IOssObjectAppService _service;
public OssObjectAppServiceTests()
{
_service = GetRequiredService<IOssObjectAppService>();
}
[Fact]
public async Task Get_By_Bucket_And_Object_Shouldly_Not_Null()
{
var ossObject = await _service
.GetAsync(
new GetOssObjectInput
{
Bucket = "abp-file-management",
Object = "123.png"
});
ossObject.ShouldNotBeNull();
}
}
}

36
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN.Abp.Rules.RulesEngine.Tests.csproj

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace />
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\rules\LINGYUN.Abp.Rules.RulesEngine\LINGYUN.Abp.Rules.RulesEngine.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Rules\TestMultipleRuleInput.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Rules\TestInput.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

8
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/AbpRulesEngineTestBase.cs

@ -0,0 +1,8 @@
using LINGYUN.Abp.Tests;
namespace LINGYUN.Abp.Rules.RulesEngine
{
public class AbpRulesEngineTestBase : AbpTestsBase<AbpRulesEngineTestModule>
{
}
}

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

@ -0,0 +1,23 @@
using LINGYUN.Abp.Tests;
using System.IO;
using Volo.Abp.Modularity;
using Microsoft.Extensions.DependencyInjection;
namespace LINGYUN.Abp.Rules.RulesEngine
{
[DependsOn(
typeof(AbpRulesEngineModule),
typeof(AbpTestsBaseModule))]
public class AbpRulesEngineTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMemoryCache();
Configure<AbpRulesEngineOptions>(options =>
{
options.PhysicalPath = Path.Combine(Directory.GetCurrentDirectory(), "Rules");
});
}
}
}

24
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestInput.cs

@ -0,0 +1,24 @@
namespace LINGYUN.Abp.Rules.RulesEngine
{
public class TestInput
{
public string Required { get; set; }
public int Integer1 { get; set; }
public int Integer2 { get; set; }
public string Length { get; set; }
}
public class TestMultipleRuleInput
{
public string Required { get; set; }
public int Integer1 { get; set; }
public int Integer2 { get; set; }
public string Length { get; set; }
}
}

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

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

38
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/LINGYUN/Abp/Rules/RulesEngine/TestMultipleRuleInputTests.cs

@ -0,0 +1,38 @@
using Shouldly;
using System.Threading.Tasks;
using Volo.Abp.Validation;
using Xunit;
namespace LINGYUN.Abp.Rules.RulesEngine
{
public class TestMultipleRuleInputTests : AbpRulesEngineTestBase
{
private readonly IRuleProvider _ruleProvider;
public TestMultipleRuleInputTests()
{
_ruleProvider = GetRequiredService<IRuleProvider>();
}
[Fact]
public async Task Multiple_Rule_Input_Should_Failed()
{
var input = new TestMultipleRuleInput
{
Length = "12345",
Integer1 = 100,
Integer2 = 100
};
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
{
await _ruleProvider.ExecuteAsync(input);
});
exception.Message.ShouldBe("一个或多个规则未通过");
exception.ValidationErrors.Count.ShouldBe(2);
exception.ValidationErrors[0].ErrorMessage.ShouldBe("输入字段验证无效!");
exception.ValidationErrors[1].ErrorMessage.ShouldBe("长度与求和验证无效!");
}
}
}

42
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/Rules/TestInput.json

@ -0,0 +1,42 @@
[
{
"WorkflowName": "TestInputValidation",
"Rules": [
{
"RuleName": "InputRequired",
"ErrorMessage": "字段 Required 必须输入!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "!string.IsNullOrWhiteSpace(input1.Required)"
},
{
"RuleName": "MustBeGreaterThan100",
"ErrorMessage": "字段 Integer1 必须大于100!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Integer1 > 100"
},
{
"RuleName": "MustBeLessThan100",
"ErrorMessage": "字段 Integer2 必须小于100!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Integer2 < 100"
},
{
"RuleName": "SumMustBeGreaterThan150",
"ErrorMessage": "字段 Integer1 与 Integer2 之和 必须大于150!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Integer1 + input1.Integer2 > 150"
},
{
"RuleName": "RequiredLengthMustBeGreaterThan5",
"ErrorMessage": "字段 Length 长度必须大于5!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Length.Length > 5"
}
]
}
]

58
aspnet-core/tests/LINGYUN.Abp.Rules.RulesEngine.Tests/Rules/TestMultipleRuleInput.json

@ -0,0 +1,58 @@
[
{
"WorkflowName": "TestMultipleRuleInputValidation",
"Rules": [
{
"RuleName": "ValidationInputField",
"ErrorMessage": "输入字段验证无效!",
"ErrorType": "Error",
"Operator": "AndAlso",
"Rules": [
{
"RuleName": "InputRequired",
"ErrorMessage": "字段 Required 必须输入!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "!string.IsNullOrWhiteSpace(input1.Required)"
},
{
"RuleName": "MustBeGreaterThan100",
"ErrorMessage": "字段 Integer1 必须大于100!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Integer1 > 100"
},
{
"RuleName": "MustBeLessThan100",
"ErrorMessage": "字段 Integer2 必须小于100!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Integer2 < 100"
}
]
},
{
"RuleName": "ValidationLengthAndSum",
"ErrorMessage": "长度与求和验证无效!",
"ErrorType": "Error",
"Operator": "AndAlso",
"Rules": [
{
"RuleName": "SumMustBeGreaterThan150",
"ErrorMessage": "字段 Integer1 与 Integer2 之和 必须大于200!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Integer1 + input1.Integer2 > 200"
},
{
"RuleName": "RequiredLengthMustBeGreaterThan5",
"ErrorMessage": "字段 Length 长度必须大于5!",
"ErrorType": "Error",
"RuleExpressionType": "LambdaExpression",
"Expression": "input1.Length.Length > 5"
}
]
}
]
}
]
Loading…
Cancel
Save