Служба ASP.NET Core Singleton создавалась несколько раз

Я работаю над проектом ASP.NET Core 2.1, где мне нужно зарегистрироваться, а затем использовать одноэлементную службу внутри Startup.ConfigureServices.

У меня есть следующий код:

public void ConfigureServices(IServiceCollection services)
{
    //....
    //....

    services.AddSingleton<IMyService,MyService>();

    var serviceProvider = services.BuildServiceProvider();

    var myService = serviceProvider.GetService<IMyService>();

    services.AddDbContext<MyDbContext>(options => options.UseMySql(myService.DBConnectionString));
}

Приведенный выше код отлично работает, чтобы я мог использовать «MyService» внутри ConfigureServices. Однако позже в моем приложении, когда я пытаюсь использовать MyService, снова вызывается конструктор MyService. Почему он не использует уже созданный экземпляр, так как я зарегистрировал класс с помощью AddSingleton?

Обновлено: я решил отредактировать, чтобы добавить свою конечную цель, чтобы посмотреть, есть ли другой способ сделать это. Мой одноэлементный сервис предоставляет доступ к нескольким настройкам, которые могут быть получены из двух разных мест. Одним из таких параметров является строка подключения к БД. Мне нужна эта строка подключения в ConfigureServices, чтобы она была у меня, когда я вызываю services.AddDbContext. Я также хочу вести журнал в службе, которая получает параметры конфигурации, что означает, что мне также нужно получить ILoggerFactory.

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

Nkosi 27.06.2019 00:55

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

Nkosi 27.06.2019 00:57

@Nkosi Я добавил правку в свой исходный пост, чтобы указать, что я пытаюсь сделать. Может быть, есть другой способ сделать это?

James 27.06.2019 01:11

@Nkosi Я больше ничего не пробовал, так как даже не знаю, с чего начать.

James 27.06.2019 01:22

Откуда ваша служба получает строку подключения?

Nkosi 27.06.2019 01:22

Это может быть проблема XY.

Nkosi 27.06.2019 01:22

@Nkosi служба получает строку подключения (и несколько других значений) либо из appSettings.json, если он есть, либо путем внешнего вызова API с использованием AWS SDK для извлечения из AWS Secrets Manager. Этот же сервис также предоставляет несколько других значений (также взятых либо из AWS, либо из appSettings.json), но эти другие значения не нужны в ConfigureServices.

James 27.06.2019 01:29

строка подключения будет поступать из нескольких мест или только из файла настроек? если только из файла настроек, то нет необходимости в вашем сервисе. получить его непосредственно из IConfiguration и использовать в службах настройки

Nkosi 27.06.2019 01:30

@Nkosi строка подключения может исходить от AWS Secrets Manager

James 27.06.2019 01:32

Тогда я думаю, что это фактический вопрос, который вы должны задать.

Nkosi 27.06.2019 01:33

@Nkosi, но я уже могу это сделать. Получение строки подключения к БД либо из AWS Secret Manager, либо из appSettings.json уже работает. Проблема в том, что мне нужно, чтобы служба, которая делает это, уже была зарегистрирована (без повторного создания позже), поэтому я могу использовать это значение (откуда оно пришло) для регистрации моего DBContext. См. добавленную строку во фрагменте кода моего исходного сообщения. options.UseMySql(myService.DBConnectionString). Свойство DBConnectionString в MyService вернет правильную строку подключения к БД.

James 27.06.2019 01:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
11
2 686
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вызов BuildServiceProvider из ConfigureServices приведет к созданию дополнительной копии одноэлементных сервисов.

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

//...

services.AddSingleton<IMyService, MyService>();

services.AddDbContext<MyDbContext>((serviceProvider, options) =>
    options.UseMySql(serviceProvider.GetRequiredService<IMyService>().DBConnectionString)
);

//....

Ссылка AddDbContext<TContext>(IServiceCollection, Action<IServiceProvider,DbContextOptionsBuilder>, ServiceLifetime, ServiceLifetime)

AddSingleton сообщает Unity построить его один раз. Этот «один раз» является дополнением к любым конструкторам, которые вы вызываете непосредственно в своем коде.

Если вы хотите повторно использовать созданный вами экземпляр, используйте вместо этого AddInstance.

var serviceProvider = services.BuildServiceProvider();

var myService = serviceProvider.GetService<IMyService>();

services.AddInstance<IMyService>(myService);

services.AddDbContext<MyDbContext>(options => options.UseMySql(myService.DBConnectionString));

Можно ли получить экземпляр из serviceProvider перед добавлением IMyService в services?

Hamid Mayeli 29.05.2020 16:39

Другие вопросы по теме