docs: Improved DI documentation (#2407)
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
---
|
||||
uid: Guides.TextCommands.DI
|
||||
title: Dependency Injection
|
||||
---
|
||||
|
||||
# Dependency Injection
|
||||
|
||||
The Text Command Service is bundled with a very barebone Dependency
|
||||
Injection service for your convenience. It is recommended that you use
|
||||
DI when writing your modules.
|
||||
|
||||
> [!WARNING]
|
||||
> If you were brought here from the Interaction Service guides,
|
||||
> make sure to replace all namespaces that imply `Discord.Commands` with `Discord.Interactions`
|
||||
|
||||
## Setup
|
||||
|
||||
1. Create a @Microsoft.Extensions.DependencyInjection.ServiceCollection.
|
||||
2. Add the dependencies to the service collection that you wish
|
||||
to use in the modules.
|
||||
3. Build the service collection into a service provider.
|
||||
4. Pass the service collection into @Discord.Commands.CommandService.AddModulesAsync* / @Discord.Commands.CommandService.AddModuleAsync* , @Discord.Commands.CommandService.ExecuteAsync* .
|
||||
|
||||
### Example - Setting up Injection
|
||||
|
||||
[!code-csharp[IServiceProvider Setup](samples/dependency-injection/dependency_map_setup.cs)]
|
||||
|
||||
## Usage in Modules
|
||||
|
||||
In the constructor of your module, any parameters will be filled in by
|
||||
the @System.IServiceProvider that you've passed.
|
||||
|
||||
Any publicly settable properties will also be filled in the same
|
||||
manner.
|
||||
|
||||
> [!NOTE]
|
||||
> Annotating a property with a [DontInjectAttribute] attribute will
|
||||
> prevent the property from being injected.
|
||||
|
||||
> [!NOTE]
|
||||
> If you accept `CommandService` or `IServiceProvider` as a parameter
|
||||
> in your constructor or as an injectable property, these entries will
|
||||
> be filled by the `CommandService` that the module is loaded from and
|
||||
> the `IServiceProvider` that is passed into it respectively.
|
||||
|
||||
### Example - Injection in Modules
|
||||
|
||||
[!code-csharp[Injection Modules](samples/dependency-injection/dependency_module.cs)]
|
||||
[!code-csharp[Disallow Dependency Injection](samples/dependency-injection/dependency_module_noinject.cs)]
|
||||
|
||||
[DontInjectAttribute]: xref:Discord.Commands.DontInjectAttribute
|
||||
@@ -187,7 +187,7 @@ service provider.
|
||||
|
||||
### Module Constructors
|
||||
|
||||
Modules are constructed using [Dependency Injection](xref:Guides.TextCommands.DI). Any parameters
|
||||
Modules are constructed using [Dependency Injection](xref:Guides.DI.Intro). Any parameters
|
||||
that are placed in the Module's constructor must be injected into an
|
||||
@System.IServiceProvider first.
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
public class Initialize
|
||||
{
|
||||
private readonly CommandService _commands;
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
// Ask if there are existing CommandService and DiscordSocketClient
|
||||
// instance. If there are, we retrieve them and add them to the
|
||||
// DI container; if not, we create our own.
|
||||
public Initialize(CommandService commands = null, DiscordSocketClient client = null)
|
||||
{
|
||||
_commands = commands ?? new CommandService();
|
||||
_client = client ?? new DiscordSocketClient();
|
||||
}
|
||||
|
||||
public IServiceProvider BuildServiceProvider() => new ServiceCollection()
|
||||
.AddSingleton(_client)
|
||||
.AddSingleton(_commands)
|
||||
// You can pass in an instance of the desired type
|
||||
.AddSingleton(new NotificationService())
|
||||
// ...or by using the generic method.
|
||||
//
|
||||
// The benefit of using the generic method is that
|
||||
// ASP.NET DI will attempt to inject the required
|
||||
// dependencies that are specified under the constructor
|
||||
// for us.
|
||||
.AddSingleton<DatabaseService>()
|
||||
.AddSingleton<CommandHandler>()
|
||||
.BuildServiceProvider();
|
||||
}
|
||||
public class CommandHandler
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IServiceProvider _services;
|
||||
|
||||
public CommandHandler(IServiceProvider services, CommandService commands, DiscordSocketClient client)
|
||||
{
|
||||
_commands = commands;
|
||||
_services = services;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
// Pass the service provider to the second parameter of
|
||||
// AddModulesAsync to inject dependencies to all modules
|
||||
// that may require them.
|
||||
await _commands.AddModulesAsync(
|
||||
assembly: Assembly.GetEntryAssembly(),
|
||||
services: _services);
|
||||
_client.MessageReceived += HandleCommandAsync;
|
||||
}
|
||||
|
||||
public async Task HandleCommandAsync(SocketMessage msg)
|
||||
{
|
||||
// ...
|
||||
// Pass the service provider to the ExecuteAsync method for
|
||||
// precondition checks.
|
||||
await _commands.ExecuteAsync(
|
||||
context: context,
|
||||
argPos: argPos,
|
||||
services: _services);
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// After setting up dependency injection, modules will need to request
|
||||
// the dependencies to let the library know to pass
|
||||
// them along during execution.
|
||||
|
||||
// Dependency can be injected in two ways with Discord.Net.
|
||||
// You may inject any required dependencies via...
|
||||
// the module constructor
|
||||
// -or-
|
||||
// public settable properties
|
||||
|
||||
// Injection via constructor
|
||||
public class DatabaseModule : ModuleBase<SocketCommandContext>
|
||||
{
|
||||
private readonly DatabaseService _database;
|
||||
public DatabaseModule(DatabaseService database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
[Command("read")]
|
||||
public async Task ReadFromDbAsync()
|
||||
{
|
||||
await ReplyAsync(_database.GetData());
|
||||
}
|
||||
}
|
||||
|
||||
// Injection via public settable properties
|
||||
public class DatabaseModule : ModuleBase<SocketCommandContext>
|
||||
{
|
||||
public DatabaseService DbService { get; set; }
|
||||
|
||||
[Command("read")]
|
||||
public async Task ReadFromDbAsync()
|
||||
{
|
||||
await ReplyAsync(DbService.GetData());
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Sometimes injecting dependencies automatically with the provided
|
||||
// methods in the prior example may not be desired.
|
||||
|
||||
// You may explicitly tell Discord.Net to **not** inject the properties
|
||||
// by either...
|
||||
// restricting the access modifier
|
||||
// -or-
|
||||
// applying DontInjectAttribute to the property
|
||||
|
||||
// Restricting the access modifier of the property
|
||||
public class ImageModule : ModuleBase<SocketCommandContext>
|
||||
{
|
||||
public ImageService ImageService { get; }
|
||||
public ImageModule()
|
||||
{
|
||||
ImageService = new ImageService();
|
||||
}
|
||||
}
|
||||
|
||||
// Applying DontInjectAttribute
|
||||
public class ImageModule : ModuleBase<SocketCommandContext>
|
||||
{
|
||||
[DontInject]
|
||||
public ImageService ImageService { get; set; }
|
||||
public ImageModule()
|
||||
{
|
||||
ImageService = new ImageService();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user