Create a Discord bot in C# and .NET - Part 2

This is part 2 in the series of articles about creating a Discord bot in C# and .NET. In part 1 of the series, we completed our project setup in Visual Studio and created all the necessary information in the Discord developer portal. This article assumes you have a working console application and our bot's Discord token is stored in user secrets. This article will focus on the fundamentals of using the Discord.NET library to create a Discord bot from a console application. Then we'll finish off by creating a simple command called !echo which will repeat back what was said.

🧑🏻‍💻 Source code: https://github.com/adamstirtan/DiscordBotTutorial

🧠 Part 1: https://blog.adamstirtan.net/2023/10/create-discord-bot-in-c-and-net-part-1.html

🧠 Part 3: https://blog.adamstirtan.net/2023/10/create-discord-bot-in-c-and-net-part-3.html

Install the Discord.NET NuGet package

We're going to use Discord.NET, an unofficial .NET wrapper for the Discord API. It's a comprehensive library that provides a simple to use framework for working with the Discord API. By using this library, we can focus our attention on the bot's features, rather than the inner-workings of Discord's networking.

Using the dotnet CLI

dotnet add package Discord.NET

Using Visual Studio's package manager

Right click on your project and select "Manage NuGet Packages..."


Select Browse, then search for "Discord.NET" and select Install on the right hand side.

Creating a bot interface and class

We're going to use dependency injection (DI) as we build our bot. Dependency injection allows us to register interfaces and classes together. When we need an instance of a class to be created, it too may have dependencies in its constructor. This chain of requirements is solved using a dependency injection container which resolves each link in the chain on instantiation. 

We're going to create an interface for a bot that can start and stop. Then we'll register that interface alongside a class that implements it. Later on, we'll add more things to our dependency injection container such as services, commands and configuration.

Add the Microsoft.Extensions.DependencyInjection package

Just like before, add another package named Microsoft.Extensions.DependencyInjection. You can use the CLI or Visual Studio's package manager.

Create interface IBot.cs

Create class Bot.cs

Review

The Bot class now supports authenticating to Discord and we'll soon add a message handler so it can respond to users in the server. Let's look at each of the lines of StartAsync to understand what we've done. On line 35, the Discord token is retrieved from user secrets. If it isn't found, an exception is raised because it will be unable to login without it.

string discordToken = _configuration["DiscordToken"] ?? throw new Exception("Missing Discord Token");

On line 37, we set the _serviceProvider instance variable to our ServiceCollection. This variable will be provided when we instantiate the Bot class from Program.cs.

I've been saying the word "Commands" previously because that's how I think about bot behaviors. Someone in the server may issue a command and the bot can respond to that command. The Discord.NET library organizes commands in to modules. On Line 39 we are using the Discord.NET library's AddModulesAsync method which tells the application to look in the executing assembly for classes that match the Module interface. Later on, when someone issues a command our bot will create an instance of the correct module and all dependencies will be provided by the ServiceCollection.

await _commands.AddModulesAsync(Assembly.GetExecutingAssembly(), _serviceProvider);

The last two lines are straightforward. The bot logs in as a Bot account using the Discord token from user secrets. Finally, the bot is started and put in to a running state.

Implementing Program.cs

The modified Program.cs starts by creating a configuration by sourcing user secrets on line 16. The ServiceCollection is created next. We have added the configuration previously created along with a registration for our bot's interface and implementation. 

In the try/catch block, an IBot interface is resolved with the Bot class. It then calls StartAsync and then begins an infinite loop that allows us to gracefully stop the bot by pressing "Q" in the terminal.

Try it out! Starting your console application will now result in your bot joining your server.

Running the Discord console app. Press "Q" to stop.

Your bot's status indicator should be green

Creating the !echo command

Implementing a message handler

Before we create some commands we have to implement some logic for handling messages said in the server. I've created a method called HandleCommandAsync which ignores messages from bots and looks for commands that start with "!". When a command is found, the CommandService will use the dependency injection container to resolve the correct module and execute the command.

Creating the command/module

Create a directory in your project called Commands. Inside the Commands directory, create another folder called Echo. Finally, inside Echo, create a class called EchoCommand.cs.

Your project should look like this at this point.

The EchoCommand is a simple demonstration of receiving and executing a command. The logic in the command will be to act on messages of this format:

!echo <phrase>

If phrase is not supplied, there is nothing to echo back. If we have a phrase, then the bot will reply with that message.

Try it out!

Start your bot and have it join your server. When it's online type the !echo command and have it repeat something. Here's some ideas for extending this further:
  1. Try changing the command from !echo to !repeat or !say
  2. We used Administrator permissions for our bot, try adjusting the bot's settings so only certain roles can issue the command.
  3. Try using embeds instead of basic text messages to add images, titles, descriptions to your bot's messages.
Don't forget the source code is available here if you get stuck: https://github.com/adamstirtan/DiscordBotTutorial/tree/master/Part%202/DiscordBot

Comments

Popular posts from this blog

Create a Discord bot in C# and .NET - Part 1

Create a Discord bot in C# and .NET - Part 3