Forlet.AssemblyScanner
1.1.0
dotnet add package Forlet.AssemblyScanner --version 1.1.0
NuGet\Install-Package Forlet.AssemblyScanner -Version 1.1.0
<PackageReference Include="Forlet.AssemblyScanner" Version="1.1.0" />
<PackageVersion Include="Forlet.AssemblyScanner" Version="1.1.0" />
<PackageReference Include="Forlet.AssemblyScanner" />
paket add Forlet.AssemblyScanner --version 1.1.0
#r "nuget: Forlet.AssemblyScanner, 1.1.0"
#:package Forlet.AssemblyScanner@1.1.0
#addin nuget:?package=Forlet.AssemblyScanner&version=1.1.0
#tool nuget:?package=Forlet.AssemblyScanner&version=1.1.0
Forlet.AssemblyScanner
A lightweight .NET assembly scanner for discovering types by interface implementation or base class inheritance. Uses MetadataLoadContext for safe metadata-only inspection with smart build detection.
Perfect for code generation tools, CLI scaffolders, build-time analyzers, and development tooling.
Features
- Smart Build Detection — Automatically builds projects when DLLs are missing or stale
- Metadata-Only Loading — Safe, non-executing inspection via
MetadataLoadContext - Performance Optimized — Configurable path scanning for large projects
- Generic Type Support — Full support using backtick notation (
ICommand1`) - Flexible Filtering — Include/exclude abstract classes, structs, nested types, non-public types
Installation
dotnet add package Forlet.AssemblyScanner
Quick Start
using Forlet.AssemblyScanner;
// Resolve and build if needed
var result = await ProjectDllResolver.PrepareAssemblyAsync("/path/to/MyProject.csproj");
// Scan for types
using var scanner = new MetadataScanner(result.DllPath);
var commands = scanner.FindTypesImplementing("ICommand");
foreach (var type in commands)
{
Console.WriteLine($"Found: {type.FullName}");
}
Check if a Type Exists
var result = await ProjectDllResolver.PrepareAssemblyAsync(csprojPath);
using var scanner = new MetadataScanner(result.DllPath);
// Early-exit optimization — stops at first match
var user = scanner.FindTypeByNameDerivedFrom("User", "BaseEntity");
if (user != null)
{
Console.WriteLine("User entity already exists");
}
Generic Types
Use backtick notation for generic types:
// Find ICommand and ICommand<T>
var commands = scanner.FindTypesImplementing(new[] { "ICommand", "ICommand`1" });
// Find IHandler<TRequest, TResponse>
var handlers = scanner.FindTypesImplementing("IHandler`2");
Configuration
Build Options
var result = await ProjectDllResolver.PrepareAssemblyAsync(
csprojPath,
new ProjectDllResolverOptions
{
BuildStrategy = BuildOptions.AutoBuild, // AutoBuild | NoBuild | AlwaysBuild
Configuration = "Debug",
PathsToCheck = new[] { "Commands", "Handlers" }, // Faster staleness checks
OnBuildStart = () => Console.WriteLine("Building...")
}
);
| Strategy | Behavior |
|---|---|
AutoBuild |
Builds if DLL is missing or stale (default) |
NoBuild |
Throws if DLL is missing or stale |
AlwaysBuild |
Always rebuilds before scanning |
Scan Options
var types = scanner.FindTypesImplementing(
"IHandler",
new ScanOptions
{
MatchFullName = false, // Match simple name (default) or full namespace
IncludeAbstract = false, // Include abstract classes
IncludeNonPublic = false, // Include internal/private types
IncludeStructs = false, // Include struct implementations
IncludeNestedTypes = false // Include nested types
}
);
How It Works
- Resolve — Parses
.csprojfor target framework, output path, and assembly name - Stale Check — Compares DLL timestamp against source files
- Build — Runs
dotnet buildif needed (when usingAutoBuild) - Load — Creates
MetadataLoadContextwith runtime assemblies from.deps.json - Scan — Searches types by interface or base class
Requirements
- .NET 10.0 or higher
dotnetCLI available in PATH (for build functionality)
Environment Variables
| Variable | Description |
|---|---|
DOTNET_ROOT |
Standard .NET env var — primary hint for the .NET installation root |
DOTNET_ROOT_X64 / DOTNET_ROOT_ARM64 |
Architecture-specific installation root overrides (standard .NET) |
FORLET_ASSEMBLY_SCANNER_RUNTIME_DIR |
Direct override — set to the exact directory containing BCL DLLs (e.g. /lib/dotnet/shared/Microsoft.NETCore.App/10.0.x/). Takes precedence over all other discovery strategies. Use this when automatic discovery fails in non-standard environments. |
Self-contained / Single-file Publish
MetadataScanner fully supports host tools published as self-contained single-file executables (PublishSingleFile=true, SelfContained=true). Runtime assemblies are located via the following strategies, in order:
FORLET_ASSEMBLY_SCANNER_RUNTIME_DIR(explicit override)DOTNET_ROOT/DOTNET_ROOT_X64/DOTNET_ROOT_ARM64- The
dotnetexecutable found inPATH(symlinks resolved to the install root) - OS-specific well-known installation paths (Windows, Linux, macOS)
RuntimeEnvironment.GetRuntimeDirectory()fallback
If scanning fails in a non-standard environment, set FORLET_ASSEMBLY_SCANNER_RUNTIME_DIR to the runtime DLL directory to resolve it without any code changes:
# Linux example
export FORLET_ASSEMBLY_SCANNER_RUNTIME_DIR=/lib/dotnet/shared/Microsoft.NETCore.App/10.0.x
# Windows example
$env:FORLET_ASSEMBLY_SCANNER_RUNTIME_DIR = "C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.x"
Documentation
- Usage Guide — Patterns, examples, and best practices
- API Reference — Complete API documentation
License
MIT License — see LICENSE for details.
Part of the Forlet framework.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- System.Reflection.MetadataLoadContext (>= 10.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.