PyNurseInjector Features

PyNurseInjector provides a comprehensive set of features designed to simplify dependency injection in .NET applications while maintaining flexibility and performance.

Namespace-Based Registration

The most powerful feature of PyNurseInjector is the ability to automatically discover and register services based on namespaces.

How It Works

PyNurseInjector scans the specified namespace and automatically registers all classes that implement interfaces. This eliminates the need for manual registration of each service.

// Register all services in a namespace
services.AddServicesFrom("MyApp.Services");

// Register with specific lifetime
services.AddServicesFrom("MyApp.Repositories", ServiceLifetime.Scoped);

// Include sub-namespaces
services.AddServicesFrom("MyApp", deep: true);

Benefits

  • Zero manual registration required
  • Automatically discovers new services
  • Reduces startup configuration code
  • Enforces consistent namespace organization

Advanced Usage

// Register from multiple namespaces
services.AddServicesFrom("MyApp.Core.Services");
services.AddServicesFrom("MyApp.Infrastructure.Repositories");
services.AddServicesFrom("MyApp.External.Adapters");

// Use lambda for dynamic namespace selection
services.AddServicesFrom(type => type.Namespace?.StartsWith("MyApp.") ?? false);

Comprehensive Attribute System

PyNurseInjector provides a rich set of attributes for fine-grained control over service registration.

[RegisterAs] Attribute

Explicitly specify which interfaces a class should be registered as.

// Single interface registration
[RegisterAs(typeof(IUserService))]
public class UserService : IUserService, IDisposable
{
    // Only registered as IUserService, not IDisposable
}

// Multiple interface registration with different lifetimes
[RegisterAs(typeof(IEmailService), ServiceLifetime.Singleton)]
[RegisterAs(typeof(INotificationService), ServiceLifetime.Scoped)]
public class EmailService : IEmailService, INotificationService
{
    // Registered as both interfaces with different lifetimes
}

[ServiceLifeTime] Attribute

Override the default lifetime for a specific service.

[ServiceLifeTime(ServiceLifetime.Singleton)]
public class ConfigurationService : IConfigurationService
{
    // Always registered as Singleton
}

// Can be combined with RegisterAs
[RegisterAs(typeof(ICacheService))]
[ServiceLifeTime(ServiceLifetime.Singleton)]
public class MemoryCacheService : ICacheService { }

[DontRegister] Attribute

Exclude specific types from automatic registration.

[DontRegister]
public class LegacyService : IService
{
    // Won't be registered even if in scanned namespace
}

[DontRegister]
internal class TestHelper : IHelper
{
    // Useful for test utilities in production namespaces
}

Property & Field Injection

Eliminate constructor clutter with automatic property and field injection.

[InjectService] Attribute

Mark properties or fields to be automatically injected by the DI container.

public class OrderController : Controller
{
    // Property injection
    [InjectService] 
    public IOrderService OrderService { get; private set; }
    
    // Field injection
    [InjectService] 
    private readonly ILogger<OrderController> logger;
    
    [InjectService] 
    protected IEmailService emailService;
    
    public async Task<IActionResult> CreateOrder(OrderDto dto)
    {
        logger.LogInformation("Creating order");
        var order = await OrderService.CreateAsync(dto);
        await emailService.SendOrderConfirmation(order);
        return Ok(order);
    }
}

Benefits

  • Cleaner, more readable classes
  • No constructor parameter lists
  • Easy to add/remove dependencies
  • Works with inheritance hierarchies

Supported Access Modifiers

Property/field injection works with:

  • Public properties and fields
  • Protected properties and fields
  • Private properties and fields (with setter)
  • Readonly fields

Flexible Lifetime Management

PyNurseInjector provides multiple ways to control service lifetimes.

Supported Lifetimes

Transient

New instance created every time

ServiceLifetime.Transient

Scoped

One instance per request/scope

ServiceLifetime.Scoped

Singleton

Single instance for app lifetime

ServiceLifetime.Singleton

Lifetime Configuration Methods

1. Global Default

// Set default lifetime for namespace
services.AddServicesFrom("MyApp.Services", ServiceLifetime.Scoped);

2. Per-Type Override

[ServiceLifeTime(ServiceLifetime.Singleton)]
public class CacheService : ICacheService { }

3. Per-Interface Override

[RegisterAs(typeof(IService), ServiceLifetime.Singleton)]
[RegisterAs(typeof(IDisposable), ServiceLifetime.Transient)]
public class MyService : IService, IDisposable { }

Custom Configuration Options

Fine-tune registration behavior with powerful configuration options.

DotNurseInjectorOptions

Interface Selection

services.AddServicesFrom("MyApp.Services", options =>
{
    // Choose primary interface when multiple exist
    options.SelectInterface = interfaces => 
        interfaces.FirstOrDefault(i => i.Name.StartsWith("I"));
    
    // Or use custom logic
    options.SelectInterface = interfaces =>
        interfaces.OrderBy(i => i.Name.Length).FirstOrDefault();
});

Implementation Filtering

services.AddServicesFrom("MyApp.Services", options =>
{
    // Exclude certain implementations
    options.SelectImplementation = type => 
        !type.Name.Contains("Mock") && !type.Name.Contains("Test");
    
    // Only include specific patterns
    options.SelectImplementation = type =>
        type.Name.EndsWith("Service") || type.Name.EndsWith("Repository");
});

Base Type Filtering

services.AddServicesFrom("MyApp.Data", options =>
{
    // Only register types inheriting from BaseRepository
    options.ImplementationBase = typeof(BaseRepository);
});

Self Registration

services.AddServicesFrom("MyApp.Services", options =>
{
    // Also register implementation type itself
    options.SelfRegister = true;
});

// Allows both:
services.GetService<IUserService>();
services.GetService<UserService>();

Advanced Type Exploration

PyNurseInjector provides powerful type discovery capabilities.

Expression-Based Discovery

// Register using lambda expressions
services.AddServicesFrom(type => 
    type.Namespace != null && 
    type.Namespace.StartsWith("MyApp.") &&
    type.Name.EndsWith("Service"));

// Complex filtering
services.AddServicesFrom(type =>
{
    var hasInterface = type.GetInterfaces().Any();
    var isPublic = type.IsPublic;
    var notAbstract = !type.IsAbstract;
    var hasAttribute = type.GetCustomAttribute<ServiceAttribute>() != null;
    
    return hasInterface && isPublic && notAbstract && hasAttribute;
});

Assembly Scanning

// Scan specific assemblies
services.AddServicesFromAssembly(typeof(UserService).Assembly);

// Scan multiple assemblies
var assemblies = new[] 
{
    typeof(UserService).Assembly,
    typeof(ProductRepository).Assembly
};

foreach (var assembly in assemblies)
{
    services.AddServicesFromAssembly(assembly);
}

Performance Optimizations

PyNurseInjector is designed with performance in mind.

Optimizations

  • Reflection Caching: Type information is cached after first scan
  • Lazy Loading: Services are only instantiated when needed
  • Minimal Overhead: Property injection adds minimal runtime overhead
  • Smart Scanning: Efficient namespace filtering reduces scan time

Benchmark Results

Operation PyNurseInjector Manual Registration Difference
Startup (100 services) 12ms 8ms +4ms
Service Resolution 0.1μs 0.1μs ~0μs
Property Injection 0.3μs N/A +0.3μs

Compatibility

PyNurseInjector is designed to work seamlessly with the .NET ecosystem.

Framework Support

  • .NET 5.0+
  • .NET Core 3.1
  • ASP.NET Core 3.1+
  • .NET Standard 2.0+

Integration with Other DI Features

// Works alongside manual registration
services.AddServicesFrom("MyApp.Services");
services.AddSingleton<IExternalService, ExternalService>();

// Compatible with Options pattern
services.Configure<MyOptions>(configuration.GetSection("MyOptions"));

// Works with hosted services
services.AddHostedService<BackgroundWorker>();

// Supports factory patterns
services.AddSingleton<IServiceFactory>(provider => 
    new ServiceFactory(provider));

Third-Party Container Support

PyNurseInjector works with the default .NET DI container. For third-party containers like Autofac or Unity, use their respective registration methods after PyNurseInjector's initial registration.