Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ServiceComposer/ServiceComposer.AspNetCore/llms.txt

Use this file to discover all available pages before exploring further.

AssemblyScanner drives ServiceComposer’s automatic handler discovery at application startup. When enabled (the default), it loads every *.dll and *.exe file it can find — from the currently loaded AppDomain assemblies, the application base directory, and the TRUSTED_PLATFORM_ASSEMBLIES list — and then reflects over the types in those assemblies to register composition components into the DI container. The scanner recognises the following interfaces and attributes and registers matching types automatically:
Interface / AttributeRegistered as
ICompositionRequestsHandlerTransient composition handler
ICompositionEventsSubscriberTransient composition handler
ICompositionEventsHandler<T>Transient event handler
IViewModelFactoryTransient global ViewModel factory
IEndpointScopedViewModelFactoryTransient endpoint-scoped factory
ICompositionRequestFilter / ICompositionRequestFilter<T>Transient request filter
IViewModelPreviewHandlerTransient preview handler
IViewModelCompositionOptionsCustomizationInstantiated at startup to customize ViewModelCompositionOptions
The AssemblyScanner instance is exposed as the AssemblyScanner property on ViewModelCompositionOptions and is configured during the AddViewModelComposition callback.

Properties

IsEnabled

public bool IsEnabled { get; }
true when the scanner will run at startup (the default); false after Disable() has been called. Read-only from outside the class — use Disable() to change the value.

DirectorySearchOptions

public SearchOption DirectorySearchOptions { get; set; }
Controls whether the file-system scan of AppContext.BaseDirectory searches only the top-level directory or recurses into subdirectories.
DirectorySearchOptions
System.IO.SearchOption
SearchOption.TopDirectoryOnly (default) — only the base directory is searched. SearchOption.AllDirectories — all subdirectories are also searched.
builder.Services.AddViewModelComposition(options =>
{
    options.AssemblyScanner.DirectorySearchOptions = SearchOption.AllDirectories;
});

Methods

Disable

public void Disable()
Turns off the assembly scanner entirely. When disabled, no automatic type discovery takes place; you must manually register every composition handler using ViewModelCompositionOptions.RegisterCompositionHandler<T>() or AddTypesRegistrationHandler.
builder.Services.AddViewModelComposition(options =>
{
    options.AssemblyScanner.Disable();

    // Register handlers explicitly
    options.RegisterCompositionHandler<ProductDetailsHandler>();
    options.RegisterCompositionHandler<PricingHandler>();
});

AddAssemblyFilter

public void AddAssemblyFilter(Func<string, FilterResults> filter)
Appends a filter delegate to the scanner’s filter chain. The delegate receives the full file-system path of each candidate assembly and returns FilterResults.Include to allow it or FilterResults.Exclude to skip it. All registered filters must return Include for an assembly to be loaded; a single Exclude from any filter causes the assembly to be skipped.
filter
Func<string, FilterResults>
required
A delegate that receives the assembly’s full path and returns FilterResults.Include or FilterResults.Exclude.
builder.Services.AddViewModelComposition(options =>
{
    // Only scan assemblies whose file name starts with "MyApp."
    options.AssemblyScanner.AddAssemblyFilter(path =>
        System.IO.Path.GetFileName(path).StartsWith("MyApp.")
            ? AssemblyScanner.FilterResults.Include
            : AssemblyScanner.FilterResults.Exclude);
});
Multiple filters can be combined:
builder.Services.AddViewModelComposition(options =>
{
    options.AssemblyScanner.AddAssemblyFilter(path =>
        path.Contains("Legacy")
            ? AssemblyScanner.FilterResults.Exclude
            : AssemblyScanner.FilterResults.Include);

    options.AssemblyScanner.AddAssemblyFilter(path =>
        path.Contains("Tests")
            ? AssemblyScanner.FilterResults.Exclude
            : AssemblyScanner.FilterResults.Include);
});

FilterResults Enum

public enum FilterResults
{
    Exclude = 0,
    Include = 1
}
Return value of an AddAssemblyFilter delegate.
ValueIntegerMeaning
Exclude0Skip this assembly; do not load or reflect over it.
Include1Allow this assembly to be loaded and scanned.

How scanning works

At the end of AddViewModelComposition, the scanner performs the following steps:
  1. Iterates over every assembly already loaded into AppDomain.CurrentDomain.
  2. Searches AppContext.BaseDirectory for *.dll and *.exe files using DirectorySearchOptions.
  3. Searches the TRUSTED_PLATFORM_ASSEMBLIES list (present in single-file and trimmed deployments).
  4. For each candidate path, validates it is a .NET managed assembly and is not a Microsoft runtime assembly (using a public-key-token check). Invalid or runtime assemblies are silently skipped.
  5. Applies all registered filters; any Exclude result drops the assembly.
  6. Loads qualifying assemblies and reflects over all public non-abstract types.
  7. Invokes every IViewModelCompositionOptionsCustomization found, then runs each registered typesRegistrationHandler against the filtered type list.

Build docs developers (and LLMs) love