InzSoftwares.NetDynamicModuleLoader 1.2.0

dotnet add package InzSoftwares.NetDynamicModuleLoader --version 1.2.0
                    
NuGet\Install-Package InzSoftwares.NetDynamicModuleLoader -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="InzSoftwares.NetDynamicModuleLoader" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="InzSoftwares.NetDynamicModuleLoader" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="InzSoftwares.NetDynamicModuleLoader" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add InzSoftwares.NetDynamicModuleLoader --version 1.2.0
                    
#r "nuget: InzSoftwares.NetDynamicModuleLoader, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package InzSoftwares.NetDynamicModuleLoader@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=InzSoftwares.NetDynamicModuleLoader&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=InzSoftwares.NetDynamicModuleLoader&version=1.2.0
                    
Install as a Cake Tool

InzDynamicModuleLoader

InzDynamicModuleLoader is a .NET 9.0 library that enables plugin-based architecture by loading modules at startup time. This allows for better separation of concerns, module isolation, and flexible infrastructure switching while maintaining clean architecture boundaries.

Table of Contents

Features

  • Dynamic Module Loading: Load modules at runtime based on configuration
  • Plugin Architecture: Create extensible applications with modular functionality
  • Easy Integration: Simple setup with .NET's built-in dependency injection
  • Dependency Management: Automatic resolution of module-specific dependencies
  • Configuration-Driven: Control which modules load through configuration files
  • Development & Production: Works seamlessly in both environments

Prerequisites

  • .NET 9.0 or higher

How to Use

1. Install the Package

Add the Inz Dynamic Module Loader to your startup project:

dotnet add package InzSoftwares.NetDynamicModuleLoader

2. Configure Build Targets

Create a Directory.Build.targets file in your solution root directory with this content. This ensures all module dependencies are properly copied:


<Project>
    <PropertyGroup Condition="'$(IsModuleProject)' == 'true'">
        
        <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
        
        <GenerateDependencyFile>true</GenerateDependencyFile>
    </PropertyGroup>

    
    <Target Name="DeployModuleToUnifiedFolder" AfterTargets="Build" Condition="'$(IsModuleProject)' == 'true'">
        <PropertyGroup>
            <UnifiedModulePath>$(MSBuildThisFileDirectory)BuiltModules/$(MSBuildProjectName)/</UnifiedModulePath>
        </PropertyGroup>

        <ItemGroup>
            <ModuleFiles Include="$(OutputPath)**/*.*"/>
        </ItemGroup>

        <Message Text="[Module Deployment] Copying $(MSBuildProjectName) to $(UnifiedModulePath)" Importance="High"/>

        <Copy SourceFiles="@(ModuleFiles)"
              DestinationFolder="$(UnifiedModulePath)%(RecursiveDir)"
              SkipUnchangedFiles="true"/>
    </Target>
</Project>

This configuration ensures each dynamically loaded module includes all its dependencies and the deps.json file. The custom target creates a dedicated BuiltModules directory in the solution directory where each dynamically loaded module's dependencies can be found and resolved correctly.

For more details about this file and its purpose, see the Directory.Build.targets Documentation.

3. Create a Module Project

  1. Create a new .NET Class Library project
  2. In the .csproj file, add the IsModuleProject property:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net9.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        
        <IsModuleProject>true</IsModuleProject>
    </PropertyGroup>

</Project>

4. Implement Your Module

In your module project, create a class that implements the IAmModule interface:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using InzDynamicLoader.Core;

public class MyExampleModule : IAmModule
{
    public IServiceCollection RegisterServices(IServiceCollection services, IConfiguration configuration)
    {
        // Register your module's services here
        // Example: services.AddScoped<IMyService, MyServiceImplementation>();

        return services;
    }

    public IServiceProvider InitializeServices(IServiceProvider services, IConfiguration configuration)
    {
        // Initialize services after registration (optional)
        // Example: Initialize database connections, event handlers, etc.

        return services;
    }
}

5. Configure Modules

In your main application's appsettings.json, specify which modules to load:

{
  "Modules": [
    "MyExampleModule",
    "AnotherModule"
  ]
}

6. Register and Initialize Modules

In your main application's Program.cs (or Startup.cs), register and initialize the modules:

using InzDynamicLoader.Core;

var builder = WebApplication.CreateBuilder(args);

// Register modules and their services
builder.Services.RegisterModules(builder.Configuration);

var app = builder.Build();

// Initialize modules after services are registered
app.Services.InitializeModules(builder.Configuration);

// Continue with your application setup
app.Run();

7. Publish Your Application

When you publish your host application, your modules are copied automatically into a Modules folder next to the executable — which is where the loader looks for them in production:

dotnet build                          # builds your modules into BuiltModules/
dotnet publish YourHost -o ./deploy   # ./deploy/Modules/MyExampleModule/... is created for you

Build your modules before publishing. The publish step copies from BuiltModules/, which is only populated when your module projects build. If it is missing or empty you will get a build warning and no modules will be copied — the deployed app would then fail at startup with Could not locate 'Modules' folder.

Add a build-order reference from your host project to each module project, so the build system builds your modules before it publishes your host, and in the same configuration:


<ItemGroup>
    <ProjectReference Include="..\MyExampleModule\MyExampleModule.csproj"
                      ReferenceOutputAssembly="false" PrivateAssets="all" />
</ItemGroup>

ReferenceOutputAssembly="false" means the host gets no compile-time reference to the module — the host still cannot see module types, and modules are still chosen through configuration, not code. Without a reference like this, a solution-level publish can copy an incomplete set of modules, and a Debug build followed by a Release publish can deploy Debug modules into a Release app.

Three properties are available if you need them:

Property Default Purpose
InzModulesSourcePath BuiltModules next to your solution-root Directory.Build.targets Where modules are copied from. Set it if your modules live elsewhere, or if your host project has its own Directory.Build.targets, which moves the search anchor.
InzCopyModulesToPublish true Set to false if you deploy modules another way (for example a Docker COPY).
InzRequireModulesOnPublish false Set to true in a release pipeline. A missing or empty module folder then stops the build with error INZ001 instead of a warning.

The warning carries the code INZ001, so -p:NoWarn=INZ001 silences it in a build that treats warnings as errors.

Project Structure

After setup, your solution will have this structure:

YourSolution/
├── MainApplication/          # Your main application
├── MyExampleModule/          # First module project
├── MyOtherModule/            # Second module project
├── Directory.Build.targets   # Build configuration
├── Directory.Packages.props  # Centralized package versions
└── BuiltModules/             # Automatically created - contains compiled modules
    ├── MyExampleModule/
    │   ├── MyExampleModule.dll
    │   ├── MyExampleModule.deps.json
    │   └── Dependencies...
    └── MyOtherModule/
        ├── MyOtherModule.dll
        ├── MyOtherModule.deps.json
        └── Dependencies...

Managing Dependencies

When working with multiple modules, you may encounter the "Diamond Dependency" problem. This occurs when different modules require the same dependency but at different versions. For example:

  • Module A requires Newtonsoft.Json v13
  • Module B requires Newtonsoft.Json v9
  • At runtime, only one version can be loaded, which may cause compatibility issues

To solve this problem and ensure version consistency across all modules, create a Directory.Packages.props file in your solution root. This file enables Central Package Management, which defines package versions in one central location:


<Project>
    <PropertyGroup>
        <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    </PropertyGroup>

    <ItemGroup>
        
        <PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0"/>
        <PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0"/>
        <PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.0"/>
        
    </ItemGroup>
</Project>

When using this approach, reference packages without specifying versions in your project files:


<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions"/>

For more information about this file and its content, see the Directory.Packages.props Documentation.

IAmModule Interface Explained

The IAmModule interface has two methods:

  • RegisterServices: Called first, registers services with the dependency injection container
  • InitializeServices: Called after registration, allows for service initialization and configuration

Example Implementation

The project includes a comprehensive example that demonstrates the dynamic loading capabilities of the InzDynamicModuleLoader system. The example showcases a real-world scenario where database infrastructure can be switched at startup without code changes.

The example includes:

  • Multiple database provider implementations (MySQL and PostgreSQL)
  • Core shared components with contracts and data models
  • Common EF Core repository patterns
  • Runtime switching between database providers based on configuration
  • Clean separation of concerns between modules

The example uses modules with the Example. prefix to demonstrate:

  • Example.Module.Common - Contains shared contracts, entities, and configurations
  • Example.Module.EFCore.MySQL - MySQL-specific implementation
  • Example.Module.EFCore.PostgreSQL - PostgreSQL-specific implementation
  • Example.Module.EFCore.Repositories - Repository implementations
  • Example.Module.WebStartup - Web application startup project

This architecture demonstrates how to build flexible applications where infrastructure concerns can be swapped out dynamically, maintaining clean separation of concerns while enabling maximum flexibility.

For step-by-step instructions on how to run and understand the example, see the Example Breakdown documentation.

Troubleshooting

Problem: Module dependencies not found

  • Solution: Ensure IsModuleProject=true is set in your module project

Problem: Type conflicts between modules

  • Solution: Use Directory.Packages.props to ensure version consistency

Problem: Module not loading

  • Solution: Check that the module name in appsettings.json matches the assembly name exactly

Learn More

For detailed technical information about how the module loading system works, check out the Module System Architecture documentation.

Contributing

Contributions are welcome! Feel free to submit issues or pull requests to improve this library.

License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 90 8/15/2026
1.1.0 140 2/17/2026
1.0.2 294 12/19/2025
1.0.1 233 11/24/2025
1.0.0 221 11/24/2025
0.9.1 230 11/23/2025
0.9.0 232 11/23/2025