Convert Figma logo to code with AI

khellang logoScrutor

Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection

3,570
233
3,570
54

Top Related Projects

4,467

An addictive .NET IoC container

An easy, flexible, and fast Dependency Injection library that promotes best practice to steer developers towards the pit of success.

1,513

Castle Windsor is a best of breed, mature Inversion of Control container available for .NET

1,659

This repository contains all relevant information about Unity Container suit

11,001

Simple, unambitious mediator implementation in .NET

Quick Overview

Scrutor is a library for .NET that provides assembly scanning and decoration capabilities for Microsoft.Extensions.DependencyInjection. It simplifies the process of registering services in your dependency injection container by allowing you to scan assemblies and register services based on conventions or attributes.

Pros

  • Simplifies service registration in dependency injection containers
  • Supports flexible scanning and filtering of assemblies
  • Allows for easy decoration of services without modifying existing code
  • Integrates seamlessly with Microsoft.Extensions.DependencyInjection

Cons

  • May introduce performance overhead for large assemblies
  • Requires careful configuration to avoid unintended service registrations
  • Learning curve for developers unfamiliar with assembly scanning concepts
  • Limited to .NET ecosystem

Code Examples

  1. Scanning an assembly and registering all types:
services.Scan(scan => scan
    .FromAssemblyOf<IService>()
    .AddClasses()
    .AsImplementedInterfaces()
    .WithTransientLifetime());
  1. Registering services with a specific naming convention:
services.Scan(scan => scan
    .FromAssemblies(Assembly.GetExecutingAssembly())
    .AddClasses(classes => classes.Where(type => type.Name.EndsWith("Service")))
    .AsMatchingInterface()
    .WithScopedLifetime());
  1. Decorating a service:
services.Scan(scan => scan
    .FromAssemblyOf<IService>()
    .AddClasses(classes => classes.AssignableTo<IService>())
    .AsImplementedInterfaces()
    .WithTransientLifetime());

services.Decorate<IService, LoggingDecorator>();

Getting Started

To use Scrutor in your project, follow these steps:

  1. Install the NuGet package:

    dotnet add package Scrutor
    
  2. In your Startup.cs or where you configure services, add the following:

using Scrutor;

public void ConfigureServices(IServiceCollection services)
{
    services.Scan(scan => scan
        .FromAssemblyOf<Program>()
        .AddClasses()
        .AsMatchingInterface()
        .WithScopedLifetime());
}

This basic setup scans the assembly containing your Program class, registers all classes with matching interfaces, and gives them a scoped lifetime.

Competitor Comparisons

4,467

An addictive .NET IoC container

Pros of Autofac

  • More comprehensive IoC container with advanced features like modules and lifetime scoping
  • Supports a wider range of registration and resolution scenarios
  • Better performance for large-scale applications with many dependencies

Cons of Autofac

  • Steeper learning curve due to its extensive feature set
  • More complex setup and configuration compared to simpler DI solutions
  • Potential for overengineering in smaller projects

Code Comparison

Scrutor (Assembly Scanning):

services.Scan(scan => scan
    .FromAssemblyOf<ITransientService>()
    .AddClasses(classes => classes.AssignableTo<ITransientService>())
    .AsImplementedInterfaces()
    .WithTransientLifetime());

Autofac (Assembly Scanning):

builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
    .Where(t => t.IsAssignableTo<ITransientService>())
    .AsImplementedInterfaces()
    .InstancePerDependency();

Both libraries offer assembly scanning capabilities, but Autofac provides more granular control over registration and lifetime management. Scrutor focuses on enhancing Microsoft.Extensions.DependencyInjection with scanning features, while Autofac is a full-fledged IoC container with broader functionality.

An easy, flexible, and fast Dependency Injection library that promotes best practice to steer developers towards the pit of success.

Pros of SimpleInjector

  • More comprehensive dependency injection framework with advanced features
  • Better performance in large-scale applications
  • Supports automatic lifestyle management for registered components

Cons of SimpleInjector

  • Steeper learning curve due to more complex API
  • Requires more configuration and setup compared to Scrutor
  • Less focused on assembly scanning and convention-based registration

Code Comparison

SimpleInjector:

var container = new Container();
container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Singleton);
container.Register<IUserService, UserService>(Lifestyle.Transient);
container.Verify();

Scrutor:

services.Scan(scan => scan
    .FromAssemblyOf<IUserRepository>()
    .AddClasses(classes => classes.AssignableTo<IUserRepository>())
    .AsImplementedInterfaces()
    .WithSingletonLifetime());

SimpleInjector provides a more explicit registration approach, while Scrutor focuses on convention-based scanning and registration. SimpleInjector offers more control over component lifestyles, whereas Scrutor integrates seamlessly with Microsoft's dependency injection container.

1,513

Castle Windsor is a best of breed, mature Inversion of Control container available for .NET

Pros of Windsor

  • Full-featured IoC container with advanced capabilities like interception, proxying, and lifecycle management
  • Supports various component registration methods, including XML configuration and fluent API
  • Mature project with extensive documentation and community support

Cons of Windsor

  • Steeper learning curve due to its comprehensive feature set
  • Can be overkill for simpler projects that only need basic dependency injection
  • Slightly more complex setup and configuration compared to lightweight alternatives

Code Comparison

Windsor registration:

container.Register(Component.For<IService>().ImplementedBy<ServiceImpl>());

Scrutor registration:

services.Scan(scan => scan
    .FromAssemblyOf<IService>()
    .AddClasses(classes => classes.AssignableTo<IService>())
    .AsImplementedInterfaces());

Windsor focuses on explicit registration with a fluent API, while Scrutor emphasizes convention-based registration using assembly scanning. Windsor provides more control over component lifecycle and configuration, whereas Scrutor offers a simpler approach for common scenarios in ASP.NET Core applications.

1,659

This repository contains all relevant information about Unity Container suit

Pros of Unity

  • More comprehensive IoC container with advanced features like hierarchical containers and lifetime management
  • Supports various injection methods (constructor, property, method)
  • Extensive documentation and community support

Cons of Unity

  • Heavier and more complex than Scrutor
  • Steeper learning curve for beginners
  • Less focused on assembly scanning and registration conventions

Code Comparison

Unity:

container.RegisterType<IService, ServiceImplementation>();
container.RegisterType<IRepository, Repository>(new ContainerControlledLifetimeManager());
var instance = container.Resolve<IService>();

Scrutor:

services.Scan(scan => scan
    .FromAssemblyOf<IService>()
    .AddClasses(classes => classes.AssignableTo<IService>())
    .AsImplementedInterfaces()
    .WithScopedLifetime());

Summary

Unity is a full-featured IoC container with more capabilities but higher complexity. Scrutor focuses on assembly scanning and registration conventions, offering a simpler approach for specific use cases. Unity is better suited for large, complex applications requiring advanced DI features, while Scrutor excels in scenarios where automatic registration and convention-based configuration are primary needs.

11,001

Simple, unambitious mediator implementation in .NET

Pros of MediatR

  • Implements the mediator pattern, promoting loose coupling and separation of concerns
  • Supports both synchronous and asynchronous request/response handling
  • Provides pipeline behaviors for cross-cutting concerns (e.g., logging, validation)

Cons of MediatR

  • Requires more boilerplate code for defining request/handler classes
  • Can lead to a proliferation of small classes in larger applications
  • May introduce additional complexity for simpler scenarios

Code Comparison

MediatR:

public class GetUserQuery : IRequest<User> { }

public class GetUserHandler : IRequestHandler<GetUserQuery, User>
{
    public Task<User> Handle(GetUserQuery request, CancellationToken cancellationToken)
    {
        // Handler implementation
    }
}

Scrutor:

services.Scan(scan => scan
    .FromAssemblyOf<ITransientService>()
    .AddClasses(classes => classes.AssignableTo<ITransientService>())
    .AsImplementedInterfaces()
    .WithTransientLifetime());

While MediatR focuses on implementing the mediator pattern for decoupling request/response handling, Scrutor is primarily used for assembly scanning and automatic dependency registration. They serve different purposes in application architecture and can be used together in a project.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Scrutor Build status NuGet Package

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.

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

var collection = new ServiceCollection();

collection.Scan(scan => scan
     // We start out with all types in the assembly of ITransientService
    .FromAssemblyOf<ITransientService>()
        // 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<ITransientService>())
            // 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<IScopedService>())
            // Now, we just want to register these types as a single interface, IScopedService.
            .As<IScopedService>()
            // And again, just specify the lifetime.
            .WithScopedLifetime()
        // Generic interfaces are also supported too, e.g. public interface IOpenGeneric<T> 
        .AddClasses(classes => classes.AssignableTo(typeof(IOpenGeneric<>)))
            .AsImplementedInterfaces()
        // And you scan generics with multiple type parameters too
        // e.g. public interface IQueryHandler<TQuery, TResult>
        .AddClasses(classes => classes.AssignableTo(typeof(IQueryHandler<,>)))
            .AsImplementedInterfaces());

Decoration

var collection = new ServiceCollection();

// First, add our service to the collection.
collection.AddSingleton<IDecoratedService, Decorated>();

// Then, decorate Decorated with the Decorator type.
collection.Decorate<IDecoratedService, Decorator>();

// 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<IDecoratedService>((inner, provider) => new OtherDecorator(inner, provider.GetRequiredService<IService>()));

var serviceProvider = collection.BuildServiceProvider();

// When we resolve the IDecoratedService service, we'll get the following structure:
// OtherDecorator -> Decorator -> Decorated
var instance = serviceProvider.GetRequiredService<IDecoratedService>();