因此该命令的工作原理如下。用户选择类别,然后键入查询。 Bot 使用 GraphQL 客户端搜索内容,发送包含 5 个结果的消息。用户现在单击 1-5 中的按钮来选择一个对象,机器人将编辑消息。第一次使用命令和按钮时,这完全可以正常工作。但是当第二次尝试整个过程时,机器人会在控制台中抛出消息 NotFound:
[2023-12-25 02:56:21 +01:00] [104 /EventHandler] [Error] Event handler exception for event COMPONENT_INTERACTED thrown from System.Threading.Tasks.Task <SearchCommand>b__0(DSharpPlus.DiscordClient, DSharpPlus.EventArgs.ComponentInteractionCreateEventArgs) (defined in AnimeSharpBot.SearchModule+<>c__DisplayClass0_0)
DSharpPlus.Exceptions.NotFoundException: Not found: 404
at DSharpPlus.Net.DiscordApiClient.CreateInteractionResponseAsync(UInt64 interaction_id, String interaction_token, InteractionResponseType type, DiscordInteractionResponseBuilder builder)
at AnimeSharpBot.SearchModule.ButtonClick(DiscordClient sender, ComponentInteractionCreateEventArgs e, IEnumerable`1 animeDetails) in C:\Users\mrady\RiderProjects\AnimeSharpBot\SearchModule.cs:line 110
at AnimeSharpBot.SearchModule.<>c__DisplayClass0_0.<<SearchCommand>b__0>d.MoveNext() in C:\Users\mrady\RiderProjects\AnimeSharpBot\SearchModule.cs:line 44
--- End of stack trace from previous location ---
at DSharpPlus.AsyncEvents.AsyncEvent`2.<>c__DisplayClass7_0.<<InvokeAsync>b__0>d.MoveNext()
这让我很困惑,因为该功能可以工作,但由于某种原因出现该错误。我该如何修复它?这是我的代码:
using System.Text;
using DSharpPlus;
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using AniListNet;
using AniListNet.Objects;
using AniListNet.Parameters;
using DSharpPlus.EventArgs;
namespace AnimeSharpBot;
public class SearchModule : ApplicationCommandModule
{
[SlashCommand("search", "Search for anime, manga, staff, character, or studio")]
public async Task SearchCommand(InteractionContext ctx,
[Option("category", "Category to search for")]
[Choice("Anime", "anime")]
[Choice("Manga", "manga")]
[Choice("Staff", "staff")]
[Choice("Character", "character")]
[Choice("Studio", "studio")]
string category,
[Option("query", "Search query")]
string query)
{
var (resultMessage, animeDetails) = await SearchAsync(category, query);
var row = new DiscordComponent[]
{
new DiscordButtonComponent(ButtonStyle.Primary, "option_1", "1"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_2", "2"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_3", "3"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_4", "4"),
new DiscordButtonComponent(ButtonStyle.Primary, "option_5", "5"),
};
var message = new DiscordMessageBuilder()
.WithContent(resultMessage)
.AddComponents(row)
.SendAsync(ctx.Channel);
var client = ctx.Client;
client.ComponentInteractionCreated += async (sender, e) =>
await ButtonClick(sender, e, animeDetails);
}
private async Task<(string ResultMessage, IEnumerable<Media> AnimeDetails)> SearchAsync(string category, string query)
{
var resultMessage = new StringBuilder();
var client = new AniClient();
IEnumerable<Media> animeDetails = null;
if (category.Equals("anime", StringComparison.OrdinalIgnoreCase))
{
var results = await client.SearchMediaAsync(new SearchMediaFilter
{
Query = query,
Type = MediaType.Anime,
Sort = MediaSort.Popularity,
Format = new Dictionary<MediaFormat, bool>
{
{ MediaFormat.TV, true },
{ MediaFormat.Movie, true },
{ MediaFormat.TVShort, true }
}
});
for (int i = 0; i < Math.Min(results.Data.Length, 5); i++)
{
var animeTitle = results.Data[i].Title.EnglishTitle;
resultMessage.AppendLine($"Result {i + 1}: {animeTitle}");
}
animeDetails = results.Data;
}
else if (category.Equals("manga", StringComparison.OrdinalIgnoreCase))
{
}
else if (category.Equals("staff", StringComparison.OrdinalIgnoreCase))
{
}
else if (category.Equals("character", StringComparison.OrdinalIgnoreCase))
{
}
else if (category.Equals("studio", StringComparison.OrdinalIgnoreCase))
{
}
else
{
return ("Please choose a valid category (anime, manga, staff, character, studio).", null);
}
return (resultMessage.ToString(), animeDetails);
}
private async Task ButtonClick(DiscordClient sender, ComponentInteractionCreateEventArgs e, IEnumerable<Media> animeDetails)
{
int selectedOption = int.Parse(e.Id.Substring("option_".Length));
var selectedAnime = animeDetails.ElementAtOrDefault(selectedOption - 1);
if (selectedAnime != null)
{
await e.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage,
new DiscordInteractionResponseBuilder().WithContent($"You selected option {selectedOption}! Here are the details:\n{selectedAnime.Title.EnglishTitle} (ID: {selectedAnime.Id})\n{selectedAnime.Description}"));
}
}
}
如果确实有问题,您可以提出除修复之外的任何建议。
你的错误根源可以在这里的代码中找到,我在引起错误的地方和问题根源处进行了评论
private async Task ButtonClick(DiscordClient sender, ComponentInteractionCreateEventArgs e,
IEnumerable<Media> animeDetails) //404 caused in second arg
{
int selectedOption = int.Parse(e.Id.Substring("option_".Length));
var selectedAnime = animeDetails.ElementAtOrDefault(selectedOption - 1);
if (selectedAnime != null)
{
await e.Interaction.CreateResponseAsync(InteractionResponseType.UpdateMessage, //404 source, I set the 3 second countdown right here
new DiscordInteractionResponseBuilder().WithContent($"You selected option {selectedOption}! Here are the details:\n{selectedAnime.Title.EnglishTitle} (ID: {selectedAnime.Id})\n{selectedAnime.Description}"));
}
}
当您在第一个
ComponentInteractionCreated
事件触发后超过 3 秒获取 ComponentInteractionCreateEventArgs
来调用 ComponentInteractionCreated
事件时,就会出现此问题。您可以通过使用 DeferredMessageUpdate
而不是 UpdateMessage
来触发后续消息来解决此问题。 DeferredMessageUpdate API 信息可以在这里找到 和 DiscordFollowUpMessageBuilder 可以在这里找到
解决此问题的另一种方法是删除机器人发送的原始消息,并在发生交互时重新发送具有相同内容和按钮的相同消息,但这会造成更多卡顿,并且适用于 API 实际上不同意的用例你在做什么。