diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/FodyWeavers.xml b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/FodyWeavers.xsd b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/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/LINGYUN.Abp.Dynamic.Definitions.csproj b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN.Abp.Dynamic.Definitions.csproj
new file mode 100644
index 000000000..1e16ed5b0
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN.Abp.Dynamic.Definitions.csproj
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0
+ LINGYUN.Abp.Dynamic.Definitions
+ LINGYUN.Abp.Dynamic.Definitions
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsModule.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsModule.cs
new file mode 100644
index 000000000..47fd99517
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/AbpDynamicDefinitionsModule.cs
@@ -0,0 +1,32 @@
+using Volo.Abp.Authorization;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Features;
+using Volo.Abp.Modularity;
+using Volo.Abp.Settings;
+using Volo.Abp.TextTemplating;
+
+namespace LINGYUN.Abp.Dynamic.Definitions;
+
+[DependsOn(
+ typeof(AbpFeaturesModule),
+ typeof(AbpAuthorizationModule),
+ typeof(AbpTextTemplatingCoreModule),
+ typeof(AbpDynamicDefinitionsCoreModule))]
+public class AbpDynamicDefinitionsModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+
+ options.MapStrategy(DynamicDefinitionStrategy.Merge);
+ });
+ }
+}
diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/FeatureDynamicDefinitionManager.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/FeatureDynamicDefinitionManager.cs
new file mode 100644
index 000000000..8075a3665
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/FeatureDynamicDefinitionManager.cs
@@ -0,0 +1,253 @@
+using JetBrains.Annotations;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Features;
+
+namespace LINGYUN.Abp.Dynamic.Definitions;
+
+[Dependency(ReplaceServices = true)]
+[ExposeServices(
+ typeof(IFeatureDefinitionManager),
+ typeof(FeatureDynamicDefinitionManager))]
+public class FeatureDynamicDefinitionManager :
+ DynamicDefinitionManager,
+ IFeatureDefinitionManager,
+ ISingletonDependency
+{
+ protected IStaticFeatureDefinitionStore StaticStore { get; }
+ protected IDynamicFeatureDefinitionStore DynamicStore { get; }
+ public FeatureDynamicDefinitionManager(
+ IStaticFeatureDefinitionStore staticStore,
+ IDynamicFeatureDefinitionStore dynamicStore,
+ IOptions options)
+ : base(options)
+ {
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
+ }
+
+ public async virtual Task> GetAllAsync()
+ {
+ var staticDefinitions = await StaticStore.GetFeaturesAsync();
+ var dynamicDefinitions = await DynamicStore.GetFeaturesAsync();
+
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined feature: " + name);
+ }
+
+ public async virtual Task> GetGroupsAsync()
+ {
+ var staticGroupDefinitions = await StaticStore.GetGroupsAsync();
+ var dynamicGroupDefinitions = await DynamicStore.GetGroupsAsync();
+
+ return await GetGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions);
+ }
+
+ public async virtual Task GetOrNullAsync(string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
+
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
+ }
+
+ protected override string GetDefinitionKey(FeatureDefinition definition)
+ {
+ return definition.Name;
+ }
+
+ protected override string GetGroupDefinitionKey(FeatureGroupDefinition groupDefinition)
+ {
+ return groupDefinition.Name;
+ }
+
+ protected override Task MergeDefinitionAsync(FeatureDefinition targetDefinition, FeatureDefinition sourceDefinition)
+ {
+ targetDefinition.DisplayName = sourceDefinition.DisplayName;
+
+ if (sourceDefinition.Description != null)
+ {
+ targetDefinition.Description = sourceDefinition.Description;
+ }
+
+ if (sourceDefinition.DefaultValue != null)
+ {
+ targetDefinition.DefaultValue = sourceDefinition.DefaultValue;
+ }
+
+ if (sourceDefinition.ValueType != null)
+ {
+ targetDefinition.ValueType = sourceDefinition.ValueType;
+ }
+
+ targetDefinition.IsVisibleToClients = targetDefinition.IsVisibleToClients || sourceDefinition.IsVisibleToClients;
+ targetDefinition.IsAvailableToHost = targetDefinition.IsAvailableToHost || sourceDefinition.IsAvailableToHost;
+
+ CopyFeatureDetails(targetDefinition, sourceDefinition);
+
+ return Task.FromResult(targetDefinition);
+ }
+
+ protected async override Task AfterMergeDefinitionAsync(FeatureDefinition targetDefinition, FeatureDefinition sourceDefinition)
+ {
+ foreach (var child in sourceDefinition.Children)
+ {
+ await MergeChildFeature(targetDefinition, child);
+ }
+ }
+
+ protected async override Task MergeGroupDefinitionAsync(FeatureGroupDefinition targetGroupDefinition, FeatureGroupDefinition sourceGroupDefinition)
+ {
+ if (sourceGroupDefinition.DisplayName != null)
+ {
+ targetGroupDefinition.DisplayName = sourceGroupDefinition.DisplayName;
+ }
+ foreach (var property in sourceGroupDefinition.Properties)
+ {
+ targetGroupDefinition.Properties[property.Key] = property.Value;
+ }
+
+ foreach (var sourceFeature in sourceGroupDefinition.Features)
+ {
+ var existingFeature = GetFeatureOrNull(targetGroupDefinition, sourceFeature.Name);
+
+ if (existingFeature == null)
+ {
+ var newFeature = targetGroupDefinition.AddFeature(
+ sourceFeature.Name,
+ sourceFeature.DefaultValue,
+ sourceFeature.DisplayName,
+ sourceFeature.Description,
+ sourceFeature.ValueType,
+ sourceFeature.IsVisibleToClients,
+ sourceFeature.IsAvailableToHost
+ );
+
+ CopyFeatureDetails(sourceFeature, newFeature);
+
+ foreach (var child in sourceFeature.Children)
+ {
+ AddChildFeatureRecursively(newFeature, child);
+ }
+ }
+ else
+ {
+ await MergeDefinitionAsync(existingFeature, sourceFeature);
+
+ foreach (var child in sourceFeature.Children)
+ {
+ await MergeChildFeature(existingFeature, child);
+ }
+ }
+ }
+ }
+
+ private async Task MergeChildFeature(FeatureDefinition parent, FeatureDefinition sourceChild)
+ {
+ var existingChild = parent.Children.FirstOrDefault(c => c.Name == sourceChild.Name);
+
+ if (existingChild == null)
+ {
+ var newChild = parent.CreateChild(
+ sourceChild.Name,
+ sourceChild.DefaultValue,
+ sourceChild.DisplayName,
+ sourceChild.Description,
+ sourceChild.ValueType,
+ sourceChild.IsVisibleToClients,
+ sourceChild.IsAvailableToHost
+ );
+ CopyFeatureDetails(sourceChild, newChild);
+
+ foreach (var grandchild in sourceChild.Children)
+ {
+ AddChildFeatureRecursively(newChild, grandchild);
+ }
+ }
+ else
+ {
+ await MergeDefinitionAsync(existingChild, sourceChild);
+
+ foreach (var grandchild in sourceChild.Children)
+ {
+ await MergeChildFeature(existingChild, grandchild);
+ }
+ }
+ }
+
+ private static void AddChildFeatureRecursively(FeatureDefinition parent, FeatureDefinition sourceChild)
+ {
+ var newChild = parent.CreateChild(
+ sourceChild.Name,
+ sourceChild.DefaultValue,
+ sourceChild.DisplayName,
+ sourceChild.Description,
+ sourceChild.ValueType,
+ sourceChild.IsVisibleToClients,
+ sourceChild.IsAvailableToHost
+ );
+
+ CopyFeatureDetails(sourceChild, newChild);
+
+ foreach (var grandchild in sourceChild.Children)
+ {
+ AddChildFeatureRecursively(newChild, grandchild);
+ }
+ }
+
+ private static void CopyFeatureDetails(FeatureDefinition source, FeatureDefinition target)
+ {
+ foreach (var property in source.Properties)
+ {
+ target.Properties[property.Key] = property.Value;
+ }
+
+ foreach (var provider in source.AllowedProviders)
+ {
+ if (!target.AllowedProviders.Contains(provider))
+ {
+ target.AllowedProviders.Add(provider);
+ }
+ }
+ }
+
+ public static FeatureDefinition? GetFeatureOrNull(
+ FeatureGroupDefinition group,
+ [NotNull] string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ return GetFeatureOrNullRecursively(group.Features, name);
+ }
+
+ private static FeatureDefinition? GetFeatureOrNullRecursively(
+ IReadOnlyList features,
+ string name)
+ {
+ foreach (var feature in features)
+ {
+ if (feature.Name == name)
+ {
+ return feature;
+ }
+
+ var childFeature = GetFeatureOrNullRecursively(feature.Children, name);
+ if (childFeature != null)
+ {
+ return childFeature;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/PermissionDynamicDefinitionManager.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/PermissionDynamicDefinitionManager.cs
new file mode 100644
index 000000000..36eaa06c1
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/PermissionDynamicDefinitionManager.cs
@@ -0,0 +1,249 @@
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.MultiTenancy;
+
+namespace LINGYUN.Abp.Dynamic.Definitions;
+
+[Dependency(ReplaceServices = true)]
+[ExposeServices(
+ typeof(IPermissionDefinitionManager),
+ typeof(PermissionDynamicDefinitionManager))]
+public class PermissionDynamicDefinitionManager :
+ DynamicDefinitionManager,
+ IPermissionDefinitionManager,
+ ITransientDependency
+{
+ protected IStaticPermissionDefinitionStore StaticStore { get; }
+ protected IDynamicPermissionDefinitionStore DynamicStore { get; }
+ public PermissionDynamicDefinitionManager(
+ IStaticPermissionDefinitionStore staticStore,
+ IDynamicPermissionDefinitionStore dynamicStore,
+ IOptions options) : base(options)
+ {
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined permission: " + name);
+ }
+
+ public async virtual Task> GetGroupsAsync()
+ {
+ var staticGroupDefinitions = await StaticStore.GetGroupsAsync();
+ var dynamicGroupDefinitions = await DynamicStore.GetGroupsAsync();
+
+ return await GetGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions);
+ }
+
+ public async virtual Task GetOrNullAsync(string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
+
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
+ }
+
+ public async virtual Task> GetPermissionsAsync()
+ {
+ var staticDefinitions = await StaticStore.GetPermissionsAsync();
+ var dynamicDefinitions = await DynamicStore.GetPermissionsAsync();
+
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
+ }
+
+ public async virtual Task GetResourcePermissionAsync(string resourceName, string name)
+ {
+ return await GetResourcePermissionOrNullAsync(resourceName, name)
+ ?? throw new AbpException($"Undefined resource permission: {name} for resource: {resourceName}");
+ }
+
+ public async virtual Task GetResourcePermissionOrNullAsync(string resourceName, string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ var staticDefinition = await StaticStore.GetResourcePermissionOrNullAsync(resourceName, name);
+ var dynamicDefinition = await DynamicStore.GetResourcePermissionOrNullAsync(resourceName, name);
+
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
+ }
+
+ public async virtual Task> GetResourcePermissionsAsync()
+ {
+ var staticDefinitions = await StaticStore.GetResourcePermissionsAsync();
+ var dynamicDefinitions = await DynamicStore.GetResourcePermissionsAsync();
+
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
+ }
+
+ protected override string GetDefinitionKey(PermissionDefinition definition)
+ {
+ return definition.Name;
+ }
+
+ protected override string GetGroupDefinitionKey(PermissionGroupDefinition groupDefinition)
+ {
+ return groupDefinition.Name;
+ }
+
+ protected override Task MergeDefinitionAsync(PermissionDefinition targetDefinition, PermissionDefinition sourceDefinition)
+ {
+ targetDefinition.DisplayName = sourceDefinition.DisplayName;
+ if (sourceDefinition.ResourceName != null)
+ {
+ targetDefinition.ResourceName = sourceDefinition.ResourceName;
+ }
+ if (sourceDefinition.ManagementPermissionName != null)
+ {
+ targetDefinition.ManagementPermissionName = sourceDefinition.ManagementPermissionName;
+ }
+
+ if (sourceDefinition.MultiTenancySide != MultiTenancySides.Both)
+ {
+ targetDefinition.MultiTenancySide |= sourceDefinition.MultiTenancySide;
+ }
+
+ targetDefinition.IsEnabled = targetDefinition.IsEnabled || sourceDefinition.IsEnabled;
+
+ CopyPermissionDetails(targetDefinition, sourceDefinition);
+
+ return Task.FromResult(targetDefinition);
+ }
+
+ protected async override Task MergeGroupDefinitionAsync(PermissionGroupDefinition targetGroupDefinition, PermissionGroupDefinition sourceGroupDefinition)
+ {
+ if (sourceGroupDefinition.DisplayName != null)
+ {
+ targetGroupDefinition.DisplayName = sourceGroupDefinition.DisplayName;
+ }
+ foreach (var property in sourceGroupDefinition.Properties)
+ {
+ targetGroupDefinition.Properties[property.Key] = property.Value;
+ }
+
+ foreach (var sourcePermission in sourceGroupDefinition.Permissions)
+ {
+ var existingPermission = targetGroupDefinition.GetPermissionOrNull(sourcePermission.Name);
+
+ if (existingPermission == null)
+ {
+ var newPermission = targetGroupDefinition.AddPermission(
+ sourcePermission.Name,
+ sourcePermission.DisplayName,
+ sourcePermission.MultiTenancySide,
+ sourcePermission.IsEnabled
+ );
+ newPermission.ResourceName = sourcePermission.ResourceName;
+ newPermission.ManagementPermissionName = sourcePermission.ManagementPermissionName;
+
+ CopyPermissionDetails(sourcePermission, newPermission);
+
+ foreach (var child in sourcePermission.Children)
+ {
+ AddChildPermissionRecursively(newPermission, child);
+ }
+ }
+ else
+ {
+ await MergeDefinitionAsync(existingPermission, sourcePermission);
+
+ foreach (var sourceChild in sourcePermission.Children)
+ {
+ await MergeChildPermissions(existingPermission, sourceChild);
+ }
+ }
+ }
+ }
+
+ protected async override Task AfterMergeDefinitionAsync(PermissionDefinition targetDefinition, PermissionDefinition sourceDefinition)
+ {
+ foreach (var child in sourceDefinition.Children)
+ {
+ await MergeChildPermissions(targetDefinition, child);
+ }
+ }
+
+ private async Task MergeChildPermissions(PermissionDefinition parent, PermissionDefinition sourceChild)
+ {
+ var existingChild = parent.Children.FirstOrDefault(c => c.Name == sourceChild.Name);
+
+ if (existingChild == null)
+ {
+ var newChild = parent.AddChild(
+ sourceChild.Name,
+ sourceChild.DisplayName,
+ sourceChild.MultiTenancySide,
+ sourceChild.IsEnabled
+ );
+ newChild.ResourceName = sourceChild.ResourceName;
+ newChild.ManagementPermissionName = sourceChild.ManagementPermissionName;
+
+ CopyPermissionDetails(sourceChild, newChild);
+
+ foreach (var grandchild in sourceChild.Children)
+ {
+ AddChildPermissionRecursively(newChild, grandchild);
+ }
+ }
+ else
+ {
+ await MergeDefinitionAsync(existingChild, sourceChild);
+
+ foreach (var grandchild in sourceChild.Children)
+ {
+ await MergeChildPermissions(existingChild, grandchild);
+ }
+ }
+ }
+
+ private static void AddChildPermissionRecursively(PermissionDefinition parent, PermissionDefinition sourceChild)
+ {
+ var newChild = parent.AddChild(
+ sourceChild.Name,
+ sourceChild.DisplayName,
+ sourceChild.MultiTenancySide,
+ sourceChild.IsEnabled
+ );
+ newChild.ResourceName = sourceChild.ResourceName;
+ newChild.ManagementPermissionName = sourceChild.ManagementPermissionName;
+
+ CopyPermissionDetails(sourceChild, newChild);
+
+ foreach (var grandchild in sourceChild.Children)
+ {
+ AddChildPermissionRecursively(newChild, grandchild);
+ }
+ }
+
+ private static void CopyPermissionDetails(PermissionDefinition source, PermissionDefinition target)
+ {
+ foreach (var property in source.Properties)
+ {
+ target.Properties[property.Key] = property.Value;
+ }
+
+ foreach (var provider in source.Providers)
+ {
+ if (!target.Providers.Contains(provider))
+ {
+ target.Providers.Add(provider);
+ }
+ }
+
+ foreach (var checker in source.StateCheckers)
+ {
+ if (!target.StateCheckers.Contains(checker))
+ {
+ target.StateCheckers.Add(checker);
+ }
+ }
+ }
+}
diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/SettingDynamicDefinitionManager.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/SettingDynamicDefinitionManager.cs
new file mode 100644
index 000000000..833f90f99
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/SettingDynamicDefinitionManager.cs
@@ -0,0 +1,82 @@
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Settings;
+
+namespace LINGYUN.Abp.Dynamic.Definitions;
+
+[Dependency(ReplaceServices = true)]
+[ExposeServices(
+ typeof(ISettingDefinitionManager),
+ typeof(SettingDynamicDefinitionManager))]
+public class SettingDynamicDefinitionManager :
+ DynamicDefinitionManager,
+ ISettingDefinitionManager,
+ ISingletonDependency
+{
+ protected IStaticSettingDefinitionStore StaticStore { get; }
+ protected IDynamicSettingDefinitionStore DynamicStore { get; }
+ public SettingDynamicDefinitionManager(
+ IStaticSettingDefinitionStore staticStore,
+ IDynamicSettingDefinitionStore dynamicStore,
+ IOptions options) : base(options)
+ {
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
+ }
+
+ public async virtual Task> GetAllAsync()
+ {
+ var staticDefinitions = await StaticStore.GetAllAsync();
+ var dynamicDefinitions = await DynamicStore.GetAllAsync();
+
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined setting: " + name);
+ }
+
+ public async virtual Task GetOrNullAsync(string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
+
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
+ }
+
+ protected override string GetDefinitionKey(SettingDefinition definition)
+ {
+ return definition.Name;
+ }
+
+ protected override Task MergeDefinitionAsync(SettingDefinition targetDefinition, SettingDefinition sourceDefinition)
+ {
+ targetDefinition.DisplayName = sourceDefinition.DisplayName;
+ targetDefinition.Description = sourceDefinition.Description ?? targetDefinition.Description;
+ targetDefinition.DefaultValue = sourceDefinition.DefaultValue ?? targetDefinition.DefaultValue;
+ targetDefinition.IsVisibleToClients = targetDefinition.IsVisibleToClients || sourceDefinition.IsVisibleToClients;
+ targetDefinition.IsInherited = targetDefinition.IsInherited || sourceDefinition.IsInherited;
+ targetDefinition.IsEncrypted = targetDefinition.IsEncrypted || sourceDefinition.IsEncrypted;
+
+ foreach (var property in sourceDefinition.Properties)
+ {
+ targetDefinition.Properties[property.Key] = property.Value;
+ }
+
+ foreach (var provider in sourceDefinition.Providers)
+ {
+ if (!targetDefinition.Providers.Contains(provider))
+ {
+ targetDefinition.Providers.Add(provider);
+ }
+ }
+
+ return Task.FromResult(targetDefinition);
+ }
+}
diff --git a/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/TemplateDynamicDefinitionManager.cs b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/TemplateDynamicDefinitionManager.cs
new file mode 100644
index 000000000..e489cb542
--- /dev/null
+++ b/aspnet-core/framework/dynamic-definition/LINGYUN.Abp.Dynamic.Definitions/LINGYUN/Abp/Dynamic/Definitions/TemplateDynamicDefinitionManager.cs
@@ -0,0 +1,99 @@
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.TextTemplating;
+
+namespace LINGYUN.Abp.Dynamic.Definitions;
+
+[Dependency(ReplaceServices = true)]
+[ExposeServices(
+ typeof(ITemplateDefinitionManager),
+ typeof(TemplateDynamicDefinitionManager))]
+public class TemplateDynamicDefinitionManager :
+ DynamicDefinitionManager,
+ ITemplateDefinitionManager,
+ ISingletonDependency
+{
+ protected IStaticTemplateDefinitionStore StaticStore { get; }
+ protected IDynamicTemplateDefinitionStore DynamicStore { get; }
+
+ public TemplateDynamicDefinitionManager(
+ IStaticTemplateDefinitionStore staticStore,
+ IDynamicTemplateDefinitionStore dynamicStore,
+ IOptions options) : base(options)
+ {
+ StaticStore = staticStore;
+ DynamicStore = dynamicStore;
+ }
+
+ public async virtual Task> GetAllAsync()
+ {
+ var staticDefinitions = await StaticStore.GetAllAsync();
+ var dynamicDefinitions = await DynamicStore.GetAllAsync();
+
+ return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions);
+ }
+
+ public async virtual Task GetAsync(string name)
+ {
+ return await GetOrNullAsync(name) ?? throw new AbpException("Undefined Template: " + name);
+ }
+
+ public async virtual Task GetOrNullAsync(string name)
+ {
+ Check.NotNull(name, nameof(name));
+
+ var staticDefinition = await StaticStore.GetOrNullAsync(name);
+ var dynamicDefinition = await DynamicStore.GetOrNullAsync(name);
+
+ return await GetDefinitionAsync(staticDefinition, dynamicDefinition);
+ }
+
+ protected override string GetDefinitionKey(TemplateDefinition definition)
+ {
+ return definition.Name;
+ }
+
+ protected override Task MergeDefinitionAsync(TemplateDefinition targetDefinition, TemplateDefinition sourceDefinition)
+ {
+ var localizationResourceName = sourceDefinition.LocalizationResourceName ?? targetDefinition.LocalizationResourceName;
+ var defaultCultureName = sourceDefinition.DefaultCultureName ?? targetDefinition.DefaultCultureName;
+ var displayName = sourceDefinition.DisplayName ?? targetDefinition.DisplayName;
+ var isLayout = sourceDefinition.IsLayout || targetDefinition.IsLayout;
+ var layout = sourceDefinition.Layout ?? targetDefinition.Layout;
+
+ var mergedTemplate = new TemplateDefinition(
+ targetDefinition.Name,
+ localizationResourceName,
+ displayName,
+ isLayout,
+ layout,
+ defaultCultureName
+ );
+
+ foreach (var property in targetDefinition.Properties)
+ {
+ mergedTemplate.Properties[property.Key] = property.Value;
+ }
+
+ foreach (var property in sourceDefinition.Properties)
+ {
+ mergedTemplate.Properties[property.Key] = property.Value;
+ }
+
+ if (!string.IsNullOrEmpty(sourceDefinition.RenderEngine))
+ {
+ mergedTemplate.RenderEngine = sourceDefinition.RenderEngine;
+ }
+ else if (!string.IsNullOrEmpty(targetDefinition.RenderEngine))
+ {
+ mergedTemplate.RenderEngine = targetDefinition.RenderEngine;
+ }
+
+ mergedTemplate.IsInlineLocalized = sourceDefinition.IsInlineLocalized || targetDefinition.IsInlineLocalized;
+
+ return Task.FromResult(mergedTemplate);
+ }
+}