docs: Improved DI documentation (#2407)

This commit is contained in:
Armano den Boef
2022-08-02 11:20:27 +02:00
committed by GitHub
parent 503fa755a0
commit 6fdcf98240
28 changed files with 460 additions and 198 deletions

View File

@@ -0,0 +1,9 @@
async Task RunAsync()
{
//...
await _serviceProvider.GetRequiredService<ServiceActivator>()
.ActivateAsync();
//...
}

View File

@@ -0,0 +1,13 @@
static IServiceProvider CreateServices()
{
var config = new DiscordSocketConfig()
{
//...
};
var collection = new ServiceCollection()
.AddSingleton(config)
.AddSingleton<DiscordSocketClient>();
return collection.BuildServiceProvider();
}

View File

@@ -0,0 +1,14 @@
public class ClientHandler
{
private readonly DiscordSocketClient _client;
public ClientHandler(DiscordSocketClient client)
{
_client = client;
}
public async Task ConfigureAsync()
{
//...
}
}

View File

@@ -0,0 +1,18 @@
public class ServiceActivator
{
// This contains *all* registered services of serviceType IService
private readonly IEnumerable<IService> _services;
public ServiceActivator(IEnumerable<IService> services)
{
_services = services;
}
public async Task ActivateAsync()
{
foreach(var service in _services)
{
await service.StartAsync();
}
}
}

View File

@@ -0,0 +1,12 @@
public static ServiceCollection RegisterImplicitServices(this ServiceCollection collection, Type interfaceType, Type activatorType)
{
// Get all types in the executing assembly. There are many ways to do this, but this is fastest.
foreach (var type in typeof(Program).Assembly.GetTypes())
{
if (interfaceType.IsAssignableFrom(type) && !type.IsAbstract)
collection.AddSingleton(interfaceType, type);
}
// Register the activator so you can activate the instances.
collection.AddSingleton(activatorType);
}

View File

@@ -0,0 +1,16 @@
public class MyModule : InteractionModuleBase
{
private readonly MyService _service;
public MyModule(MyService service)
{
_service = service;
}
[SlashCommand("things", "Shows things")]
public async Task ThingsAsync()
{
var str = string.Join("\n", _service.Things)
await RespondAsync(str);
}
}

View File

@@ -0,0 +1,24 @@
public class Program
{
private readonly IServiceProvider _serviceProvider;
public Program()
{
_serviceProvider = CreateProvider();
}
static void Main(string[] args)
=> new Program().RunAsync(args).GetAwaiter().GetResult();
static IServiceProvider CreateProvider()
{
var collection = new ServiceCollection();
//...
return collection.BuildServiceProvider();
}
async Task RunAsync(string[] args)
{
//...
}
}

View File

@@ -0,0 +1,9 @@
public class ClientHandler
{
public DiscordSocketClient Client { get; set; }
public async Task ConfigureAsync()
{
//...
}
}

View File

@@ -0,0 +1,26 @@
public class UtilizingProvider
{
private readonly IServiceProvider _provider;
private readonly AnyService _service;
// This service is allowed to be null because it is only populated if the service is actually available in the provider.
private readonly AnyOtherService? _otherService;
// This constructor injects only the service provider,
// and uses it to populate the other dependencies.
public UtilizingProvider(IServiceProvider provider)
{
_provider = provider;
_service = provider.GetRequiredService<AnyService>();
_otherService = provider.GetService<AnyOtherService>();
}
// This constructor injects the service provider, and AnyService,
// making sure that AnyService is not null without having to call GetRequiredService
public UtilizingProvider(IServiceProvider provider, AnyService service)
{
_provider = provider;
_service = service;
_otherService = provider.GetService<AnyOtherService>();
}
}

View File

@@ -0,0 +1,17 @@
async Task RunAsync(string[] args)
{
// Request the instance from the client.
// Because we're requesting it here first, its targetted constructor will be called and we will receive an active instance.
var client = _services.GetRequiredService<DiscordSocketClient>();
client.Log += async (msg) =>
{
await Task.CompletedTask;
Console.WriteLine(msg);
}
await client.LoginAsync(TokenType.Bot, "");
await client.StartAsync();
await Task.Delay(Timeout.Infinite);
}

View File

@@ -0,0 +1,6 @@
// With serviceType:
collection.AddScoped<IScopedService, ScopedService>();
// Without serviceType:
collection.AddScoped<ScopedService>();

View File

@@ -0,0 +1,21 @@
static IServiceProvider CreateServices()
{
var config = new DiscordSocketConfig()
{
//...
};
// X represents either Interaction or Command, as it functions the exact same for both types.
var servConfig = new XServiceConfig()
{
//...
}
var collection = new ServiceCollection()
.AddSingleton(config)
.AddSingleton<DiscordSocketClient>()
.AddSingleton(servConfig)
.AddSingleton<XService>();
return collection.BuildServiceProvider();
}

View File

@@ -0,0 +1,9 @@
public class MyService
{
public List<string> Things { get; }
public MyService()
{
Things = new();
}
}

View File

@@ -0,0 +1,6 @@
// With serviceType:
collection.AddSingleton<ISingletonService, SingletonService>();
// Without serviceType:
collection.AddSingleton<SingletonService>();

View File

@@ -0,0 +1,6 @@
// With serviceType:
collection.AddTransient<ITransientService, TransientService>();
// Without serviceType:
collection.AddTransient<TransientService>();