Discord. Net внедрение зависимости - зависимость не найдена при запуске команды - PullRequest
0 голосов
/ 15 января 2020

Я пытаюсь выполнить внедрение зависимостей через конструктор модуля, и, похоже, это работает, потому что я могу успешно использовать класс внутри конструктора, но всякий раз, когда я запускаю команду, она ломается. Вот что я получаю, когда пытаюсь запустить команду:

---> 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();
    }
}

1 Ответ

0 голосов
/ 12 февраля 2020

Попробуйте это в программе на ConfigureServices:

private static IServiceProvider ConfigureServices()
{
    var map = new ServiceCollection()
        .AddSingleton<TestService>()

    return map.BuildServiceProvider();
}
...