You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
How to get an instance of IStorage in a non controller class? #188
Я использую ExtCore в своем проекте (Blazor + .Net 5.0) для реализации плагинов. Абстрактно плагины - это расширения для добавления новых меню с собственным контентом (Razor Class Library), и в них IStorage прекрасно импортируется через
@inject IStorage storage
При этом одни из плагинов также реализует модульность, но на более примитивном уровне, для создания цепочек из блоков-модулей с простейшими функциями (тракт). Каждый модуль - это отдельная dll без веб-компонентов, работает в отдельном потоке (Task). Модули также прекрасно подтягиваются через ExtesionMenager.
Проблема в том, что модулям тоже нужно обращаться к базе данных. Модули не наследуют Controller или ComponentBase, они не рендерятся, к ним нет обращения через web-api, они не возвращают и не должны возвращать ActionResult, они вообще вне веб-части.
Есть ли способ получить экземпляр IStorage в таком модуле?
Вы можете достать из DI сервис в любом месте приложения с помощью IServiceProvider. К нему можно получить доступ через HttpContext.Request.RequestServices.
Если же это код, который выполняется вне контекста HTTP-запроса, и доступного HttpContext нет, то тогда остается вариант лишь вручную сконструировать IStorage используя ExtensionManager. Т. е. создать вручную новый объект, передав необходимые параметры.
Но это кажется мне не изящным.
У меня была задача выполнять регулярные действия через Hangfire, но там задачи также можно сделать сервисами, и тогда в их конструкторах работает DI. Может быть у вас тоже можно как-то так?
Да, Вы правы, код выполняется вне контекста HTTP. Почитал про Hangfire, но это решение слишком громоздко для моих задач, к тому же ориентировано на собственное регулирование стека задач, а мне нужно жестко самому контролировать их параллельное выполнение. Здесь больше подошли бы BackgroundService или IHostedService, но опять же - задачи формируются вне контекста HTTP.
Я решил проблему, создав отдельный DbContext на основе реализованных Entities, продублировав строку подключения через IConfigureServicesAction:
А также, по сути, продублировав OnModelCreating() содержимым из RegisterEntities().
Я понимаю, что доступ к контейнеру служб вне контекста HTTP, не предполагается при разработке веб-приложения. Но иметь такую функциональность через уже реализованный статический ExtensionManager было бы неплохо. К тому же не я один задаюсь таким же вопросом (я нагуглил с десяток аналогичных вопросов без грамотного решения). Ограничения, безопасность, стабильность и бла ,бла ,бла - это все да. Мне не нужны все службы из контейнера, хотя бы для собственных расширений (реализующих ExtensionBase) можно как-то организовать? Ведь есть же GetInstances(), который прекрасно работает для классов, не требующих DI.
Теперь сижу и думаю: "А зачем мне тогда реализации IRepository и RepositoryBase?"
И еще есть сопутствующий вопрос #189
Я не вижу ничего плохого в том, что какому-то коду необходимо вызываться вне HTTP-контекста. Например, служебные процедуры по расписанию. Если вам нужна DI вы можете использовать hosted services, либо же просто как вы и сделали -- создавать вручную экземпляр IStorage. Вы ведь можете создать экземпляр доступной реализации IStorage с помощью ExtensionManager, чтобы не указывать явно конкретную. Т. е. приложение останется слабо связанным.
Насчет репозиториев. Они нужны чтобы был единый контекст работы с базой.
Activity
DmitrySikorsky commentedon Mar 9, 2021
Добрый день!
Вы можете достать из DI сервис в любом месте приложения с помощью IServiceProvider. К нему можно получить доступ через HttpContext.Request.RequestServices.
Если же это код, который выполняется вне контекста HTTP-запроса, и доступного HttpContext нет, то тогда остается вариант лишь вручную сконструировать IStorage используя ExtensionManager. Т. е. создать вручную новый объект, передав необходимые параметры.
Но это кажется мне не изящным.
У меня была задача выполнять регулярные действия через Hangfire, но там задачи также можно сделать сервисами, и тогда в их конструкторах работает DI. Может быть у вас тоже можно как-то так?
Bork44 commentedon Mar 15, 2021
Доброго дня!
Да, Вы правы, код выполняется вне контекста HTTP. Почитал про Hangfire, но это решение слишком громоздко для моих задач, к тому же ориентировано на собственное регулирование стека задач, а мне нужно жестко самому контролировать их параллельное выполнение. Здесь больше подошли бы BackgroundService или IHostedService, но опять же - задачи формируются вне контекста HTTP.
Я решил проблему, создав отдельный DbContext на основе реализованных Entities, продублировав строку подключения через IConfigureServicesAction:
А также, по сути, продублировав OnModelCreating() содержимым из RegisterEntities().
Я понимаю, что доступ к контейнеру служб вне контекста HTTP, не предполагается при разработке веб-приложения. Но иметь такую функциональность через уже реализованный статический ExtensionManager было бы неплохо. К тому же не я один задаюсь таким же вопросом (я нагуглил с десяток аналогичных вопросов без грамотного решения). Ограничения, безопасность, стабильность и бла ,бла ,бла - это все да. Мне не нужны все службы из контейнера, хотя бы для собственных расширений (реализующих ExtensionBase) можно как-то организовать? Ведь есть же GetInstances(), который прекрасно работает для классов, не требующих DI.
Теперь сижу и думаю: "А зачем мне тогда реализации IRepository и RepositoryBase?"
И еще есть сопутствующий вопрос #189
DmitrySikorsky commentedon Mar 16, 2021
Я не вижу ничего плохого в том, что какому-то коду необходимо вызываться вне HTTP-контекста. Например, служебные процедуры по расписанию. Если вам нужна DI вы можете использовать hosted services, либо же просто как вы и сделали -- создавать вручную экземпляр IStorage. Вы ведь можете создать экземпляр доступной реализации IStorage с помощью ExtensionManager, чтобы не указывать явно конкретную. Т. е. приложение останется слабо связанным.
Насчет репозиториев. Они нужны чтобы был единый контекст работы с базой.