Skip to content

Instantly share code, notes, and snippets.

@puschie286
Created August 11, 2025 13:58
Show Gist options
  • Select an option

  • Save puschie286/13874f7a15eb4b2f8200bbb7aa38e346 to your computer and use it in GitHub Desktop.

Select an option

Save puschie286/13874f7a15eb4b2f8200bbb7aa38e346 to your computer and use it in GitHub Desktop.
Dynamic abp module dependencies handling
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 );
}
}
public interface IDynamicModuleDependency
{
public Type[] GetDynamicDependencies( IServiceCollection collection )
{
return [];
}
}
@puschie286
Copy link
Author

How to use:

  1. register DynamicModuleLoader before abp startup (before AddApplication is called) in your Program.cs
    builder.Services.AddSingleton<IModuleLoader>( new DynamicModuleLoader() );
  2. implement IDynamicModuleDependency in the desired modules

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment