FAQ rework, replacing outdated info, better interaction FAQ (#2106)

* FAQ rework, replacing outdated info, better interaction faq

* Update docs/faq/basics/getting-started.md

Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com>

* Update docs/faq/basics/getting-started.md

Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com>

* Update docs/faq/int_framework/general.md

Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com>

* fix TOC reference

Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com>
Co-authored-by: Quin Lynch <lynchquin@gmail.com>
This commit is contained in:
Armano den Boef
2022-03-02 21:24:34 +01:00
committed by GitHub
parent b7f6db96ef
commit a13dce2550
20 changed files with 178 additions and 96 deletions

View File

@@ -0,0 +1,46 @@
---
uid: FAQ.Basics.DI
title: Questions about Dependency Injection.
---
# Dependency-injection-related Questions
In the following section, you will find common questions and answers
to utilizing dependency injection with @Discord.Commands and @Discord.Interactions, as well as
common troubleshooting steps regarding DI.
## What is a service? Why does my module not hold any data after execution?
In Discord.Net, modules are created similarly to ASP.NET, meaning
that they have a transient nature; modules are spawned whenever a
request is received, and are killed from memory when the execution
finishes. In other words, you cannot store persistent
data inside a module. Consider using a service if you wish to
workaround this.
Service is often used to hold data externally so that they persist
throughout execution. Think of it like a chest that holds
whatever you throw at it that won't be affected by anything unless
you want it to. Note that you should also learn Microsoft's
implementation of [Dependency Injection] \([video]) before proceeding.
A brief example of service and dependency injection can be seen below.
[!code-csharp[DI](samples/DI.cs)]
[Dependency Injection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
[video]: https://www.youtube.com/watch?v=QtDTfn8YxXg
## Why is my Command/Interaction Service complaining about a missing dependency?
If you encounter an error similar to `Failed to create MyModule,
dependency MyExternalDependency was not found.`, you may have
forgotten to add the external dependency to the dependency container.
For example, if your module, `MyModule`, requests a `DatabaseService`
in its constructor, the `DatabaseService` must be present in the
[IServiceProvider] when registering `MyModule`.
[!code-csharp[Missing Dependencies](samples/missing-dep.cs)]
[IServiceProvider]: xref:System.IServiceProvider

View File

@@ -11,18 +11,32 @@ introduction to the Discord API ecosystem.
## How do I add my bot to my server/guild?
You can do so by using the [permission calculator] provided
by [FiniteReality].
This tool allows you to set permissions that the bot will be assigned
with, and invite the bot into your guild. With this method, bots will
also be assigned a unique role that a regular user cannot use; this
is what we call a `Managed` role. Because you cannot assign this
role to any other users, it is much safer than creating a single
role which, intentionally or not, can be applied to other users
to escalate their privilege.
Inviting your bot can be done by using the OAuth2 url generator provided by the [Discord Developer Portal].
[FiniteReality]: https://github.com/FiniteReality/permissions-calculator
[permission calculator]: https://finitereality.github.io/permissions-calculator
Permissions can be granted by selecting the `bot` scope in the scopes section.
![Scopes](images/scopes.png)
A permissions tab will appear below the scope selection,
from which you can pick any permissions your bot may require to function.
When invited, the role this bot is granted will include these permissions.
If you grant no permissions, no role will be created for your bot upon invitation as there is no need for one.
![Permissions](images/permissions.png)
When done selecting permissions, you can use the link below in your browser to invite the bot
to servers where you have the `Manage Server` permission.
![Invite](images/link.png)
If you are planning to play around with slash/context commands,
make sure to check the `application commands` scope before inviting your bot!
> [!NOTE]
> You do not have to kick and reinvite your bot to update permissions/scopes later on.
> Simply reusing the invite link with provided scopes/perms will update it accordingly.
[Discord Developer Portal]: https://discord.com/developers/applications/
## What is a token?

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,88 +0,0 @@
---
uid: FAQ.Basics.InteractionBasics
title: Basics of interactions, common practice
---
# Interactions basics, where to get started
This section answers basic questions and common mistakes in handling application commands, and responding to them.
## What's the difference between RespondAsync, DeferAsync and FollowupAsync?
The difference between these 3 functions is in how you handle the command response.
[RespondAsync] and
[DeferAsync] let the API know you have succesfully received the command. This is also called 'acknowledging' a command.
DeferAsync will not send out a response, RespondAsync will.
[FollowupAsync] follows up on succesful acknowledgement.
> [!WARNING]
> If you have not acknowledged the command FollowupAsync will not work! the interaction has not been resonded to, so you cannot follow it up!
[RespondAsync]: xref:Discord.IDiscordInteraction
[DeferAsync]: xref:Discord.IDiscordInteraction
[FollowUpAsync]: xref:Discord.IDiscordInteraction
## Im getting System.TimeoutException: 'Cannot respond to an interaction after 3 seconds!'
This happens because your computers clock is out of sync or your trying to respond after 3 seconds. If your clock is out of sync and you cant fix it, you can set the `UseInteractionSnowflakeDate` to false in the config.
## Bad form Exception when I try to create my commands, why do I get this?
Bad form exceptions are thrown if the slash, user or message command builder has invalid values.
The following options could resolve your error.
#### Is your command name lowercase?
If your command name is not lowercase, it is not seen as a valid command entry.
`Avatar` is invalid; `avatar` is valid.
#### Are your values below or above the required amount? (This also applies to message components)
Discord expects all values to be below maximum allowed.
Going over this maximum amount of characters causes an exception.
> [!NOTE]
> All maximum and minimum value requirements can be found in the [Discord Developer Docs].
> For components, structure documentation is found [here].
[Discord Developer Docs]: https://discord.com/developers/docs/interactions/application-commands#application-commands
[here]: https://discord.com/developers/docs/interactions/message-components#message-components
#### Is your subcommand branching correct?
Branching structure is covered properly here: xref:Guides.SlashCommands.SubCommand
## My interaction commands are not showing up?
If you registered your commands globally, it can take up to 1 hour for them to register.
Did you register a guild command (should be instant), or waited more than an hour and still don't have them show up?
- Try to check for any errors in the console, there is a good chance something might have been thrown.
- Register your commands after the Ready event in the client. The client is not configured to register commands before this moment.
- Check if no bad form exception is thrown; If so, refer to the above question.
- Do you have the application commands scope checked when adding your bot to guilds?
![Scope check](images/scope.png)
## There are many options for creating commands, which do I use?
[!code-csharp[Register examples](samples/registerint.cs)]
> [!NOTE]
> You can use bulkoverwrite even if there are no commands in guild, nor globally.
> The bulkoverwrite method disposes the old set of commands and replaces it with the new.
## Do I need to create commands on startup?
If you are registering your commands for the first time, it is required to create them once.
After this, commands will exist indefinitely until you overwrite them.
Overwriting is only required if you make changes to existing commands, or add new ones.
## I can't see all of my user/message commands, why?
Message and user commands have a limit of 5 per guild, and another 5 globally.
If you have more than 5 guild-only message commands being registered, no more than 5 will actually show up.
You can get up to 10 entries to show if you register 5 per guild, and another 5 globally.

View File

@@ -0,0 +1,28 @@
public class MyService
{
public string MyCoolString { get; set; }
}
public class Setup
{
public IServiceProvider BuildProvider() =>
new ServiceCollection()
.AddSingleton<MyService>()
.BuildServiceProvider();
}
public class MyModule : ModuleBase<SocketCommandContext>
{
// Inject via public settable prop
public MyService MyService { get; set; }
// ...or via the module's constructor
// private readonly MyService _myService;
// public MyModule (MyService myService) => _myService = myService;
[Command("string")]
public Task GetOrSetStringAsync(string input)
{
if (string.IsNullOrEmpty(_myService.MyCoolString)) _myService.MyCoolString = input;
return ReplyAsync(_myService.MyCoolString);
}
}

View File

@@ -0,0 +1,32 @@
public class MyModule : ModuleBase<SocketCommandContext>
{
private readonly DatabaseService _dbService;
public MyModule(DatabaseService dbService)
=> _dbService = dbService;
}
public class CommandHandler
{
private readonly CommandService _commands;
private readonly IServiceProvider _services;
public CommandHandler(DiscordSocketClient client)
{
_services = new ServiceCollection()
.AddSingleton<CommandService>()
.AddSingleton(client)
// We are missing DatabaseService!
.BuildServiceProvider();
}
public async Task RegisterCommandsAsync()
{
// ...
// The method fails here because DatabaseService is a required
// dependency and cannot be resolved by the dependency
// injection service at runtime since the service is not
// registered in this instance of _services.
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
// ...
// The same approach applies to the interaction service.
// Make sure to resolve these issues!
}
}

View File

@@ -1,21 +0,0 @@
private async Task ReadyAsync()
{
// pull your commands from some array, everyone has a different approach for this.
var commands = _builders.ToArray();
// write your list of commands globally in one go.
await _client.Rest.BulkOverwriteGlobalCommands(commands);
// write your array of commands to one guild in one go.
// You can do a foreach (... in _client.Guilds) approach to write to all guilds.
await _client.Rest.BulkOverwriteGuildCommands(commands, /* some guild ID */);
foreach (var c in commands)
{
// Create a global command, repeating usage for multiple commands.
await _client.Rest.CreateGlobalCommand(c);
// Create a guild command, repeating usage for multiple commands.
await _client.Rest.CreateGuildCommand(c, guildId);
}
}