. net код 3.0 Работник службы IServiceProvider утилизирует - PullRequest
0 голосов
/ 26 апреля 2020

Я пытаюсь сделать рабочий сервис как windows сервис. Задача: 1. Проверить таблицу БД, если в ней есть строки, в которых столбцы «State» готовы - обработать эти строки. 2. Запустите sqltabledependency к уведомлениям об изменениях в db для обработки новых или обновленных строк.

Вот мой код.

Worker.cs

public class Worker : BackgroundService
    {
        private static readonly string Directory = AppDomain.CurrentDomain.BaseDirectory;

        private readonly ILogger<Worker> _logger;
        private readonly IServiceProvider _provider;
        private ICommandDispatcher _commandDispatcher;
        private IQueryDispatcher _queryDispatcher;
        private readonly SmtpOptions _smtpOptions;

        public Worker(ILogger<Worker> logger, IServiceProvider provider)
        {
            _logger = logger;
            _provider = provider;
            _smtpOptions = new SmtpOptions(...);
            using (IServiceScope scope = _provider.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                _commandDispatcher = scope.ServiceProvider.GetService<ICommandDispatcher>();
                _queryDispatcher = scope.ServiceProvider.GetService<IQueryDispatcher>();
            }
        }

        private async Task<OutgoingLetter> GetCurrentLetter()
        {
            return await _queryDispatcher.HandleAsync<LetterGetQuery, OutgoingLetter>(new LetterGetQuery());
        }

        private async Task ProcessLetterTask()
        {
                OutgoingLetter letter = null;
                do
                {
                    try
                    {
                        letter = await GetCurrentLetter();
                        if (letter != null)
                        {

                            if (letter.MessageTypeID == MessageTypes.Auth)
                                    await _commandDispatcher.HandleAsync(new AuthLetterProcessCommand(letter, _smtpOptions));

                            if (letter.MessageTypeID == MessageTypes.Rests)
                                await _commandDispatcher.HandleAsync(
                                    new RestsLetterProcessCommand(Directory, letter, _smtpOptions));
                        }
                    }catch (Exception ex)
                    {
                        await _commandDispatcher.HandleAsync(new LetterErrorProcessCommand(letter));
                    }
                } while (letter != null);
      }


        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            await ProcessLetterTask();
            string connection = "...my connection string";
            var tableName = "OutgoingLetters";
            var tableDependency = new SqlTableDependency<OutgoingLetter>(connection, tableName, "Queues");
            tableDependency.OnChanged += OnNotificationReceived;
            tableDependency.Start();
        }

        private void OnNotificationReceived(object sender, RecordChangedEventArgs<OutgoingLetter> e)
        {
            if (e.ChangeType == ChangeType.Insert || e.ChangeType == ChangeType.Update)
            {
                Task.WhenAll(ProcessLetterTask());
            }
        }
    }
}

Program.cs

  public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    string connection = "Server=MS-SQL2;Database=GoodWill_New;Trusted_Connection=True;";
                    services.AddDbContext<QueuesDbContext>(options => options.UseSqlServer(connection));

                    services.AddScoped<ICommandHandler<LetterProcessCommand>, LetterProcessCommandHandler>();
                    services.AddScoped<ICommandHandler<LetterErrorProcessCommand>, LetterErrorProcessCommandHandler>();
                    services.AddScoped<ICommandHandler<LetterSuccessProcessCommand>, LetterSuccessProcessCommandHandler>();
                    services.AddScoped<ICommandHandler<OneCErrorLetterProcessCommand>, OneCErrorLetterProcessCommandHandler>();

                    services.AddScoped<IQueryHandler<LetterGetQuery, OutgoingLetter>, LetterGetQueryHandler>();

                    services.AddScoped<ICommandDispatcher, CommandDispatcher>();
                    services.AddScoped<IQueryDispatcher, QueryDispatcher>();
                    services.AddHostedService<Worker>();
                });
    }

LetterGetQueryHandler.cs

internal sealed class LetterGetQueryHandler: IQueryHandler<LetterGetQuery, OutgoingLetter>
    {
        private readonly QueuesDbContext _queuesDbContext;

        public LetterGetQueryHandler(QueuesDbContext queuesDbContext)
        {
            _queuesDbContext = queuesDbContext;
        }

        public async Task<OutgoingLetter> HandleAsync(LetterGetQuery query)
        {
            return await _queuesDbContext.Letters.FirstOrDefaultAsync(x => x.QueueStateID == QueueStates.Ready);
        }
    }

Все обработчики команд имеют одинаковую структуру - метод HandleAsyn c и используют QueueDbContext. Теперь я получаю исключение объекта. Возникло исключение: System.ObjectDisposedException в System.Private.CoreLib.dll. Имя объекта: IServiceProvider. Я думаю, что он не может внедрить QueuesDbContext в обработчики, но я понятия не имею, как его исправить. Спасибо за любой совет

...