Discord.Net 依赖注入 - 运行命令时未找到依赖项
Posted
技术标签:
【中文标题】Discord.Net 依赖注入 - 运行命令时未找到依赖项【英文标题】:Discord.Net dependency injection - dependency was not found when running command 【发布时间】:2020-05-01 16:53:35 【问题描述】:我正在尝试通过模块构造函数进行依赖注入,它似乎可以工作,因为我可以成功地使用构造函数内部的类,但是每当我运行命令时它就会中断。这是我尝试运行命令时得到的结果:
---> System.InvalidOperationException: Failed to create "AnimeCalendarBot.Modules.InfoModule", dependency "TestService" was not found.
at Discord.Commands.ReflectionUtils.GetMember(CommandService commands, IServiceProvider services, Type memberType, TypeInfo ownerType)
at Discord.Commands.ReflectionUtils.<>c__DisplayClass2_0`1.<CreateBuilder>b__0(IServiceProvider services)
at Discord.Commands.ModuleClassBuilder.<>c__DisplayClass6_0 <<BuildCommand>g__ExecuteCallback|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Discord.Commands.CommandInfo.ExecuteInternalAsync(ICommandContext context, Object[] args, IServiceProvider services)
--- End of inner exception stack trace ---
但是在运行命令之前,一切都很好。
程序:
public class Program
public static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();
private readonly DiscordSocketClient _client;
private readonly CommandService _commands;
private readonly CommandHandler _commandHandler;
private readonly IServiceProvider _services;
private Program()
_client = new DiscordSocketClient(new DiscordSocketConfig
LogLevel = LogSeverity.Info,
);
_commands = new CommandService(new CommandServiceConfig
LogLevel = LogSeverity.Info,
CaseSensitiveCommands = false,
);
_services = ConfigureServices();
_commandHandler = new CommandHandler(_client, _commands, _services);
_client.Log += Log;
_commands.Log += Log;
private static IServiceProvider ConfigureServices()
var map = new ServiceCollection()
.AddSingleton(new TestService());
return map.BuildServiceProvider();
private static Task Log(LogMessage message)
switch (message.Severity)
case LogSeverity.Critical:
case LogSeverity.Error:
Console.ForegroundColor = ConsoleColor.Red;
break;
case LogSeverity.Warning:
Console.ForegroundColor = ConsoleColor.Yellow;
break;
case LogSeverity.Info:
Console.ForegroundColor = ConsoleColor.White;
break;
case LogSeverity.Verbose:
case LogSeverity.Debug:
Console.ForegroundColor = ConsoleColor.DarkGray;
break;
Console.WriteLine($"DateTime.Now,-19 [message.Severity,8] message.Source: message.Message message.Exception");
Console.ResetColor();
return Task.CompletedTask;
public async Task MainAsync()
await _commandHandler.InstallCommandsAsync();
_client.Log += Log;
await _client.LoginAsync(TokenType.Bot,
Environment.GetEnvironmentVariable("AnimeCalendarBotToken"));
await _client.StartAsync();
// Block this task until the program is closed.
await Task.Delay(-1);
CommandHandler:
public class CommandHandler
private readonly DiscordSocketClient _client;
private readonly CommandService _commands;
private readonly IServiceProvider _services;
public CommandHandler(DiscordSocketClient client, CommandService commands, IServiceProvider services)
_client = client;
_commands = commands;
_services = services;
public async Task InstallCommandsAsync()
_client.MessageReceived += HandleCommandAsync;
await _commands.AddModulesAsync(assembly: Assembly.GetEntryAssembly(),
services: _services);
private async Task HandleCommandAsync(SocketMessage messageParam)
// Don't process the command if it was a system message
var message = messageParam as SocketUserMessage;
if (message == null) return;
// Create a number to track where the prefix ends and the command begins
int argPos = 0;
// Determine if the message is a command based on the prefix and make sure no bots trigger commands
if (!(message.HasCharPrefix('!', ref argPos) ||
message.HasMentionPrefix(_client.CurrentUser, ref argPos)) ||
message.Author.IsBot)
return;
// Create a WebSocket-based command context based on the message
var context = new SocketCommandContext(_client, message);
// Execute the command with the command context we just
// created, along with the service provider for precondition checks.
// Keep in mind that result does not indicate a return value
// rather an object stating if the command executed successfully.
var result = await _commands.ExecuteAsync(
context: context,
argPos: argPos,
services: null);
信息模块:
public class InfoModule : ModuleBase<SocketCommandContext>
private readonly TestService _testService;
public InfoModule(TestService testService)
_testService = testService;
_testService.Start(); // this works
[Command("startTest")]
[Summary("Starts test service.")]
public Task StartTestService()
_testService.Start();
return Task.CompletedTask;
[Command("stopTest")]
[Summary("Stops test service.")]
public Task StopTestService()
_testService.Stop();
return Task.CompletedTask;
测试服务:
public class TestService
private readonly Timer _timer;
public TestService()
_timer = new Timer(1000) AutoReset = true ;
_timer.Elapsed += TimerElapsed;
private void TimerElapsed(object sender, ElapsedEventArgs e)
String currentTime = DateTime.Now.ToString();
Console.WriteLine(currentTime);
public void Start()
_timer.Start();
public void Stop()
_timer.Stop();
【问题讨论】:
您没有将服务提供者传递给 ExecuteAsync 【参考方案1】:我之前遇到过同样的问题。问题是CommandHandler
没有注入服务。
首先,我会像@EnderIce2 的回答那样分配您的服务。
var map = new ServiceCollection()
.AddSingleton<TestService>()
之后你需要转到CommandHandler
并更改结尾InstallCommandsAsync
方法:
await _commands.AddModulesAsync(assembly: Assembly.GetEntryAssembly(),
services: null);
到
await _commands.AddModulesAsync(assembly: Assembly.GetEntryAssembly(),
services: _services);
HandleCommandAsync
也是如此;最后更改:
await _commands.ExecuteAsync(
context: context,
argPos: argPos,
services: null);
收件人:
await _commands.ExecuteAsync(
context: context,
argPos: argPos,
services: _services);
【讨论】:
【参考方案2】:在 ConfigureServices 的 Program 上试试这个:
private static IServiceProvider ConfigureServices()
var map = new ServiceCollection()
.AddSingleton<TestService>()
return map.BuildServiceProvider();
【讨论】:
以上是关于Discord.Net 依赖注入 - 运行命令时未找到依赖项的主要内容,如果未能解决你的问题,请参考以下文章