Scrutor Documentation

repository·master·Indexed 26 days ago

https://github.com/khellang/scrutor

A library providing assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection. It enables automatic type registration based on assembly contents via the Scan() method and simplifies the implementation of the Decorator pattern using the Decorate() method.

Tokens
1.3K
Snippets
4
Records
4
Agent score
38%

What's inside Scrutor

  1. Install Scrutor via NuGet

    master

    To use Scrutor for assembly scanning and decoration in your .NET project, install the Scrutor NuGet package using one of the following commands:

    # Package Manager Console
    Install-Package Scrutor
    
    # .NET Core CLI
    dotnet add package Scrutor
  2. Scan compiler-generated types (e.g., for UI frameworks)

    master

    By default, Scrutor excludes compiler-generated types from .AddClasses() filters. If you are using frameworks like Avalonia UI where views are compiler-generated, you must explicitly opt-in using .WithAttribute<CompilerGeneratedAttribute>(). It is recommended to use precise filters like .InNamespaces() or .AssignableToAny() when doing this to avoid excessive registrations.

    .AddClasses(classes => classes
        // Opt-in to compiler-generated types
        .WithAttribute<CompilerGeneratedAttribute>()
        // Optionally filter types to reduce number of service registrations.
        .InNamespaces("MyApp.Desktop.Views")
        .AssignableToAny(
            typeof(Window),
            typeof(UserControl)
        )
        .AsSelf()
        .WithSingletonLifetime()
  3. Perform assembly scanning with Scan()

    master

    The Scan extension method on IServiceCollection is the entry point for assembly scanning. It allows you to find types in an assembly and register them with specific lifetimes and interfaces.

    Commonly used methods within the scanning delegate include:

    • FromAssemblyOf<T>(): Starts scanning from the assembly containing type T.
    • AddClasses(filter): Filters for public, non-abstract types. The filter can use AssignableTo<T>(), AssignableTo(typeof(T)), or AssignableToAny(params Type[]).
    • AsImplementedInterfaces(): Registers the types as all of their implemented interfaces.
    • As<T>(): Registers the types as a specific type T.
    • AsSelf(): Registers the types as themselves.
    • WithTransientLifetime(), WithScopedLifetime(), WithSingletonLifetime(): Sets the service lifetime.
    var collection = new ServiceCollection();
    
    collection.Scan(scan => scan
         .FromAssemblyOf<ITransientService>()
            .AddClasses(classes => classes.AssignableTo<ITransientService>())
                .AsImplementedInterfaces()
                .WithTransientLifetime()
            .AddClasses(classes => classes.AssignableTo(typeof(IOpenGeneric<>)))
                .AsImplementedInterfaces()
            .AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)))
                .AsImplementedInterfaces());
  4. Decorate services with Decorate()

    master

    The Decorate extension method allows you to wrap an existing service registration with a decorator. You can decorate using a simple type-to-type mapping or a factory delegate that provides access to the inner service and the IServiceProvider.

    When multiple decorators are applied, they wrap each other in the order they were registered (e.g., Decorator2 -> Decorator1 -> OriginalService).

    var collection = new ServiceCollection();
    
    // 1. Add the base service
    collection.AddSingleton<IDecoratedService, Decorated>();
    
    // 2. Decorate with a simple type
    collection.Decorate<IDecoratedService, Decorator>();
    
    // 3. Decorate using a factory delegate (allows injecting other services from the provider)
    collection.Decorate<IDecoratedService>((inner, provider) => 
        new OtherDecorator(inner, provider.GetRequiredService<IService>()));
    
    var serviceProvider = collection.BuildServiceProvider();
    
    // Resolving IDecoratedService returns: OtherDecorator -> Decorator -> Decorated
    var instance = serviceProvider.GetRequiredService<IDecoratedService>();