Невозможно разрешить экземпляр в Webapp program.cs в C# .NET Core. ⇐ C#
-
Гость
Невозможно разрешить экземпляр в Webapp program.cs в C# .NET Core.
У меня 4 проекта на C#
[*]WebApp (веб-приложение ASP.NET Core MVC) [*]EmailNotificationService (библиотека классов) [*]PushNotificationService (библиотека классов) [*]EventBroker (библиотека классов)
В веб-приложении у меня работает фоновая служба, которая постоянно прослушивает очередь (внедренную как синглтон). Очередь обновляется веб-приложением, а фоновая служба считывает из очереди и обрабатывает каждый элемент, а затем загружает его в базу данных. Фоновая служба также содержит экземпляр EventManager (внедренный в синглтон), с помощью которого она публикует событие загрузки
публичный класс UploadBackgroundService: BackgroundService { частный UploadQueue _workerQueue только для чтения; частный только для чтения IServiceProvider _serviceProvider; частный только для чтения ILogger _logger; частный только для чтения EventManager _eventManager; общедоступная UploadBackgroundService (UploadQueue workerQueue, IServiceProvider serviceProvider, ILogger регистратор, EventManager eventManager) { _workerQueue = workerQueue ?? бросить новое ArgumentNullException(nameof(workerQueue)); _serviceProvider = поставщик услуг ?? выдать новое ArgumentNullException(nameof(serviceProvider)); _eventManager = eventManager ?? бросить новое ArgumentNullException(nameof(eventManager)); _logger = регистратор; } защищенное переопределение асинхронной задачи ExecuteAsync (CancellationToken StopToken) { в то время как (!stoppingToken.IsCancellationRequested) { пытаться { использование области IServiceScope = _serviceProvider.CreateScope(); используя DbContext dbContext =scope.ServiceProvider.GetService() ?? throw new Exception("Контекст базы данных имеет значение null!"); await foreach(Func workItem в this._workerQueue.ReadAsyncStream()) { UploadResult uploadResult = ждут workItem (dbContext); _eventManager.NotifyObservers(новый UploadResult(Enums.UploadStatus.Error)); } } поймать (Исключение ex) { Console.WriteLine(ex.ToString()); } } } } Проект EventBroker содержит класс EventManager, который создает событие загрузки и уведомляет всех своих подписчиков.
публичный класс EventManager { публичное событие EventHandler? ЗагрузитьСобытие; общедоступная виртуальная пустота OnUpload (UploadEventArgs uploadEventArgs) { UploadEvent?.Invoke(this, uploadEventArgs); } public void NotifyObservers (объект uploadResult) { UploadEventArgs uploadEventArgs = новый UploadEventArgs(); uploadEventArgs.Data = JsonConvert.SerializeObject(uploadResult); OnUpload (uploadEventArgs); } } EmailNotificationsService содержит класс потребителя электронной почты, который подписывается на событие загрузки в EventManager и при каждом получении уведомления отправляет электронное письмо пользователям.
публичный класс EmailConsumer: IConsumer { частный только для чтения IEmailSender _emailSender; общедоступный EmailConsumer (IEmailSender emailSender) { _emailSender = emailSender ?? выбросить новое ArgumentNullException(nameof(emailSender)); } публичная недействительная подписка (EventManager eventBroker) { eventBroker.UploadEvent += SendEmailNotifications!; } public void SendEmailNotifications (отправитель объекта, UploadEventArgs eventArgs) { EmailUploadResult uploadResult = JsonConvert.DeserializeObject(eventArgs.Data) ?? выдать новое InvalidDataException("Поврежденные данные"); _emailSender.SendEmailAsync(null, new List {new Address("testcapsdev@outlook.com") }, null, null, null, uploadResult); } } PushNotificationsService содержит потребительский класс signalRNotification, который подписывается на событие загрузки в EventManager и при каждом получении уведомления отправляет push-уведомления в пользовательский интерфейс.
публичный класс SignalRNotificationConsumer: IConsumer { частный только для чтения IHubContext _hubContext; public SignalRNotificationConsumer (IHubContexthubContext) { _hubContext = HubContext; } публичная недействительная подписка (EventManager eventBroker) { eventBroker.UploadEvent += SendSignalRNotifications!; } Private void SendSignalRNotifications (отправитель объекта, UploadEventArgs uploadEventArgs) { пытаться { SignalRUploadResult uploadResult = JsonConvert.DeserializeObject(uploadEventArgs.Data) ?? выдать новое InvalidDataException("Поврежденные данные"); _hubContext.Clients.All.UploadNotifications(uploadResult); } поймать (исключение ex) { Console.WriteLine(ex); } } } Теперь я подписываюсь на событие внутри веб-приложения program.cs:
var Services = builder.Services; Services.AddSingleton(); Services.AddSingleton(); Services.AddScoped().AddScoped(s => s.GetService()!); Services.AddScoped().AddScoped(s => s.GetService()!); Services.AddScoped(); вар приложение = builder.Build(); EventManager eventBroker = app.ServiceProvider.GetService()!; IConsumer потребитель = (IConsumer)app.ServiceProvider.GetService(typeof(EmailConsumer))!; потребитель.Подписаться(eventBroker); IConsumer потребитель = (IConsumer)app.ServiceProvider.GetService(typeof(SignalRNotificationConsumer))!; потребитель.Подписаться(eventBroker); Теперь я получаю сообщение об ошибке
Невозможно разрешить службу с ограниченной областью действия от корневого поставщика
Я не хочу подписываться на фоновую службу, которая работает нормально. Потому что фоновой службе ничего не нужно знать о подписчиках.
защищенное переопределение асинхронной задачи ExecuteAsync (CancellationToken StoppingToken) { IConsumer signalRConsumer = (IConsumer)_serviceProvider.CreateScope().ServiceProvider.GetService(typeof(SignalRNotificationConsumer))! ?? выдать новое ArgumentNullException("SignalRConsumer"); IConsumer emailConsumer = (IConsumer)_serviceProvider.CreateScope().ServiceProvider.GetService(typeof(EmailConsumer))! ?? выдать новое ArgumentNullException("SignalRConsumer"); signalRConsumer.Subscribe(_eventManager); emailConsumer.Subscribe(_eventManager); в то время как (!stoppingToken.IsCancellationRequested) { пытаться { использование области IServiceScope = _serviceProvider.CreateScope(); используя DbContext dbContext =scope.ServiceProvider.GetService() ?? throw new Exception("Контекст базы данных имеет значение null!"); await foreach(Func workItem в this._workerQueue.ReadAsyncStream()) { UploadResult uploadResult = ждут workItem (dbContext); _eventManager.NotifyObservers(новый UploadResult(Enums.UploadStatus.Error)); } } поймать (Исключение ex) { Console.WriteLine(ex.ToString()); } } } Приведенный выше код работает нормально.
Итак, может кто-нибудь указать правильное направление. Уместна ли моя мысль? и как мне заставить это работать без инициализации подписчиков фоновой службой.
У меня 4 проекта на C#
[*]WebApp (веб-приложение ASP.NET Core MVC) [*]EmailNotificationService (библиотека классов) [*]PushNotificationService (библиотека классов) [*]EventBroker (библиотека классов)
В веб-приложении у меня работает фоновая служба, которая постоянно прослушивает очередь (внедренную как синглтон). Очередь обновляется веб-приложением, а фоновая служба считывает из очереди и обрабатывает каждый элемент, а затем загружает его в базу данных. Фоновая служба также содержит экземпляр EventManager (внедренный в синглтон), с помощью которого она публикует событие загрузки
публичный класс UploadBackgroundService: BackgroundService { частный UploadQueue _workerQueue только для чтения; частный только для чтения IServiceProvider _serviceProvider; частный только для чтения ILogger _logger; частный только для чтения EventManager _eventManager; общедоступная UploadBackgroundService (UploadQueue workerQueue, IServiceProvider serviceProvider, ILogger регистратор, EventManager eventManager) { _workerQueue = workerQueue ?? бросить новое ArgumentNullException(nameof(workerQueue)); _serviceProvider = поставщик услуг ?? выдать новое ArgumentNullException(nameof(serviceProvider)); _eventManager = eventManager ?? бросить новое ArgumentNullException(nameof(eventManager)); _logger = регистратор; } защищенное переопределение асинхронной задачи ExecuteAsync (CancellationToken StopToken) { в то время как (!stoppingToken.IsCancellationRequested) { пытаться { использование области IServiceScope = _serviceProvider.CreateScope(); используя DbContext dbContext =scope.ServiceProvider.GetService() ?? throw new Exception("Контекст базы данных имеет значение null!"); await foreach(Func workItem в this._workerQueue.ReadAsyncStream()) { UploadResult uploadResult = ждут workItem (dbContext); _eventManager.NotifyObservers(новый UploadResult(Enums.UploadStatus.Error)); } } поймать (Исключение ex) { Console.WriteLine(ex.ToString()); } } } } Проект EventBroker содержит класс EventManager, который создает событие загрузки и уведомляет всех своих подписчиков.
публичный класс EventManager { публичное событие EventHandler? ЗагрузитьСобытие; общедоступная виртуальная пустота OnUpload (UploadEventArgs uploadEventArgs) { UploadEvent?.Invoke(this, uploadEventArgs); } public void NotifyObservers (объект uploadResult) { UploadEventArgs uploadEventArgs = новый UploadEventArgs(); uploadEventArgs.Data = JsonConvert.SerializeObject(uploadResult); OnUpload (uploadEventArgs); } } EmailNotificationsService содержит класс потребителя электронной почты, который подписывается на событие загрузки в EventManager и при каждом получении уведомления отправляет электронное письмо пользователям.
публичный класс EmailConsumer: IConsumer { частный только для чтения IEmailSender _emailSender; общедоступный EmailConsumer (IEmailSender emailSender) { _emailSender = emailSender ?? выбросить новое ArgumentNullException(nameof(emailSender)); } публичная недействительная подписка (EventManager eventBroker) { eventBroker.UploadEvent += SendEmailNotifications!; } public void SendEmailNotifications (отправитель объекта, UploadEventArgs eventArgs) { EmailUploadResult uploadResult = JsonConvert.DeserializeObject(eventArgs.Data) ?? выдать новое InvalidDataException("Поврежденные данные"); _emailSender.SendEmailAsync(null, new List {new Address("testcapsdev@outlook.com") }, null, null, null, uploadResult); } } PushNotificationsService содержит потребительский класс signalRNotification, который подписывается на событие загрузки в EventManager и при каждом получении уведомления отправляет push-уведомления в пользовательский интерфейс.
публичный класс SignalRNotificationConsumer: IConsumer { частный только для чтения IHubContext _hubContext; public SignalRNotificationConsumer (IHubContexthubContext) { _hubContext = HubContext; } публичная недействительная подписка (EventManager eventBroker) { eventBroker.UploadEvent += SendSignalRNotifications!; } Private void SendSignalRNotifications (отправитель объекта, UploadEventArgs uploadEventArgs) { пытаться { SignalRUploadResult uploadResult = JsonConvert.DeserializeObject(uploadEventArgs.Data) ?? выдать новое InvalidDataException("Поврежденные данные"); _hubContext.Clients.All.UploadNotifications(uploadResult); } поймать (исключение ex) { Console.WriteLine(ex); } } } Теперь я подписываюсь на событие внутри веб-приложения program.cs:
var Services = builder.Services; Services.AddSingleton(); Services.AddSingleton(); Services.AddScoped().AddScoped(s => s.GetService()!); Services.AddScoped().AddScoped(s => s.GetService()!); Services.AddScoped(); вар приложение = builder.Build(); EventManager eventBroker = app.ServiceProvider.GetService()!; IConsumer потребитель = (IConsumer)app.ServiceProvider.GetService(typeof(EmailConsumer))!; потребитель.Подписаться(eventBroker); IConsumer потребитель = (IConsumer)app.ServiceProvider.GetService(typeof(SignalRNotificationConsumer))!; потребитель.Подписаться(eventBroker); Теперь я получаю сообщение об ошибке
Невозможно разрешить службу с ограниченной областью действия от корневого поставщика
Я не хочу подписываться на фоновую службу, которая работает нормально. Потому что фоновой службе ничего не нужно знать о подписчиках.
защищенное переопределение асинхронной задачи ExecuteAsync (CancellationToken StoppingToken) { IConsumer signalRConsumer = (IConsumer)_serviceProvider.CreateScope().ServiceProvider.GetService(typeof(SignalRNotificationConsumer))! ?? выдать новое ArgumentNullException("SignalRConsumer"); IConsumer emailConsumer = (IConsumer)_serviceProvider.CreateScope().ServiceProvider.GetService(typeof(EmailConsumer))! ?? выдать новое ArgumentNullException("SignalRConsumer"); signalRConsumer.Subscribe(_eventManager); emailConsumer.Subscribe(_eventManager); в то время как (!stoppingToken.IsCancellationRequested) { пытаться { использование области IServiceScope = _serviceProvider.CreateScope(); используя DbContext dbContext =scope.ServiceProvider.GetService() ?? throw new Exception("Контекст базы данных имеет значение null!"); await foreach(Func workItem в this._workerQueue.ReadAsyncStream()) { UploadResult uploadResult = ждут workItem (dbContext); _eventManager.NotifyObservers(новый UploadResult(Enums.UploadStatus.Error)); } } поймать (Исключение ex) { Console.WriteLine(ex.ToString()); } } } Приведенный выше код работает нормально.
Итак, может кто-нибудь указать правильное направление. Уместна ли моя мысль? и как мне заставить это работать без инициализации подписчиков фоновой службой.
Мобильная версия