Rystem.DependencyInjection 9.0.0

dotnet add package Rystem.DependencyInjection --version 9.0.0                
NuGet\Install-Package Rystem.DependencyInjection -Version 9.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Rystem.DependencyInjection" Version="9.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Rystem.DependencyInjection --version 9.0.0                
#r "nuget: Rystem.DependencyInjection, 9.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Rystem.DependencyInjection as a Cake Addin
#addin nuget:?package=Rystem.DependencyInjection&version=9.0.0

// Install Rystem.DependencyInjection as a Cake Tool
#tool nuget:?package=Rystem.DependencyInjection&version=9.0.0                

What is Rystem?

Get Started

Dependency injection extensions

Warm up

When you use the DI pattern in your .Net application you could need a warm up after the build of your services. And with Rystem you can simply do it.

builder.Services.AddWarmUp(() => somethingToDo());

and after the build use the warm up

var app = builder.Build();
await app.Services.WarmUpAsync();

Population service

You can use the population service to create a list of random value of a specific Type. An example from unit test explains how to use the service.

IServiceCollection services = new ServiceCollection();
services.AddPopulationService();
var serviceProvider = services.BuildServiceProvider().CreateScope().ServiceProvider;
var populatedModel = serviceProvider.GetService<IPopulation<PopulationModelTest>>();
IPopulation<PopulationModelTest> allPrepopulation = populatedModel!
    .Setup()
    .WithPattern(x => x.J!.First().A, "[a-z]{4,5}")
        .WithPattern(x => x.Y!.First().Value.A, "[a-z]{4,5}")
        .WithImplementation(x => x.I, typeof(MyInnerInterfaceImplementation))
        .WithPattern(x => x.I!.A!, "[a-z]{4,5}")
        .WithPattern(x => x.II!.A!, "[a-z]{4,5}")
        .WithImplementation<IInnerInterface, MyInnerInterfaceImplementation>(x => x.I!);
var all = allPrepopulation.Populate();

Abstract factory

You can use this abstract factory solution when you need to setup more than one service of the same kind and you need to distinguish them by a name.

I have an interface

public interface IMyService
{
    string GetName();
}

Some options for every service

public class SingletonOption
{
    public string ServiceName { get; set; }
}
public class TransientOption
{
    public string ServiceName { get; set; }
}
public class ScopedOption
{
    public string ServiceName { get; set; }
}

with built options which is a IServiceOptions, a options class that ends up with another class. Used for example when you have to add a settings like a connection string but you want to use a service like a client that uses that connection string.

public class BuiltScopedOptions : IServiceOptions<ScopedOption>
{
    public string ServiceName { get; set; }

    public Task<Func<ScopedOption>> BuildAsync()
    {
        return Task.FromResult(() => new ScopedOption
        {
            ServiceName = ServiceName
        });
    }
}

And six different services

public class SingletonService : IMyService, IServiceWithOptions<SingletonOption>
{
    public SingletonOption Options { get; set; }
    public string Id { get; } = Guid.NewGuid().ToString();
    public string GetName()
    {
        return $"{Options.ServiceName} with id {Id}";
    }
}
public class TransientService : IMyService, IServiceWithOptions<TransientOption>
{
    public TransientOption Options { get; set; }
    public string Id { get; } = Guid.NewGuid().ToString();
    public string GetName()
    {
        return $"{Options.ServiceName} with id {Id}";
    }
}
public class ScopedService : IMyService, IServiceWithOptions<ScopedOption>
{
    public ScopedOption Options { get; set; }
    public string Id { get; } = Guid.NewGuid().ToString();
    public string GetName()
    {
        return $"{Options.ServiceName} with id {Id}";
    }
}
public class ScopedService2 : IMyService, IServiceWithOptions<ScopedOption>
{
    public ScopedOption Options { get; set; }
    public string Id { get; } = Guid.NewGuid().ToString();

    public string GetName()
    {
        return $"{Options.ServiceName} with id {Id}";
    }
}
public class ScopedService3 : IMyService, IServiceWithOptions<ScopedOption>
{
    public ScopedOption Options { get; set; }
    public string Id { get; } = Guid.NewGuid().ToString();

    public string GetName()
    {
        return $"{Options.ServiceName} with id {Id}";
    }
}
public class ScopedService4 : IMyService, IServiceWithOptions<ScopedOption>
{
    public ScopedOption Options { get; set; }
    public string Id { get; } = Guid.NewGuid().ToString();

    public string GetName()
    {
        return $"{Options.ServiceName} with id {Id}";
    }
}

I can setup them in this way

var services = new ServiceCollection();
services.AddFactory<IMyService, SingletonService, SingletonOption>(x =>
{
    x.ServiceName = "singleton";
},
"singleton",
ServiceLifetime.Singleton);

services.AddFactory<IMyService, TransientService, TransientOption>(x =>
{
    x.ServiceName = "transient";
},
"transient",
ServiceLifetime.Transient);

services.AddFactory<IMyService, ScopedService, ScopedOption>(x =>
{
    x.ServiceName = "scoped";
},
"scoped",
ServiceLifetime.Scoped);

services.AddFactory<IMyService, ScopedService2, ScopedOption>(x =>
{
    x.ServiceName = "scoped2";
},
"scoped2",
ServiceLifetime.Scoped);

await services.AddFactoryAsync<IMyService, ScopedService3, BuiltScopedOptions, ScopedOption>(
    x =>
    {
        x.ServiceName = "scoped3";
    },
    "scoped3"
);

await services.AddFactoryAsync<IMyService, ScopedService3, BuiltScopedOptions, ScopedOption>(
    x =>
    {
        x.ServiceName = "scoped3_2";
    },
    "scoped3_2"
);

await services.AddFactoryAsync<IMyService, ScopedService4, BuiltScopedOptions, ScopedOption>(
    x =>
    {
        x.ServiceName = "scoped4";
    },
    "scoped4"
);

and use them in this way

var serviceProvider = services.BuildServiceProvider().CreateScope().ServiceProvider;
var factory = serviceProvider.GetService<IFactory<IMyService>>()!;
var factory2 = serviceProvider.GetService<IFactory<IMyService>>()!;

var singletonFromFactory = factory.Create("singleton").Id;
var singletonFromFactory2 = factory2.Create("singleton").Id;
var transientFromFactory = factory.Create("transient").Id;
var transientFromFactory2 = factory2.Create("transient").Id;
var scopedFromFactory = factory.Create("scoped").Id;
var scopedFromFactory2 = factory2.Create("scoped").Id;
var scoped2FromFactory = factory.Create("scoped2").Id;
var scoped2FromFactory2 = factory2.Create("scoped2").Id;
var scoped3FromFactory = factory.Create("scoped3").Id;
var scoped3FromFactory2 = factory2.Create("scoped3").Id;
var scoped3_2FromFactory = factory.Create("scoped3_2").Id;
var scoped3_2FromFactory2 = factory2.Create("scoped3_2").Id;
var scoped4FromFactory = factory.Create("scoped4").Id;
var scoped4FromFactory2 = factory2.Create("scoped4").Id;

Assert.Equal(singletonFromFactory, singletonFromFactory2);
Assert.NotEqual(transientFromFactory, transientFromFactory2);
Assert.Equal(scopedFromFactory, scopedFromFactory2);
Assert.Equal(scoped2FromFactory, scoped2FromFactory2);
Assert.NotEqual(scoped3FromFactory, scoped3FromFactory2);
Assert.NotEqual(scoped3_2FromFactory, scoped3_2FromFactory2);
Assert.NotEqual(scoped4FromFactory, scoped4FromFactory2);

Decorator

You may add a decoration for your services, based on the abstract factory integration. The decorator service replaces the previous version and receives it during the injection.

Setup

services
    .AddService<ITestWithoutFactoryService, TestWithoutFactoryService>(lifetime);
services
    .AddDecoration<ITestWithoutFactoryService, TestWithoutFactoryServiceDecorator>(null, lifetime);

Usage

var decorator = provider.GetRequiredService<ITestWithoutFactoryService>();
var previousService = provider.GetRequiredService<IDecoratedService<ITestWithoutFactoryService>>();

In decorator you may find the previousService in the method SetDecoratedService which runs in injection

public class TestWithoutFactoryServiceDecorator : ITestWithoutFactoryService, IDecoratorService<ITestWithoutFactoryService>
{
    public string Id { get; } = Guid.NewGuid().ToString();
    public ITestWithoutFactoryService Test { get; private set; }
    public void SetDecoratedService(ITestWithoutFactoryService service)
    {
        Test = service;
    }

    public void SetFactoryName(string name)
    {
        return;
    }
}

Decorator with Abstract Factory integration

You may add a decoration only for one service of your factory integration.

Setup

services.AddFactory<ITestService, TestService, TestOptions>(x =>
{
    x.ClassicName = classicName;
},
factoryName,
lifetime);
services
    .AddDecoration<ITestService, DecoratorTestService>(factoryName, lifetime);

Usage

var decoratorFactory = provider.GetRequiredService<IFactory<ITestService>>();
var decorator = decoratorFactory.Create(factoryName);
var previousService = decoratorFactory.CreateWithoutDecoration(factoryName);

Factory Fallback

You may add a fallback for your factory integration. The fallback service is called when the factory service key is not found.

services.AddFactoryFallback<TService, TFactoryFallback>();

where TFactoryFallback is class and an IFactoryFallback<TService>

You may add a fallback with an action fallback too.

services.AddActionAsFallbackWithServiceProvider<TService>(Func<FallbackBuilderForServiceProvider, TService> fallbackBuilder);

Scan dependency injection

You may scan your assemblies in search of types you need to add to dependency injection. For instance I have an interface IAnything and I need to add all classes which implements it.

public interface IAnything
{
}
internal class ScanModels : IAnything
{
}

and in service collection I can add it.

serviceCollection
    .Scan<IAnything>(ServiceLifetime.Scoped, typeof(IAnything).Assembly);

I can add to my class the interface IScannable of T to scan automatically. For instance.

public interface IAnything
{
}
internal class ScanModels : IAnything, IScannable<IAnything>
{
}

and in service collection I could add it in this way

serviceCollection
    .Scan(ServiceLifetime.Scoped, typeof(IAnything).Assembly);

Furthermore with ISingletonScannable, IScopedScannable and ITransientScannable I can override the service lifetime. For instance.

public interface IAnything
{
}
internal class ScanModels : IAnything, IScannable<IAnything>, ISingletonScannable
{
}

serviceCollection
    .Scan(ServiceLifetime.Scoped, typeof(IAnything).Assembly);

ScanModels will be installed as a Singleton service, overwriting the service lifetime from Scan method.

You also automatically use different assembly sources.

serviceCollection
    .ScanDependencyContext(ServiceLifetime.Scoped);

or

serviceCollection
    .ScanCallingAssembly(ServiceLifetime.Scoped);

or

serviceCollection
    .ScanCurrentDomain(ServiceLifetime.Scoped);

or

serviceCollection
    .ScanEntryAssembly(ServiceLifetime.Scoped);

or

serviceCollection
    .ScanExecutingAssembly(ServiceLifetime.Scoped);

or

serviceCollection
    .ScanFromType<T>(ServiceLifetime.Scoped);

or

serviceCollection
    .ScanFromTypes<T1, T2>(ServiceLifetime.Scoped);

Finally with ScanWithReferences you may call all the assemblies you want plus all referenced assemblies by them.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on Rystem.DependencyInjection:

Package Downloads
Rystem.RepositoryFramework.Abstractions

Rystem.RepositoryFramework allows you to use correctly concepts like repository pattern, CQRS and DDD. You have interfaces for your domains, auto-generated api, auto-generated HttpClient to simplify connection "api to front-end", a functionality for auto-population in memory of your models, a functionality to simulate exceptions and waiting time from external sources to improve your implementation/business test and load test.

Rystem.Api

Rystem.Api helps you to integrate Api Server and Automated Client for Aspect-Oriented programming.

Rystem.Content.Abstractions

Rystem.Content helps you to integrate with azure services or to create an abstraction layer among your infrastructure and your business.

Rystem.Authentication.Social

Rystem.Authentication.Social helps you to integrate with new .Net Identity system and social logins.

Rystem.Concurrency

Rystem.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
9.0.0 12,448 11/16/2024
9.0.0-rc.1 227 10/18/2024
6.2.0 219,453 10/9/2024
6.1.2 82 10/9/2024
6.1.1 380 10/9/2024
6.1.0 48,254 9/29/2024
6.0.24 628 9/11/2024
6.0.23 340,535 7/18/2024
6.0.22 83 7/18/2024
6.0.21 474 6/18/2024
6.0.20 728,093 6/16/2024
6.0.19 30,921 6/14/2024
6.0.18 440 6/14/2024
6.0.17 452 6/14/2024
6.0.16 50,315 6/10/2024
6.0.15 442 6/9/2024
6.0.14 94,778 5/24/2024
6.0.13 449 5/23/2024
6.0.12 366 5/23/2024
6.0.11 462 5/20/2024
6.0.9 481 5/19/2024
6.0.7 429 5/18/2024
6.0.6 417 5/10/2024
6.0.5 362 5/10/2024
6.0.4 550,443 4/3/2024
6.0.3 1,691 3/25/2024
6.0.2 380,397 3/11/2024
6.0.1 51,106 3/8/2024
6.0.0 1,171,774 11/21/2023
6.0.0-rc.6 187 10/25/2023
6.0.0-rc.5 123 10/25/2023
6.0.0-rc.4 104 10/23/2023
6.0.0-rc.3 99 10/19/2023
6.0.0-rc.2 173 10/18/2023
6.0.0-rc.1 194 10/16/2023
5.0.20 640,227 9/25/2023
5.0.19 2,861 9/10/2023
5.0.18 2,136 9/6/2023
5.0.17 2,019 9/6/2023
5.0.16 2,057 9/5/2023
5.0.15 2,025 9/5/2023
5.0.14 2,033 9/5/2023
5.0.13 2,136 9/1/2023
5.0.12 1,985 8/31/2023
5.0.11 1,993 8/30/2023
5.0.10 2,038 8/29/2023
5.0.9 2,073 8/24/2023
5.0.8 2,081 8/24/2023
5.0.7 451,537 8/23/2023