Внедренная зависимость DbContext всегда равна нулю - PullRequest
0 голосов
/ 28 ноября 2018

Я использовал DI в нескольких приложениях ASP.NET (Core), где DbContext внедряется в конструктор контроллера, и при первом запросе к контроллеру запускается конструктор и вводится зависимость.

Сейчас я работаю с проектом веб-API, который подключен к шине сообщений Azure, обрабатывая и сохраняя данные с шины и предоставляя конечную точку API для данных.Класс обработки и сохранения сообщений из Azure Message Bus: QueueProcessor.

. Мне нужно сохранить данные с начала проекта, а это значит, что мне нужен экземпляр DbContext с момента запуска проекта, а не когдаЯ запрашиваю данные через конечную точку API.Из-за этого конструктор QueueProcessor никогда не вызывается неявно, и если я хочу сделать это вручную, мне нужен уже существующий экземпляр MyDbContext, чтобы перейти к нему.

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

Самый близкий вопрос, с которым я столкнулся, этоэто, что несмотря на указание неконтроллеров, принятый ответ требует контроллера для внедрения зависимости.

Это то, что я сейчас делаю:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));

        services.AddDbContextPool<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("default")));

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

IЗатем мне нужно создать новый экземпляр моего QueueProcessor и использовать var context = new MyDbContext() внутри конструктора.Это вызывает проблемы параллелизма и полностью сводит на нет DI.

Если я хочу внедрить MyDbContext с помощью DI, как я делал сотни раз, создавая экземпляр класса для запуска процесса внутри QueueProcessor означает, что я должен передать экземпляр MyDbContext самому конструктору.VS отмечает это во время разработки.

Я когда-либо пытался использовать это как можно больше, выполняя:

services.AddTransient(x => new QueueProcessor(x.GetService<MyDbContext>(), Configuration.GetConnectionString("MessageBus")));

Я ищу более чистый способ достижения:

  • Вызовите метод внутри QueueProcessor для обработки сообщений Azure Message Bus с момента запуска проекта.
  • Перед обработкой сообщений у меня должен быть экземпляр класса MyDbContext, который я могу использовать длясохраняйте сообщения при их обработке.
  • Не нужно использовать Controller для правильной настройки DI.

Есть ли способ добиться этого или я полностью пропустилзнак здесь?

1 Ответ

0 голосов
/ 28 ноября 2018

Рабочее решение, не уверен, что это лучший шаблон:

  1. В Startup.cs шанс ConfigureServices вернуть IServiceProvider вместо void.
  2. СборкаserviceProvider, используя: var serviceProvider = services.BuildServiceProvider();
  3. Получить экземпляр MyDbContext: var context = serviceProvider.GetRequiredService<MyDbContext>();
  4. Создать экземпляр QueueProcessor и передать context в конструктор и вызвать метод для начала обработки сообщений.
  5. С ConfigureServices верните свой новый serviceProvider.

Полный кодовый блок:

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));

        var serviceProvider = services.BuildServiceProvider();

        var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();

        Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
        Processor.RunAsync().GetAwaiter().GetResult();

        return serviceProvider;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...