From 10bf53dbece5846f608162f43c3bb6cf26873b3a Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 26 Aug 2026 09:09:47 +0800 Subject: [PATCH] feat: Add DynamicsCore Module --- .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++ ...INGYUN.Abp.Dynamic.Definitions.Core.csproj | 20 ++ .../AbpDynamicDefinitionsCoreModule.cs | 8 + .../AbpDynamicDefinitionsOptions.cs | 35 +++ .../Definitions/DynamicDefinitionManager.cs | 240 ++++++++++++++++++ .../Definitions/DynamicDefinitionStrategy.cs | 8 + 7 files changed, 344 insertions(+) create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xml create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xsd create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN.Abp.Dynamic.Definitions.Core.csproj create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsCoreModule.cs create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsOptions.cs create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionManager.cs create mode 100644 aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionStrategy.cs diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xml b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xsd b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN.Abp.Dynamic.Definitions.Core.csproj b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN.Abp.Dynamic.Definitions.Core.csproj new file mode 100644 index 000000000..906978d01 --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN.Abp.Dynamic.Definitions.Core.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0 + LINGYUN.Abp.Dynamic.Definitions.Core + LINGYUN.Abp.Dynamic.Definitions.Core + false + false + false + + + + + + + + diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsCoreModule.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsCoreModule.cs new file mode 100644 index 000000000..e410761b4 --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsCoreModule.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Dynamic.Definitions; + +public class AbpDynamicDefinitionsCoreModule : AbpModule +{ + +} diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsOptions.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsOptions.cs new file mode 100644 index 000000000..cdd9c0f8c --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsOptions.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Dynamic.Definitions; + +public class AbpDynamicDefinitionsOptions +{ + public DynamicDefinitionStrategy DefaultStrategy { get; set; } + public Dictionary DefinitionStrategy { get; set; } + public AbpDynamicDefinitionsOptions() + { + DefaultStrategy = DynamicDefinitionStrategy.Static; + DefinitionStrategy = new Dictionary(); + } + + public void MapStrategy(DynamicDefinitionStrategy strategy = DynamicDefinitionStrategy.Static) + { + DefinitionStrategy[typeof(T)] = strategy; + } + + public DynamicDefinitionStrategy GetStrategy() + { + return GetStrategy(typeof(T)); + } + + public DynamicDefinitionStrategy GetStrategy(Type type) + { + if (DefinitionStrategy.TryGetValue(type, out var strategy)) + { + return strategy; + } + + return DefaultStrategy; + } +} diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionManager.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionManager.cs new file mode 100644 index 000000000..81de2a518 --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionManager.cs @@ -0,0 +1,240 @@ +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Dynamic.Definitions; + +public abstract class DynamicDefinitionManager : DynamicDefinitionManager +{ + protected DynamicDefinitionManager( + IOptions options) : base(options) + { + } + + public async virtual Task GetGroupDefinitionAsync( + TGroupDefinition? staticGroupDefinition, + TGroupDefinition? dynamicGroupDefinition) + { + if (staticGroupDefinition != null && dynamicGroupDefinition != null) + { + var strategy = Options.GetStrategy(); + switch (strategy) + { + case DynamicDefinitionStrategy.Dynamic: + return dynamicGroupDefinition; + case DynamicDefinitionStrategy.Merge: + await MergeGroupDefinitionAsync(staticGroupDefinition, dynamicGroupDefinition); + return staticGroupDefinition; + case DynamicDefinitionStrategy.Static: + default: + return staticGroupDefinition; + } + } + + return staticGroupDefinition ?? dynamicGroupDefinition; + } + + public async virtual Task> GetGroupDefinitionsAsync( + IReadOnlyList staticGroupDefinitions, + IReadOnlyList dynamicGroupDefinitions) + { + var strategy = Options.GetStrategy(); + return strategy switch + { + DynamicDefinitionStrategy.Dynamic => await GetDynamicGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions), + DynamicDefinitionStrategy.Merge => await GetMergedGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions), + _ => await GetStaticGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions), + }; + } + + protected virtual Task> GetStaticGroupDefinitionsAsync( + IReadOnlyList staticGroupDefinitions, + IReadOnlyList dynamicGroupDefinitions) + { + var staticDefinitionKeys = staticGroupDefinitions + .Select(GetGroupDefinitionKey) + .ToImmutableHashSet(); + + return Task.FromResult>( + staticGroupDefinitions + .Concat(dynamicGroupDefinitions.Where(d => !staticDefinitionKeys.Contains(GetGroupDefinitionKey(d)))) + .ToImmutableList() + ); + } + + protected virtual Task> GetDynamicGroupDefinitionsAsync( + IReadOnlyList staticGroupDefinitions, + IReadOnlyList dynamicGroupDefinitions) + { + var dynamicDefinitionKeys = dynamicGroupDefinitions + .Select(GetGroupDefinitionKey) + .ToImmutableHashSet(); + + return Task.FromResult>( + dynamicGroupDefinitions + .Concat(staticGroupDefinitions.Where(s => !dynamicDefinitionKeys.Contains(GetGroupDefinitionKey(s)))) + .ToImmutableList() + ); + } + + protected async virtual Task> GetMergedGroupDefinitionsAsync( + IReadOnlyList staticGroupDefinitions, + IReadOnlyList dynamicGroupDefinitions) + { + var mergedGroups = new Dictionary(); + + foreach (var staticGroup in staticGroupDefinitions) + { + mergedGroups[GetGroupDefinitionKey(staticGroup)] = staticGroup; + } + + foreach (var dynamicGroup in dynamicGroupDefinitions) + { + if (mergedGroups.TryGetValue(GetGroupDefinitionKey(dynamicGroup), out var existingGroup)) + { + await BeforeMergeGroupDefinitionAsync(existingGroup, dynamicGroup); + await MergeGroupDefinitionAsync(existingGroup, dynamicGroup); + await AfterMergeGroupDefinitionAsync(existingGroup, dynamicGroup); + } + else + { + mergedGroups[GetGroupDefinitionKey(dynamicGroup)] = dynamicGroup; + } + } + + await AfterMergedGroupDefinitionsAsync(mergedGroups); + + return mergedGroups.Values.ToImmutableList(); + } + + protected abstract string GetGroupDefinitionKey(TGroupDefinition groupDefinition); + + protected abstract Task MergeGroupDefinitionAsync(TGroupDefinition targetGroupDefinition, TGroupDefinition sourceGroupDefinition); + + protected virtual Task BeforeMergeGroupDefinitionAsync(TGroupDefinition targetGroupDefinition, TGroupDefinition sourceGroupDefinition) + { + return Task.CompletedTask; + } + + protected virtual Task AfterMergeGroupDefinitionAsync(TGroupDefinition targetGroupDefinition, TGroupDefinition sourceGroupDefinition) + { + return Task.CompletedTask; + } + + protected virtual Task AfterMergedGroupDefinitionsAsync(Dictionary mergedDefinitions) + { + return Task.CompletedTask; + } +} + +public abstract class DynamicDefinitionManager +{ + protected AbpDynamicDefinitionsOptions Options { get; } + protected DynamicDefinitionManager(IOptions options) + { + Options = options.Value; + } + + public async virtual Task GetDefinitionAsync(TDefinition? staticDefinition, TDefinition? dynamicDefinition) + { + if (staticDefinition != null && dynamicDefinition != null) + { + var strategy = Options.GetStrategy(); + return strategy switch + { + DynamicDefinitionStrategy.Static => staticDefinition, + DynamicDefinitionStrategy.Dynamic => dynamicDefinition, + DynamicDefinitionStrategy.Merge => await MergeDefinitionAsync(staticDefinition, dynamicDefinition), + _ => staticDefinition + }; + } + + return staticDefinition ?? dynamicDefinition; + } + + public async virtual Task> GetDefinitionsAsync(IReadOnlyList staticDefinitions, IReadOnlyList dynamicDefinitions) + { + var strategy = Options.GetStrategy(); + return strategy switch + { + DynamicDefinitionStrategy.Dynamic => await GetDynamicDefinitionsAsync(staticDefinitions, dynamicDefinitions), + DynamicDefinitionStrategy.Merge => await GetMergedDefinitionsAsync(staticDefinitions, dynamicDefinitions), + _ => await GetStaticDefinitionsAsync(staticDefinitions, dynamicDefinitions), + }; + } + + protected virtual Task> GetStaticDefinitionsAsync(IReadOnlyList staticDefinitions, IReadOnlyList dynamicDefinitions) + { + var staticDefinitionKeys = staticDefinitions + .Select(GetDefinitionKey) + .ToImmutableHashSet(); + + return Task.FromResult>( + staticDefinitions + .Concat(dynamicDefinitions.Where(d => !staticDefinitionKeys.Contains(GetDefinitionKey(d)))) + .ToImmutableList() + ); + } + + protected virtual Task> GetDynamicDefinitionsAsync(IReadOnlyList staticDefinitions, IReadOnlyList dynamicDefinitions) + { + var dynamicDefinitionKeys = dynamicDefinitions + .Select(GetDefinitionKey) + .ToImmutableHashSet(); + + return Task.FromResult>( + dynamicDefinitions + .Concat(staticDefinitions.Where(s => !dynamicDefinitionKeys.Contains(GetDefinitionKey(s)))) + .ToImmutableList() + ); + } + + protected async virtual Task> GetMergedDefinitionsAsync(IReadOnlyList staticDefinitions, IReadOnlyList dynamicDefinitions) + { + var mergedDefinitions = new Dictionary(); + + foreach (var staticDefinition in staticDefinitions) + { + mergedDefinitions[GetDefinitionKey(staticDefinition)] = staticDefinition; + } + + foreach (var dynamicDefinition in dynamicDefinitions) + { + if (mergedDefinitions.TryGetValue(GetDefinitionKey(dynamicDefinition), out var existingDefinition)) + { + await BeforeMergeDefinitionAsync(existingDefinition, dynamicDefinition); + await MergeDefinitionAsync(existingDefinition, dynamicDefinition); + await AfterMergeDefinitionAsync(existingDefinition, dynamicDefinition); + } + else + { + mergedDefinitions[GetDefinitionKey(dynamicDefinition)] = dynamicDefinition; + } + } + + await AfterMergedDefinitionsAsync(mergedDefinitions); + + return mergedDefinitions.Values.ToImmutableList(); + } + + protected abstract string GetDefinitionKey(TDefinition definition); + + protected abstract Task MergeDefinitionAsync(TDefinition targetDefinition, TDefinition sourceDefinition); + + protected virtual Task BeforeMergeDefinitionAsync(TDefinition targetDefinition, TDefinition sourceDefinition) + { + return Task.CompletedTask; + } + + protected virtual Task AfterMergeDefinitionAsync(TDefinition targetDefinition, TDefinition sourceDefinition) + { + return Task.CompletedTask; + } + + protected virtual Task AfterMergedDefinitionsAsync(Dictionary mergedDefinitions) + { + return Task.CompletedTask; + } +} diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionStrategy.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionStrategy.cs new file mode 100644 index 000000000..44e54e07e --- /dev/null +++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions.Core/LINGYUN/Abp/Dynamic/Definitions/DynamicDefinitionStrategy.cs @@ -0,0 +1,8 @@ +namespace LINGYUN.Abp.Dynamic.Definitions; + +public enum DynamicDefinitionStrategy +{ + Static = 0, + Dynamic = 1, + Merge = 2, +}