Я пытаюсь выполнить внедрение зависимостей через конструктор модуля, и, похоже, это работает, потому что я могу успешно использовать класс внутри конструктора, но всякий раз, когда я запускаю команду, она ломается. Вот что я получаю, когда пытаюсь запустить команду:
---> 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);
}
}
InfoModule:
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;
}
}
TestService:
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();
}
}