https://github.com/khellang/scrutor
Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
https://github.com/khellang/scrutor
asp-net-core assembly-scanning convention-registration conventions decoration decoration-extensions dependency-injection hacktoberfest scanning scrutor
Last synced: 10 months ago
JSON representation
Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
- Host: GitHub
- URL: https://github.com/khellang/scrutor
- Owner: khellang
- License: mit
- Created: 2015-11-14T01:26:41.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2025-05-13T07:23:22.000Z (10 months ago)
- Last Synced: 2025-05-13T08:33:35.262Z (10 months ago)
- Topics: asp-net-core, assembly-scanning, convention-registration, conventions, decoration, decoration-extensions, dependency-injection, hacktoberfest, scanning, scrutor
- Language: C#
- Homepage:
- Size: 367 KB
- Stars: 3,887
- Watchers: 63
- Forks: 252
- Open Issues: 44
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# Scrutor [](https://ci.appveyor.com/project/khellang/scrutor) [](https://www.nuget.org/packages/Scrutor)
> Scrutor - I search or examine thoroughly; I probe, investigate or scrutinize
> From scrūta, as the original sense of the verb was to search through trash. - https://en.wiktionary.org/wiki/scrutor
Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
## Installation
Install the [Scrutor NuGet Package](https://www.nuget.org/packages/Scrutor).
### Package Manager Console
```
Install-Package Scrutor
```
### .NET Core CLI
```
dotnet add package Scrutor
```
## Usage
The library adds two extension methods to `IServiceCollection`:
* `Scan` - This is the entry point to set up your assembly scanning.
* `Decorate` - This method is used to decorate already registered services.
See **Examples** below for usage examples.
## Examples
### Scanning
```csharp
var collection = new ServiceCollection();
collection.Scan(scan => scan
// We start out with all types in the assembly of ITransientService
.FromAssemblyOf()
// AddClasses starts out with all public, non-abstract types in this assembly.
// These types are then filtered by the delegate passed to the method.
// In this case, we filter out only the classes that are assignable to ITransientService.
.AddClasses(classes => classes.AssignableTo())
// We then specify what type we want to register these classes as.
// In this case, we want to register the types as all of its implemented interfaces.
// So if a type implements 3 interfaces; A, B, C, we'd end up with three separate registrations.
.AsImplementedInterfaces()
// And lastly, we specify the lifetime of these registrations.
.WithTransientLifetime()
// Here we start again, with a new full set of classes from the assembly above.
// This time, filtering out only the classes assignable to IScopedService.
.AddClasses(classes => classes.AssignableTo())
// Now, we just want to register these types as a single interface, IScopedService.
.As()
// And again, just specify the lifetime.
.WithScopedLifetime()
// Generic interfaces are also supported too, e.g. public interface IOpenGeneric
.AddClasses(classes => classes.AssignableTo(typeof(IOpenGeneric<>)))
.AsImplementedInterfaces()
// And you scan generics with multiple type parameters too
// e.g. public interface IQueryHandler
.AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)))
.AsImplementedInterfaces());
```
#### Scanning compiled view (UI) types
By default, Scrutor excludes compiler-generated types from the `.AddClasses()` type filters. When loading views from a framework such as [Avalonia UI](https://avaloniaui.net/), we need to opt in to compiler-generated types, like this:
```csharp
.AddClasses(classes => classes
// Opt-in to compiler-generated types
.WithAttribute()
// Optionally filter types to reduce number of service registrations.
.InNamespaces("MyApp.Desktop.Views")
.AssignableToAny(
typeof(Window),
typeof(UserControl)
)
.AsSelf()
.WithSingletonLifetime()
```
With some UI frameworks, these compiler-generated views implement quite a few interfaces, so unless you need them, it's probably best to register these classes `.AsSelf()`; in other words, be very precise with your filters that accept compiler generated types.
### Decoration
```csharp
var collection = new ServiceCollection();
// First, add our service to the collection.
collection.AddSingleton();
// Then, decorate Decorated with the Decorator type.
collection.Decorate();
// Finally, decorate Decorator with the OtherDecorator type.
// As you can see, OtherDecorator requires a separate service, IService. We can get that from the provider argument.
collection.Decorate((inner, provider) => new OtherDecorator(inner, provider.GetRequiredService()));
var serviceProvider = collection.BuildServiceProvider();
// When we resolve the IDecoratedService service, we'll get the following structure:
// OtherDecorator -> Decorator -> Decorated
var instance = serviceProvider.GetRequiredService();
```