Skip to content

How to get an instance of IStorage in a non controller class? #188

Open

Description

@Bork44

Я использую ExtCore в своем проекте (Blazor + .Net 5.0) для реализации плагинов. Абстрактно плагины - это расширения для добавления новых меню с собственным контентом (Razor Class Library), и в них IStorage прекрасно импортируется через

@inject IStorage storage

При этом одни из плагинов также реализует модульность, но на более примитивном уровне, для создания цепочек из блоков-модулей с простейшими функциями (тракт). Каждый модуль - это отдельная dll без веб-компонентов, работает в отдельном потоке (Task). Модули также прекрасно подтягиваются через ExtesionMenager.
Проблема в том, что модулям тоже нужно обращаться к базе данных. Модули не наследуют Controller или ComponentBase, они не рендерятся, к ним нет обращения через web-api, они не возвращают и не должны возвращать ActionResult, они вообще вне веб-части.
Есть ли способ получить экземпляр IStorage в таком модуле?

Activity

  1. DmitrySikorsky commented on Mar 9, 2021

    @DmitrySikorsky
    Member

    Добрый день!

    Вы можете достать из DI сервис в любом месте приложения с помощью IServiceProvider. К нему можно получить доступ через HttpContext.Request.RequestServices.

    Если же это код, который выполняется вне контекста HTTP-запроса, и доступного HttpContext нет, то тогда остается вариант лишь вручную сконструировать IStorage используя ExtensionManager. Т. е. создать вручную новый объект, передав необходимые параметры.

    Но это кажется мне не изящным.

    У меня была задача выполнять регулярные действия через Hangfire, но там задачи также можно сделать сервисами, и тогда в их конструкторах работает DI. Может быть у вас тоже можно как-то так?

  2. Bork44 commented on Mar 15, 2021

    @Bork44
    Author

    Доброго дня!

    Да, Вы правы, код выполняется вне контекста HTTP. Почитал про Hangfire, но это решение слишком громоздко для моих задач, к тому же ориентировано на собственное регулирование стека задач, а мне нужно жестко самому контролировать их параллельное выполнение. Здесь больше подошли бы BackgroundService или IHostedService, но опять же - задачи формируются вне контекста HTTP.

    Я решил проблему, создав отдельный DbContext на основе реализованных Entities, продублировав строку подключения через IConfigureServicesAction:

    public void Execute(IServiceCollection services, IServiceProvider serviceProvider)
    {
           services.AddDbContext<MyDbContext>(options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
    }
    

    А также, по сути, продублировав OnModelCreating() содержимым из RegisterEntities().

    Я понимаю, что доступ к контейнеру служб вне контекста HTTP, не предполагается при разработке веб-приложения. Но иметь такую функциональность через уже реализованный статический ExtensionManager было бы неплохо. К тому же не я один задаюсь таким же вопросом (я нагуглил с десяток аналогичных вопросов без грамотного решения). Ограничения, безопасность, стабильность и бла ,бла ,бла - это все да. Мне не нужны все службы из контейнера, хотя бы для собственных расширений (реализующих ExtensionBase) можно как-то организовать? Ведь есть же GetInstances(), который прекрасно работает для классов, не требующих DI.

    Теперь сижу и думаю: "А зачем мне тогда реализации IRepository и RepositoryBase?"
    И еще есть сопутствующий вопрос #189

  3. DmitrySikorsky commented on Mar 16, 2021

    @DmitrySikorsky
    Member

    Я не вижу ничего плохого в том, что какому-то коду необходимо вызываться вне HTTP-контекста. Например, служебные процедуры по расписанию. Если вам нужна DI вы можете использовать hosted services, либо же просто как вы и сделали -- создавать вручную экземпляр IStorage. Вы ведь можете создать экземпляр доступной реализации IStorage с помощью ExtensionManager, чтобы не указывать явно конкретную. Т. е. приложение останется слабо связанным.

    Насчет репозиториев. Они нужны чтобы был единый контекст работы с базой.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions