﻿# Assembly scanning


NServiceBus scans assemblies at endpoint startup to automatically detect and load [message types](/nservicebus/messaging/messages-events-commands.md), [message handlers](/nservicebus/handlers/index.md), [features](/nservicebus/pipeline/features.md), and [installers](/nservicebus/operations/installers.md).

> [!NOTE]
> Assembly scanning is optional starting in NServiceBus version 10.2. For the modern explicit registration approaches, see [Registering Handlers and Sagas](/nservicebus/handlers-and-sagas-registration.md).

There are some cases where finer control over which assemblies are loaded is required:

* To limit the number of assemblies being scanned and hence improve startup time.
* If hosting multiple endpoints out of the same directory, each endpoint may require loading a subset of assemblies.

> [!NOTE]
> NServiceBus extensions such as `NServiceBus.RavenDB.dll` are not considered a core assembly but still must be included when customizing the assembly scanning.

## AppDomain assemblies

By default, the assemblies already loaded into the AppDomain are scanned. The endpoint can also be configured to disable AppDomain assembly scanning:

<!-- snippet: ScanningApDomainAssemblies -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.ScanAppDomainAssemblies = false;
```

<!-- endsnippet -->

## Assembly files

By default, all assemblies in the endpoint's `bin` directory are scanned for related interfaces so that the endpoint can configure them automatically.

### Additional assembly scanning path

> [!NOTE]
> This configuration option is available only in NServiceBus version 7.4 and above.

Assembly scanning can be configured to scan an additional path for assemblies outside the default scanning path.

<!-- snippet: AdditionalAssemblyScanningPath -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.AdditionalAssemblyScanningPath = additionalPathToScanAssemblies;
```

<!-- endsnippet -->

### Nested directories

Nested directories are **not** scanned for assemblies by default. Nested directory assembly scanning can be enabled using:

<!-- snippet: ScanningNestedAssebliesEnabled -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.ScanAssembliesInNestedDirectories = true;
```

<!-- endsnippet -->

### Disable assembly files scanning

Scanning of assemblies deployed to the `bin` folder (and other configured scanning locations) can be disabled:

<!-- snippet: disable-file-scanning -->

```cs
endpointConfiguration.AssemblyScanner().ScanFileSystemAssemblies = false;
```

<!-- endsnippet -->

> [!WARNING]
> When disabling scanning of assembly files, ensure that all required assemblies are correctly loaded into the AppDomain at endpoint startup and that AppDomain assembly scanning is enabled.

## Assemblies to scan

The assemblies being scanned can further be controlled via user-defined exclusions. This supports common scenarios removing specific assemblies from scanning without the risk of accidentally excluding required assemblies.

### Exclude specific assemblies by name

<!-- snippet: ScanningExcludeByName -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.ExcludeAssemblies("MyAssembly1.dll", "MyAssembly2.dll");
```

<!-- endsnippet -->

### Exclude assemblies by wildcard

Multiple assemblies can be excluded by wildcards using the following approach:

<!-- snippet: ScanningAssembliesWildcard -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();

var excludeRegexs = new List<string>
{
    @"App_Web_.*\.dll",
    @".*\.resources\.dll"
};

var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
foreach (var fileName in Directory.EnumerateFiles(baseDirectory, "*.dll")
             .Select(Path.GetFileName))
{
    foreach (var pattern in excludeRegexs)
    {
        if (Regex.IsMatch(fileName, pattern, RegexOptions.IgnoreCase))
        {
            scanner.ExcludeAssemblies(fileName);
            break;
        }
    }
}
```

<!-- endsnippet -->

### Exclude specific types

<!-- snippet: ScanningExcludeTypes -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.ExcludeTypes(type1, type2);
```

<!-- endsnippet -->

## Suppress scanning exceptions

> [!NOTE]
> This configuration option is only available in NServiceBus 6.2 and above.

By default, exceptions that occurred during assembly scanning will be re-thrown. Those exceptions can be ignored using the following:

<!-- snippet: SwallowScanningExceptions -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.ThrowExceptions = false;
```

<!-- endsnippet -->

> [!WARNING]
> Ignoring assembly scanning exceptions can cause the endpoint not to load some features, behaviors, messages or message handlers and cause incorrect behavior.

## Disable assembly scanning

Assembly scanning can be completely disabled. When disabled, no assemblies are scanned, and the endpoint will not automatically discover handlers, features, or installers.

<!-- snippet: DisableAssemblyScanning -->

```cs
var scanner = endpointConfiguration.AssemblyScanner();
scanner.Disable = true;
```

<!-- endsnippet -->

> [!WARNING]
> When assembly scanning is disabled, message handlers, sagas, features, and installers must be explicitly registered. Messages received without a registered handler or saga [will fail and be moved to the error queue](/nservicebus/handlers/index_core_10.md#no-handler-for-a-message).
>
> See [Registering Handlers and Sagas](/nservicebus/handlers-and-sagas-registration.md) for details on explicit registration approaches.

> [!NOTE]
> Manual registration APIs work alongside assembly scanning, enabling a hybrid approach. Use [assembly exclusion options](#assemblies-to-scan) to limit what gets scanned, then manually register specific components as needed.

When assembly scanning is disabled, register components with the following manual registration APIs.

### Manual handler registration

Use `AddHandler<THandler>()` to register message handlers:

<!-- snippet: RegisterHandlerManually -->

```cs
endpointConfiguration.AddHandler<PlaceOrderHandler>();
```

<!-- endsnippet -->

### Manual saga registration

Use `AddSaga<TSaga>()` to register sagas:

<!-- snippet: RegisterSagaManually -->

```cs
endpointConfiguration.AddSaga<ShippingSaga>();
```

<!-- endsnippet -->

### Manual feature registration

Use `EnableFeature<TFeature>()` to enable features:

<!-- snippet: EnableFeatureManually -->

```cs
endpointConfiguration.EnableFeature<CustomRoutingFeature>();
```

<!-- endsnippet -->

### Manual installer registration

Use `AddInstaller<TInstaller>()` to register installers:

<!-- snippet: RegisterInstallerManually -->

```cs
endpointConfiguration.AddInstaller<DatabaseSetupInstaller>();
```

<!-- endsnippet -->

> [!NOTE]
> Some NServiceBus packages and extensions provide their own manual registration APIs beyond the core APIs listed above. For example, custom checks have their own registration methods. When using additional NServiceBus packages, consult their documentation for any manual registration requirements.

