Discord bot v C# je konzolová aplikace v .NET, která drží jedno odchozí spojení WebSocket s gateway Discordu a reaguje na události. Vyber si knihovnu - Discord.Net je nejrozšířenější a nejlépe zdokumentovaná, DSharpPlus je dlouholetá alternativa, NetCord je nejnovější a vznikl pro moderní .NET - zapni jen ty gateway intents, které opravdu potřebuješ, registruj slash příkazy místo parsování textu zpráv a celé to spusť pod .NET Generic Host, aby se správně spouštělo, logovalo a ukončovalo. Nepotřebuje žádný příchozí port, jen minimum CPU a u většiny botů 60 až 200 MB paměti, a proto obvykle stačí nejmenší hostingový tarif.
V tomto článku postavíme bota s Discord.Net od prázdného projektu po slash příkaz a pak si ukážeme, co se změní, když poběží na serveru nepřetržitě.
Výběr knihovny#
Všechny tři knihovny pokrývají gateway, REST API, slash příkazy, tlačítka, výběrová menu a modální okna. Liší se zralostí, stylem a tím, jak rychle sledují nejnovější funkce Discordu.
| Knihovna | Balíček | Styl | Poznámky |
|---|---|---|---|
| Discord.Net | Discord.Net | Založená na událostech, zralá | Největší základna uživatelů a nejvíc příkladů |
| DSharpPlus | DSharpPlus | Založená na událostech, rozšiřující balíčky | Verze 5 je dlouho v prerelease; zjisti, ze které vycházejí návody |
| NetCord | NetCord | Moderní .NET, hosting na prvním místě | Novější, cílí jen na aktuální .NET, blízko API Discordu |
Vyber Discord.Net, pokud chceš mít odpověď na jakoukoli otázku na jedno vyhledání. Vyber NetCord, pokud začínáš od nuly na .NET 8 nebo novějším a líbí se ti knihovny postavené od začátku na dependency injection a Generic Host. DSharpPlus zvol, pokud ho už znáš; jinak si před rozhodnutím ověř aktuální stav jeho verze 5, protože příklady psané pro verzi 4 se přímo nepřenesou.
Příklady níže používají Discord.Net 3.x. Koncepty - intents, registrace příkazů, potvrzování interakcí, host - patří Discordu, ne knihovně, a platí pro všechny tři.
Aplikace, token a intents#
Než napíšeš první řádek kódu, vytvoř bota ve Discord Developer Portal:
- Vytvoř New Application a otevři stránku Bot.
- Resetuj a zkopíruj token. Zobrazí se jen jednou. Kdokoli, kdo ho má, může jednat jako tvůj bot na každém serveru, kde je.
- Zapni privilegované intents, které bot potřebuje (viz níže).
- V části OAuth2 vygeneruj pozvánkový odkaz s rozsahy
botaapplications.commandsa jen s oprávněními, která bot skutečně používá. Otevři ho a přidej bota na testovací server.
Intents určují, jaké události ti Discord posílá. Většina je běžných, tři jsou privilegované a musí se navíc zapnout v portálu:
| Intent | Privilegovaný | K čemu ho potřebuješ |
|---|---|---|
Guilds | Ne | Téměř ke všemu - data o serverech a kanálech |
GuildMessages | Ne | Události zpráv na serverech |
MessageContent | Ano | Text zpráv, které nejsou adresované botovi |
GuildMembers | Ano | Události připojení a odchodu členů, úplné seznamy členů |
GuildPresences | Ano | Stav online a aktivity |
Na MessageContent narazí každý. Bez něj události zpráv stále chodí, ale Content je prázdný řetězec, kromě zpráv, které botovi zmiňují, a přímých zpráv jemu. Bot postavený na slash příkazech ho nepotřebuje vůbec, což je hlavní důvod stavět na slash příkazech. Jakmile je bot ve 100 nebo více serverech, privilegované intents vyžadují schválení Discordu přes verifikaci bota, takže nežádej o to, co nepoužíváš.
Stejná zdrženlivost platí pro oprávnění v pozvánkovém odkazu. Je lákavé zaškrtnout Administrator, aby nikdy nic nespadlo na „Missing Permissions“, jenže z uniklého tokenu se tím z nepříjemnosti stane ztráta všech serverů, kde bot je: útočník s administrátorským botem může mazat kanály, banovat členy a rozdávat role. Přiděl konkrétní oprávnění, která příkazy používají - Send Messages, Embed Links, Manage Roles, pokud bot přiřazuje role - a pamatuj, že platí i hierarchie rolí: bot může spravovat jen role pod svou nejvyšší rolí, ať má jakákoli oprávnění. Subusers a nejnižší nutná oprávnění vede stejnou úvahu z pohledu hostingu.
Minimální bot na Generic Host#
Vytvoř projekt typu worker a přidej balíčky:
$ dotnet new worker -n TavernBot$ cd TavernBot$ dotnet add package Discord.NetGeneric Host ti zdarma dá konfiguraci, logování, dependency injection a čisté ukončení. Samotný bot je hostovaná služba, která při startu hostu spustí klienta a při jeho zastavení ho zastaví:
using Discord;using Discord.Interactions;using Discord.WebSocket;var builder = Host.CreateApplicationBuilder(args);builder.Services.AddSingleton(new DiscordSocketConfig{ GatewayIntents = GatewayIntents.Guilds});builder.Services.AddSingleton<DiscordSocketClient>();builder.Services.AddSingleton(sp => new InteractionService(sp.GetRequiredService<DiscordSocketClient>()));builder.Services.AddHostedService<BotService>();builder.Build().Run();public sealed class BotService( DiscordSocketClient client, InteractionService interactions, IServiceProvider services, IConfiguration config, ILogger<BotService> log) : IHostedService{ public async Task StartAsync(CancellationToken ct) { client.Log += m => { log.LogInformation("{Message}", m.ToString()); return Task.CompletedTask; }; await interactions.AddModulesAsync(typeof(BotService).Assembly, services); client.Ready += async () => await interactions.RegisterCommandsToGuildAsync(config.GetValue<ulong>("Discord:GuildId")); client.InteractionCreated += async i => await interactions.ExecuteCommandAsync(new SocketInteractionContext(client, i), services); await client.LoginAsync(TokenType.Bot, config["Discord:Token"]); await client.StartAsync(); } public async Task StopAsync(CancellationToken ct) { await client.StopAsync(); await client.LogoutAsync(); }}Spousta návodů host přeskočí a Main zakončí řádkem await Task.Delay(-1), aby proces zůstal naživu. Funguje to, dokud nepotřebuješ cokoli dalšího: nejde čistě ukončit, takže bota při každém restartu zabijí uprostřed požadavku; není dependency injection, takže každý modul si vytváří vlastní připojení k databázi; a není konfigurační systém, takže token skončí natvrdo v kódu. Host stojí tucet řádků navíc a všechny tři problémy odstraní. Navíc se stejný bot může později bez úprav přesunout do aplikace ASP.NET Core, protože webová aplikace je také Generic Host.
Token se čte z konfigurace, takže na serveru je to proměnná prostředí Discord__Token, nikdy řetězec v kódu. Konfigurace a secrets v ASP.NET Core vysvětluje dvojité podtržítko; stejný konfigurační systém běží i ve workeru. Pokud se token někdy dostane do veřejného repozitáře, okamžitě ho v portálu resetuj. Discord se účastní secret scanningu na GitHubu a uniklé tokeny často zneplatní sám, ale to je záchrana, ne plán.
Slash příkazy#
S interaction frameworkem je příkaz metoda v modulu:
public sealed class GeneralModule : InteractionModuleBase<SocketInteractionContext>{ [SlashCommand("ping", "Check the bot is alive")] public Task Ping() => RespondAsync($"Pong - {Context.Client.Latency} ms"); [SlashCommand("roll", "Roll a die")] public Task Roll([MinValue(2), MaxValue(100)] int sides = 6) => RespondAsync($"You rolled {Random.Shared.Next(1, sides + 1)}"); [SlashCommand("report", "Build a server report")] public async Task Report() { await DeferAsync(ephemeral: true); var text = await BuildSlowReportAsync(); await FollowupAsync(text, ephemeral: true); } private static async Task<string> BuildSlowReportAsync() { await Task.Delay(5000); return "All quiet."; }}Tři pravidla interakčního modelu Discordu určují podobu každého příkazu:
- Odpověz do tří sekund. Pokud příkaz potřebuje déle - dotaz do databáze, volání HTTP, cokoli pomalého - zavolej nejdřív
DeferAsync(). Uživatel uvidí „thinking“ a pak máš 15 minut na odeslání skutečné odpovědi přesFollowupAsync. Příkaz, který tři sekundy nestihne, zobrazí „The application did not respond“, i když tvůj kód o chvíli později úspěšně doběhne. - Příkazy registruj, nestačí je jen deklarovat. Discord musí o příkazu vědět, než ho uživatelé uvidí. Příklad registruje na jeden testovací server přes
RegisterCommandsToGuildAsync, což se projeví okamžitě. Pro produkci registruj globálně přesRegisterCommandsGloballyAsync; globální změny se historicky objevovaly pomaleji, takže vyvíjej proti jednomu serveru a při vydání přepni. - Neregistruj znovu při každém startu bez důvodu. Registrace nahradí celou sadu příkazů. Je to neškodné, ale je to volání API a bot, který padá ve smyčce a pokaždé se znovu registruje, je jedna z cest, jak narazit na rate limity Discordu.
Volby validuje Discord ještě předtím, než k tobě dorazí - MinValue a MaxValue výše se vynucují v klientovi - takže metoda dostane hodnoty v rozsahu. Tlačítka, výběrová menu a modální okna používají obslužné metody [ComponentInteraction] a [ModalInteraction] ve stejných modulech.
Provoz 24/7#
Gateway bot se připojuje k Discordu ven; dovnitř se nepřipojuje nic. Nepotřebuje port, doménu ani certifikát. Potřebuje proces, který běží a vrátí se, když spadne, a přesně to dělá hostingový panel. Hostování Discord bota 24/7 rozebírá obecné možnosti od starého PC po VDS.
Na panelu s nasazením přes Git spouštěcí příkaz bota publikuje a spustí:
dotnet publish -c Release -o out --disable-build-servers && exec dotnet out/TavernBot.dllexec udělá z bota hlavní proces, takže signál k zastavení z panelu dorazí do Generic Host, který zavolá StopAsync, a ta čistě zavře spojení s gateway. Bot zabitý bez toho nechá chvíli online „přízračnou“ přítomnost, dokud Discord spojení nevyprší.
Na čem na serveru záleží:
- Loguj do konzole. Konzolový logger hostu píše na stdout, který panel zobrazuje živě. Odpojení a opětovná připojení ke gateway jsou normální; Discord.Net je zaloguje a připojí se samo. Bot, který loguje reconnect každých pár sekund, má problém se sítí nebo s tokenem.
- Počítej s restarty. Nasazení, aktualizace a občasný pád proces restartují. Cokoli, co musí přežít - nastavení jednotlivých serverů, uživatelská data, cooldowny - ukládej mimo paměť.
- Měj samostatného testovacího bota. Vytvoř v Developer Portal druhou aplikaci pro vývoj, s vlastním tokenem, pozvanou jen na soukromý testovací server. Spouštět lokální kopii s produkčním tokenem znamená, že se dva procesy perou o jednu relaci gateway a že se na serverech tvé komunity objevují nedodělané příkazy.
- Neošetřené výjimky v obsluze událostí. Discord.Net spouští obslužné metody na vlastních taskách a výjimky z nich loguje, ale obsluha, která dlouho blokuje, zasekne gateway. Obsluhu drž krátkou a pomalou práci přesuň do úlohy na pozadí nebo do fronty, jak popisuje .NET worker služby a úlohy na pozadí.
Na RE:NODE tarif C# / .NET nasadí bota z repozitáře na GitHubu, převezme token jako proměnnou prostředí na záložce Startup a proces restartuje, pokud skončí. Deploy on push restartuje jen server, který už běžel, takže bot, kterého jsi zastavil záměrně, zůstane zastavený. Crash watcher počítá neočekávané restarty: tři za hodinu vyvolají varování na stránce serveru a automaticky otevřou ticket, díky čemuž si všimneš bota zaseknutého ve smyčce pádů. Výběr tarifu pro Discord bota se věnuje dimenzování.
Paměť, cache a sharding#
Paměť bota tvoří většinou cache stavu Discordu v knihovně: servery, kanály, role a - pokud o ně požádáš - členové a zprávy.
Nastavení (DiscordSocketConfig) | Výchozí | Vliv na paměť |
|---|---|---|
MessageCacheSize | 0 | Zprávy držené na kanál; 0 nedrží žádné |
AlwaysDownloadUsers | false | Stáhne při startu všechny členy všech serverů |
GatewayIntents | neprivilegovaná sada | Méně intents, méně událostí a méně v cache |
Bot v hrstce serverů s výchozím nastavením se pohodlně vejde pod 150 MB. Až zapnutí GuildMembers spolu s AlwaysDownloadUsers na serverech s desítkami tisíc členů žene bota do gigabajtů. Členy stahuj jen pro servery a chvíle, kdy je opravdu potřebuješ.
Projekt typu worker používá ve výchozím stavu Workstation GC, který drží paměť níž než aplikace ASP.NET Core; rozdíl vysvětluje paměť a garbage collection v .NET. Na RE:NODE se proces, který dosáhne limitu paměti tarifu, zastaví a čistě restartuje místo swapování, takže neomezeně rostoucí cache se projeví jako pravidelné restarty, ne jako pomalý bot.
Sharding rozdělí spojení s gateway do několika relací, z nichž každá obsluhuje část serverů. Discord ho vyžaduje od 2 500 serverů. Discord.Net k tomu nabízí DiscordShardedClient. Pod touto hranicí je jedno spojení jednodušší a naprosto dostačující.
Kde bot ukládá data#
Cokoli důležitého musí přežít proces. Možnosti seřazené podle pracnosti:
- Soubor JSON pro pár nastavení. Stačí, dokud do něj dva příkazy nezapisují současně; použij zámek.
- SQLite přes EF Core nebo
Microsoft.Data.Sqlite. Jeden soubor, žádný server, skutečné transakce. Soubor drž mimo složku, kterou nasazení nahrazuje. - Databázový server, jakmile data čte víc než jeden proces nebo když chceš, aby se o zálohy postaral někdo jiný. Tarif aplikace tady obsahuje dva databázové sloty s vygenerovanými přihlašovacími údaji; poskytovatele popisuje .NET s PostgreSQL, MySQL nebo SQL Server.
Cooldowny a rate limity na uživatele mohou žít v paměti, pokud je přijatelné o ně při restartu přijít, což u bota obvykle je.
Řešení potíží#
Bot je online, ale slash příkazy se nezobrazují. Nebyly zaregistrované, byly zaregistrované na jiný server, nebo pozvánce chybělo oprávnění applications.commands. Pozvi bota znovu s oběma rozsahy a ověř, že volání registrace v obslužné metodě Ready proběhlo bez chyby v logu.
„The application did not respond“. Příkaz trval déle než tři sekundy bez deferu, nebo vyhodil výjimku dřív, než odpověděl. Podívej se do logu a pak přidej DeferAsync() ke všemu, co dělá I/O.
Obsah zprávy je prázdný. Intent MessageContent chybí v kódu, v portálu, nebo v obou. Případně funkci přesuň do slash příkazu.
„Authentication failed“ nebo 401 při přihlášení. Token je špatný, má z proměnné prostředí navíc uvozovku nebo mezeru, nebo byl resetovaný. Zkopíruj ho znovu.
Bot se opakovaně odpojuje. Běží dva procesy se stejným tokenem - často zapomenutá lokální kopie a kopie na serveru - a Discord jeden z nich pořád zavírá. Lokální zastav.
FAQ#
Která knihovna je nejlepší pro prvního bota v C#?
Discord.Net, hlavně kvůli množství dostupných příkladů a odpovědí. NetCord je silná volba pro nového bota na aktuálním .NET, pokud ti Generic Host nedělá problém.
Potřebuje Discord bot veřejnou IP adresu nebo otevřený port?
Gateway bot ne, ten se připojuje ven. Veřejný HTTPS endpoint potřebuje jen bot, který přijímá interakce přes HTTP místo gateway; v tarifu aplikace ho může zajistit proxy slot s automatickým certifikátem.
Kolik paměti potřebuje Discord bot v C#?
Obvykle 60 až 200 MB u bota v mírném počtu serverů s výchozí cache. Změní to až stahování úplných seznamů členů velkých serverů.
Můžu provozovat bota a webový dashboard v jedné aplikaci?
Ano. Použij aplikaci ASP.NET Core a zaregistruj v ní bota jako hostovanou službu; sdílejí konfiguraci i databázi. Dashboard pak potřebuje port a proxy slot, zatímco bot si drží odchozí spojení s gateway.
Proč se bot po zastavení ještě chvíli tváří jako online?
Byl zabitý, ne zastavený, takže nikdy nezavřel relaci s gateway a Discord čeká, až spojení vyprší. Ujisti se, že spouštěcí příkaz používá exec a host volá StopAsync.




Komentáře
Zcela anonymně: žádný účet, žádný e-mail, žádné cookie. Ukládáme jen jméno, které napíšeš, text a čas - nic dalšího. Počet odkazů je omezený a značkování se nevykresluje.