![]() |
VOOZH | about |
dotnet add package Nefarius.DSharpPlus.Interactivity.Extensions.Hosting --version 6.2.7
NuGet\Install-Package Nefarius.DSharpPlus.Interactivity.Extensions.Hosting -Version 6.2.7
<PackageReference Include="Nefarius.DSharpPlus.Interactivity.Extensions.Hosting" Version="6.2.7" />
<PackageVersion Include="Nefarius.DSharpPlus.Interactivity.Extensions.Hosting" Version="6.2.7" />Directory.Packages.props
<PackageReference Include="Nefarius.DSharpPlus.Interactivity.Extensions.Hosting" />Project file
paket add Nefarius.DSharpPlus.Interactivity.Extensions.Hosting --version 6.2.7
#r "nuget: Nefarius.DSharpPlus.Interactivity.Extensions.Hosting, 6.2.7"
#:package Nefarius.DSharpPlus.Interactivity.Extensions.Hosting@6.2.7
#addin nuget:?package=Nefarius.DSharpPlus.Interactivity.Extensions.Hosting&version=6.2.7Install as a Cake Addin
#tool nuget:?package=Nefarius.DSharpPlus.Interactivity.Extensions.Hosting&version=6.2.7Install as a Cake Tool
👁 .NET
👁 Static Badge
👁 GitHub
👁 Nuget
👁 Discord
An extension for DSharpPlus to make hosting a Discord bot in .NET Core Worker Services easier.
With DSharpPlus version 5 (onwards) the event handling design has been completely overhauled, making the core features of this project obsolete. Version 5 is also more tightly coupled to dependency injection, another great change. Therefore, I will no longer introduce any breaking changes nor try to make it v5 compatible. It's been a fun ride! This project's nuget versions 6.x build upon DSharpPlus 4.x. Older nuget versions are a bit chaotic, so I recommend you skip them 😁
This is not an official DSharpPlus extension, use it at your own risk!
This set of libraries abstracts away a lot of the plumbing code required to get DSharpPlus up and running in a .NET Core Worker Service (or simply a plain old Console Application) and provides Dependency-Injection-friendly integration.
It also offers a new feature/concept on top: event subscribers! Changes happening in the Discord universe are represented in DSharpPlus by a (rather large) number of events that can be subscribed to. The library offers an interface for every event of the Discord Client your "event subscriber" class can implement. These interface methods will be called when the corresponding event occurs. But there's a convenience extra: within the callback method you will have access to scoped services, like database contexts!
And if that wasn't enough, here's another one: intents will be automatically registered if you're using an interface/event that requires them! Yay automation!
I try my best to publish stable releases with every major DSharpPlus update. I try to stick to their Major.Minor
version prefixes, but the Build is out of sync as it increments every time I trigger a CI build. Overall, the library
is considered stable and production-ready. Even in pre-releases, I try to not introduce critical bugs or API-breaking
changes unless documented otherwise.
The core library for DSharpPlus required to set up a Discord client as a hosted service.
Optional. Adds support for DSharpPlus.CommandsNext extension.
Optional. Adds support for DSharpPlus.Interactivity extension.
Optional. Adds support for DSharpPlus.VoiceNext extension.
Optional. Adds support for DSharpPlus.SlashCommands extension.
If you're already familiar with .NET Core Workers or ASP.NET Core you'll have your bot up and running in seconds 👌
You can also take a look at of this repository.
Create a new .NET Core Worker project either via Visual Studio templates or using the command dotnet new worker in a
fresh directory.
Add the core hosting package (and optional extensions, if you need them) via NuGet package manager.
Most of the heavy lifting is done in the ConfigureServices method, so we will focus on that. To get a bare basic
Discord bot running, all you need to do is register the client service and the hosted background service:
//
// Adds DiscordClient singleton service you can use everywhere
//
services.AddDiscord(options =>
{
//
// Minimum required configuration
//
options.Token = "recommended to read bot token from configuration file";
});
//
// Automatically host service and connect to gateway on boot
//
services.AddDiscordHostedService();
That's pretty much it! When you launch your worker with a valid bot token you should see your bot come online in an instant, congratulations! ✨
Now to the actual convenience feature of this library! Creating one (or more) class(es) that handle events, like when a guild came online or a message got created. Let's wire one up that gets general guild and member change events:
// this does the same as calling
// services.AddDiscordGuildAvailableEventSubscriber<BotModuleForGuildAndMemberEvents>();
[DiscordGuildAvailableEventSubscriber]
// this does the same as calling
// services.AddDiscordGuildMemberAddedEventSubscriber<BotModuleForGuildAndMemberEvents>();
[DiscordGuildMemberAddedEventSubscriber]
internal class BotModuleForGuildAndMemberEvents :
// you can implement one or many interfaces for event handlers in one class
// or split it however you like. Your choice!
IDiscordGuildAvailableEventSubscriber,
IDiscordGuildMemberAddedEventSubscriber
{
private readonly ILogger<BotModuleForGuildAndMemberEvents> _logger;
/// <summary>
/// Optional constructor for Dependency Injection.
/// Parameters get populated automatically with your services.
/// </summary>
/// <param name="logger">The logger service instance.</param>
/// <param name="tracer">The tracer service instance.</param>
public BotModuleForGuildAndMemberEvents(
ILogger<BotModuleForGuildAndMemberEvents> logger
)
{
//
// Do whatever you like with these. It's recommended to not do heavy tasks in
// constructors, just store your service references for later use!
//
// You can inject scoped services like database contexts as well!
//
_logger = logger;
}
public Task DiscordOnGuildAvailable(DiscordClient sender, GuildCreateEventArgs args)
{
//
// To see some action, output the guild name
//
Console.WriteLine(args.Guild.Name);
//
// Usage of injected logger service
//
_logger.LogInformation("Guild {Guild} came online", args.Guild);
//
// Return successful execution
//
return Task.CompletedTask;
}
public Task DiscordOnGuildMemberAdded(DiscordClient sender, GuildMemberAddEventArgs args)
{
//
// Fired when a new member has joined, exciting!
//
_logger.LogInformation("New member {Member} joined!", args.Member);
//
// Return successful execution
//
return Task.CompletedTask;
}
}
Now let's dissect what is happening here. The class gets decorated by the attributes
DiscordGuildAvailableEventSubscriber and DiscordGuildMemberAddedEventSubscriber (hint: you can use only one
attribute for the event group you're interested in, you can use many more on the same class, doesn't matter, your
choice) which causes it to get automatically registered as subscribers for these events.
An alternative approach to registration is manually calling the extension methods, like
services.AddDiscordGuildAvailableEventSubscriber<BotModuleForGuildAndMemberEvents>();
services.AddDiscordGuildMemberAddedEventSubscriber<BotModuleForGuildAndMemberEvents>();
from within ConfigureServices. Using the attributes instead ensures you don't forget to register your subscribers
while coding vigorously!
Implementing the interfaces IDiscordGuildAvailableEventSubscriber and IDiscordGuildMemberEventsSubscriber ensures
your subscriber class is actually callable by the Discord Client Service. You must complete every event callback you're
not interested in with return Task.CompletedTask; as demonstrated or it will result in errors. In the example above we
are only interested in DiscordOnGuildAvailable and print the guild name to the console. I'm sure you can think of more
exciting tasks!
And last but not least; your subscriber classes are fully dependency-injection-aware! You can access services via classic constructor injection:
private readonly ILogger<BotModuleForGuildAndMemberEvents> _logger;
public BotModuleForGuildAndMemberEvents(
ILogger<BotModuleForGuildAndMemberEvents> logger
)
{
_logger = logger;
}
You can even inject scoped services, the subscriber objects get invoked in their own scope by default. This allows for easy access for e.g. database contexts within each subscriber. Neat!
The library tries to assume the required intents from the event subscribers used, but not all intents can be derived with that method. For example, if you need to read user message contents within a slash command module, you need to manually set the required intents on Discord initialization like so:
serviceCollection.AddDiscord(discordConfiguration =>
{
discordConfiguration.Intents = DiscordIntents.GuildMessages |
DiscordIntents.DirectMessages |
DiscordIntents.MessageContents;
});
Otherwise your code "might" work, but you'll experience weird side effects like empty message contents. If you do assign intents like demonstrated, they will be merged with your subscribers intents automatically, so you do not need to specify them manually again!
DiscordClientInject IDiscordClientService, there you can access the Client property.
Let's assume you have one or more slash command classes like the following:
[SlashCommandGroup("apply", "Apply for server membership.")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
public sealed class OnBoardingApplicationCommands : ApplicationCommandModule
{
[SlashRequirePermissions(Permissions.SendMessages)]
[SlashCommand("member", "Apply for regular membership.")]
public async Task Member(
InteractionContext ctx
)
{
...
You'd simply register it like so:
serviceCollection.AddDiscordSlashCommands(extension: extension =>
{
extension.RegisterCommands<OnBoardingApplicationCommands>();
});
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.2.7 | 661 | 5/30/2025 |
| 6.2.7-pre001 | 194 | 5/30/2025 |
| 6.2.6 | 248 | 5/30/2025 |
| 6.2.5 | 247 | 5/30/2025 |
| 6.2.4 | 255 | 5/30/2025 |
| 6.2.3 | 263 | 5/30/2025 |
| 6.2.2 | 229 | 5/30/2025 |
| 6.2.1 | 262 | 5/30/2025 |
| 6.2.0 | 359 | 4/23/2025 |
| 6.2.0-pre001 | 268 | 4/23/2025 |
| 6.1.0 | 286 | 4/18/2025 |
| 6.1.0-pre001 | 227 | 4/18/2025 |
| 6.0.1 | 366 | 2/22/2025 |
| 6.0.0 | 259 | 2/22/2025 |
| 6.0.0-pre001 | 171 | 2/22/2025 |
| 5.3.1-nightly.2 | 328 | 5/18/2024 |
| 5.3.1-nightly.1 | 153 | 2/26/2024 |
| 5.3.0 | 350 | 2/15/2024 |
| 5.2.0 | 306 | 2/1/2024 |
| 5.1.0 | 371 | 12/1/2023 |