Created
August 11, 2025 13:58
-
-
Save puschie286/13874f7a15eb4b2f8200bbb7aa38e346 to your computer and use it in GitHub Desktop.
Dynamic abp module dependencies handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Microsoft.Extensions.Logging.Abstractions; | |
| using Volo.Abp; | |
| using Volo.Abp.Modularity; | |
| using Volo.Abp.Modularity.PlugIns; | |
| public class DynamicModuleLoader : ModuleLoader | |
| { | |
| protected override void FillModules( List<AbpModuleDescriptor> modules, | |
| IServiceCollection services, | |
| Type startupModuleType, | |
| PlugInSourceList plugInSources ) | |
| { | |
| // regular module init | |
| base.FillModules( modules, services, startupModuleType, plugInSources ); | |
| // dynamic module init | |
| FillDynamicModules( modules, services ); | |
| } | |
| private void FillDynamicModules( List<AbpModuleDescriptor> modules, IServiceCollection services ) | |
| { | |
| // collect modules with dynamic dependencies | |
| List<IDynamicModuleDependency> dynamicDependencyModules = []; | |
| foreach( AbpModuleDescriptor module in modules ) | |
| { | |
| if( module.Instance is not IDynamicModuleDependency dynamicDependencyModule ) | |
| { | |
| continue; | |
| } | |
| dynamicDependencyModules.Add( dynamicDependencyModule ); | |
| } | |
| if( dynamicDependencyModules.Count == 0 ) | |
| { | |
| return; | |
| } | |
| // resolve dynamic modules (one level at a time) | |
| while( dynamicDependencyModules.Count > 0 ) | |
| { | |
| dynamicDependencyModules = DynamicDependencyModules( modules, services, dynamicDependencyModules ); | |
| } | |
| // set dependencies for dynamic modules (all modules exist at this point) | |
| SetDynamicDependencies( modules, services ); | |
| } | |
| private List<IDynamicModuleDependency> DynamicDependencyModules( List<AbpModuleDescriptor> modules, | |
| IServiceCollection services, | |
| IReadOnlyList<IDynamicModuleDependency> dynamicDependencyModules ) | |
| { | |
| // collect dynamic dependencies | |
| List<Type> dynamicDependencies = []; | |
| foreach( IDynamicModuleDependency dynamicDependencyModule in dynamicDependencyModules ) | |
| { | |
| foreach( Type dynamicDependency in dynamicDependencyModule.GetDynamicDependencies( services ) ) | |
| { | |
| dynamicDependencies.AddIfNotContains( dynamicDependency ); | |
| } | |
| } | |
| // resolve dynamic dependencies (to include static dependencies) | |
| HashSet<Type> resolvedDependencies = []; | |
| foreach( Type type in dynamicDependencies ) | |
| { | |
| if( modules.Any( x => x.Type == type ) ) | |
| { | |
| continue; | |
| } | |
| foreach( Type dependencyType in AbpModuleHelper.FindAllModuleTypes( type, NullLogger.Instance ) ) | |
| { | |
| resolvedDependencies.Add( dependencyType ); | |
| } | |
| } | |
| // create and register dynamic dependency modules (and collect next level modules with dynamic dependencies) | |
| List<IDynamicModuleDependency> nextModules = []; | |
| foreach( Type resolvedDependency in resolvedDependencies ) | |
| { | |
| if( modules.Any( x => x.Type == resolvedDependency ) ) | |
| { | |
| continue; | |
| } | |
| AbpModuleDescriptor descriptor = CreateModuleDescriptor( services, resolvedDependency ); | |
| // check for dynamic dependencies | |
| if( descriptor.Instance is IDynamicModuleDependency dynamicDependencyModule ) | |
| { | |
| nextModules.Add( dynamicDependencyModule ); | |
| } | |
| modules.Add( descriptor ); | |
| } | |
| return nextModules; | |
| } | |
| private static void SetDynamicDependencies( List<AbpModuleDescriptor> modules, IServiceCollection services ) | |
| { | |
| foreach( AbpModuleDescriptor module in modules ) | |
| { | |
| if( module.Instance is not IDynamicModuleDependency dynamicDependencyModule ) | |
| { | |
| continue; | |
| } | |
| // only set dynamic dependencies (statics are set in SetDependencies) | |
| foreach( Type dependedModuleType in dynamicDependencyModule.GetDynamicDependencies( services ) ) | |
| { | |
| SetModuleDependency( modules, module, dependedModuleType ); | |
| } | |
| } | |
| } | |
| private static void SetModuleDependency( IReadOnlyList<AbpModuleDescriptor> modules, | |
| AbpModuleDescriptor module, | |
| Type dependedModuleType ) | |
| { | |
| AbpModuleDescriptor? dependedModule = modules.FirstOrDefault( x => x.Type == dependedModuleType ); | |
| if( dependedModule == null ) | |
| { | |
| if( dependedModule == null ) | |
| { | |
| throw new AbpException( "Could not find a depended module " | |
| + dependedModuleType.AssemblyQualifiedName | |
| + " for " | |
| + module.Type.AssemblyQualifiedName ); | |
| } | |
| } | |
| module.AddDependency( dependedModule ); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public interface IDynamicModuleDependency | |
| { | |
| public Type[] GetDynamicDependencies( IServiceCollection collection ) | |
| { | |
| return []; | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to use:
DynamicModuleLoaderbefore abp startup (before AddApplication is called) in your Program.csbuilder.Services.AddSingleton<IModuleLoader>( new DynamicModuleLoader() );IDynamicModuleDependencyin the desired modules