Skip to content

A cross‑platform .NET Standard 2.1 library for dynamic loading of native/managed assemblies. A flexible alternative to static P/Invoke, with managed type inspection, dynamic interop, and built‑in architecture detection for Linux, macOS, Windows, Android, and iOS..

Notifications You must be signed in to change notification settings

netmodules/NetTools.AssemblyLoader

Repository files navigation

NetTools.AssemblyLoader

A cross-platform .NET Standard 2.1 library for dynamically loading and unloading native (unmanaged) and managed assemblies at runtime. It provides a flexible alternative to traditional P/Invoke by enabling dynamic declaration of interop methods and runtime type inspection across Linux, macOS, and Windows.


✨ Why does this library exist?

Working with native libraries in .NET often requires:

  • Hardcoding platform-specific paths and extensions.
  • Static P/Invoke declarations that are brittle and inflexible.
  • Limited control over unloading assemblies and reclaiming memory.

NetTools.AssemblyLoader solves these problems by:

  • Providing a unified INativeAssemblyLoader interface with built-in loaders for Linux, macOS, and Windows.
  • Offering a DynamicAssembly class to declare and invoke P/Invoke methods at runtime.
  • Supporting dynamic managed assembly loading/unloading via ManagedTypeWrapper and a custom CollectableAssemblyLoadContext.
  • Including RuntimePlatform helpers to detect OS and CPU architecture at runtime.

This makes it easier to build cross-platform .NET applications that integrate with native libraries, while keeping memory usage predictable and 'hopefully' avoiding leaks.

In addition, it provides a more flexible and dynamic approach to interop compared to traditional static P/Invoke declarations. For example, if in Windows you were to require functionality of native GDI+ (Gdiplus.dll), you could dynamically load the library and declare the necessary methods at runtime, without hardcoding paths or relying on static declarations. Meaning that functionality can easily be managed and replaced on other operating systems and CPU architectures.


Key Features

  • Dynamic native assembly loading
    Load unmanaged libraries at runtime with platform-specific loaders.

  • Dynamic P/Invoke declaration
    Define and invoke native methods dynamically using DynamicAssembly.

  • Managed assembly loading/unloading
    Inspect and invoke managed types dynamically with ManagedTypeWrapper.

  • Cross-platform support
    Built-in loaders for Linux, macOS, and Windows.

  • Runtime detection utilities
    Identify the current OS and CPU architecture with RuntimePlatform.


Getting Started

Installation

To use NetTools.AssemblyLoader in your project, simply add the library via NuGet Package Manager:

Install-Package NetTools.AssemblyLoader

Quick Examples

Here's a few basic demonstrations of how to use NetTools.AssemblyLoader:

Detecting Runtime Platform

This snippet demonstrates how to use the RuntimePlatform helper to identify the current operating system and CPU architecture at runtime. It retrieves both an enum value (platform) and a string representation (runtimeString), making it easy to branch logic or construct platform‑specific paths in cross‑platform applications.

using NetTools.AssemblyLoader;

var platform = RuntimePlatform.GetRuntimePlatform();
var runtimeString = RuntimePlatform.GetRuntimeString();

Console.WriteLine($"Running on: {platform} ({runtimeString})");

Dynamically Loading Managed Types

This example shows how to use the ManagedTypeWrapper to load and interact with managed assemblies at runtime. It demonstrates retrieving all types from a given assembly, wrapping a specific type for inspection, extracting metadata such as assembly name and version, and dynamically invoking methods without static references. This enables flexible runtime discovery and execution of managed code across different assemblies.

using NetTools.AssemblyLoader.Managed;

// Load types from a managed assembly (this example loads itself as a dynamic library, replace with any managed library path and known types).
var types = ManagedTypeWrapper.GetTypes("NetTools.AssemblyLoader.dll");
Console.WriteLine($"Found {types.Count()} types.");

// Wrap a specific type.
using var wrapper = new ManagedTypeWrapper("NetTools.AssemblyLoader.dll", "NetTools.AssemblyLoader.RuntimePlatform");

// Inspect type metadata.
wrapper.GetAssemblyName(out var name, out var version);
wrapper.GetTypeName(out var typeName, out var fullName);

Console.WriteLine($"Loaded {name} v{version}, type: {fullName}");

// Invoke a method dynamically. You can invoke Methods with arguments, and Fields and Properties dynamically using the Invoke methods within ManagedTypeWrapper. 
var runtimeString = wrapper.Invoke("GetRuntimeString");
Console.WriteLine($"Runtime string: {runtimeString}");

Dynamically Declaring P/Invoke Methods

This example demonstrates how to use the DynamicAssembly class to define and invoke native methods at runtime without static P/Invoke declarations. By dynamically binding to functions in unmanaged libraries (such as user32.dll), you can call native APIs on demand, customize signatures, and manage interop more flexibly across platforms. This approach avoids compile‑time bindings and enables dynamic interop scenarios where native methods are discovered or loaded at runtime.

using NetTools.AssemblyLoader.Dynamic;

// Define a dynamic P/Invoke for user32.dll MessageBox
using var dynamicAssembly = new DynamicAssembly(
    new PInvokeMethod("user32.dll", "ShowMessageBox", "MessageBoxA",
        new PInvokeType<int>(),
        new PInvokeType[] {
            new PInvokeType<IntPtr>(),
            new PInvokeType<string>(),
            new PInvokeType<string>(),
            new PInvokeType<uint>()
        })
);

// Invoke the method
var result = dynamicAssembly.Invoke("ShowMessageBox",
    IntPtr.Zero,
    "Hello from dynamic P/Invoke!",
    "DynamicAssembly Example",
    (uint)0);

Console.WriteLine($"MessageBox returned: {result}");

Dynamically Loading a Native Library Cross-Platform

This example illustrates how to load unmanaged libraries at runtime using the platform‑specific INativeAssemblyLoader implementations. By selecting the appropriate loader for Windows, Linux, or macOS, you can dynamically resolve and load native dependencies without hardcoding platform details. The Load method returns a result indicating success or failure, allowing you to handle errors gracefully and ensure your application works consistently across different operating systems.

using NetTools.AssemblyLoader.Native.AssemblyLoaders;

var libraryPath = "path/to/native/library";

using var loader = new WindowsAssemblyLoader();
// Or LinuxAssemblyLoader / MacOsAssemblyLoader depending on runtime
// platform detection (see above example).

var result = loader.Load(libraryPath);

if (!result.Success)
    Console.WriteLine($"Failed to load: {result.Error}");
else
    Console.WriteLine($"Successfully loaded {libraryPath}");

📚 Key Classes

Class/Interface Namespace Description
INativeAssemblyLoader NetTools.AssemblyLoader Interface for native assembly loaders.
LinuxAssemblyLoader NetTools.AssemblyLoader.Native.AssemblyLoaders Loader for Linux native libraries.
MacOsAssemblyLoader NetTools.AssemblyLoader.Native.AssemblyLoaders Loader for macOS native libraries.
WindowsAssemblyLoader NetTools.AssemblyLoader.Native.AssemblyLoaders Loader for Windows native libraries.
DynamicAssembly NetTools.AssemblyLoader.Dynamic Define and invoke P/Invoke methods dynamically.
ManagedTypeWrapper NetTools.AssemblyLoader.Managed Load and interact with managed types dynamically.
RuntimePlatform NetTools.AssemblyLoader Detect OS and CPU architecture at runtime.

Additional Examples & Advanced Usage

Explore the NetTools.AssemblyLoader.TestProject/Program.cs.

For more detailed guidance and examples, visit our repository wiki or our website (coming soon).

Full documentation coming soon!

Contributing

We welcome contributions! To get involved:

  1. Fork NetTools.AssemblyLoader, make improvements, and submit a pull request.
  2. Code will be reviewed upon submission.
  3. Join discussions via the issues board.

📝 License

This project is licensed under the MIT License, allowing unrestricted use, modification, and distribution. If you use NetTools.AssemblyLoader in your own project, we’d love to hear about your experience, and possibly feature you on our website!

NetModules Foundation

About

A cross‑platform .NET Standard 2.1 library for dynamic loading of native/managed assemblies. A flexible alternative to static P/Invoke, with managed type inspection, dynamic interop, and built‑in architecture detection for Linux, macOS, Windows, Android, and iOS..

Resources

Stars

Watchers

Forks

Languages