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