Re[7]: О пользе Dependency Injection
От: microuser  
Дата: 15.01.21 15:26
Оценка: -1
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, petroa, Вы писали:


P>>Это ведь вроде, так или иначе, придётся делать самому. Можно делегировать ioc-контейнеру. Интересно ваше мнение.


IT>Дело не в конфигурации. Обрати внимание, нелюбители DI фреймворков сетуют прежде всего на то, что с таким кодом сложно разбираться. Это действительно так. Это сложно понять, если ты написал пару проектов исключительно как писатель и не занимался их поддержкой продолжительное время. А ещё лучше это прочувствовать на чужом коде. Вот представь, у тебя есть простейший код:


IT>
IT>class Foo
IT>{
IT>    public Foo(Bar b)
IT>    {
IT>        if (b == null)
IT>            throw ...
IT>    }
IT>}
IT>

IT>Код кидает исключение. Твоя задача — найти причину. Если код без DI фрейворков, то эта задача из разряда примитивных. Shift-F12 в студии (R#?) покажет тебе абсолютно все вызовы конструктора и далее по цепочке можно раскрутить всё даже без необходимости запускать этот код. Если же используется DI фреймворк, то для того, чтобы понять что происходит необходимо запускать как минимум отладчик. При этом возникает несколько проблем.

IT>- этот код может находится в трудно доступном месте и для его выполнения потребуется создание определённого сценария, подготовки окружения и набора данных.

IT>- проблема может возникать только в определённом окружении недоступном для отладки, а при создании искуственных условий проблема не воспроизводится.

IT>При наихудшем сценарии проблему всё равно придётся решать путём анализа кода, но в случае с DI фреймворком это на порядок сложнее.


С DI фреймворком ровным счетом ничего не меняется, только Shift-F12 нажимается не на конструкторе, а на названии класса. Дальше надо посмотреть лишь классы у которых в конструкторе есть параметр с типом Foo, и так же по цепочке раскручивается. Проблема надуманная, как мне кажется.
Re[10]: О пользе Dependency Injection
От: IT Россия linq2db.com
Дата: 15.01.21 15:26
Оценка: +1
Здравствуйте, varenikAA, Вы писали:

AA>Понял, а то у ТС вообще неопнятно на что он жалуется. ну это субъективно. так то во всех учебниках учат что надо избегать явного создания объектов.


Они не учат почему этого нужно избегать? Если нет, то ввыкинь такие учебники на помоечку. Впрочем, если да, то тоже выкинь.

AA>Взять теже фабрики, билдеры они тоже зло?


Да.
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: О пользе Dependency Injection
От: IT Россия linq2db.com
Дата: 15.01.21 15:37
Оценка:
Здравствуйте, microuser, Вы писали:

M>С DI фреймворком ровным счетом ничего не меняется, только Shift-F12 нажимается не на конструкторе, а на названии класса. Дальше надо посмотреть лишь классы у которых в конструкторе есть параметр с типом Foo, и так же по цепочке раскручивается. Проблема надуманная, как мне кажется.


И что это решает? Вот нашёл ты класс, который принимает Foo как параметр. Но преждем чем его принять тебе нужно создать этот Foo, а он при создании падает.
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: О пользе Dependency Injection
От: petroa  
Дата: 15.01.21 15:52
Оценка: +1
IT>Вот представь, у тебя есть простейший код:
IT> if (b == null)
IT> throw ...
IT>Код кидает исключение. Твоя задача — найти причину. Если код без DI фрейворков, то эта задача из разряда примитивных.

Но в описываемой мною ситуации b не может быть null по определению, в этом случае контейнер бросает вполне читаемое подробное исключение, что такая-то завимисость в таком-то месте не может быть удовлетворена. Снова, возвращаемся к конфигурации и определяем эту зависимость — всё "в рамках".

Я вообще рассматривал бы именно такие проверки (на null) в другом контексте, когда мы так уж и знаем, откуда нам придут данные. Понятно, что на практике бывает по всякому, но это, как мне кажется, скорее все же не вопрос регистрации/использования дерева внутренних сервисов в рамках приложения.

Т.е. мы как бы о разных вещах говорим, я пытался описать именно преимущество ioc-контейнера как одного такого "реестра объектов" с конфигурацией правил их создания, определением реализаций где нужно, который умеет правильно очищать (через dispose) объекты с истекшим временем жизни, который строит дерево зависимостей и сам автоматически создаёт всё это дерево.

Т.е.:

IT>И здесь я опять вынужден повторить свой вопрос. Какую проблему решают DI фреймворки, которая по своей значимости способна перевесить вносимые в проект неудобства?


Я хотел примерно передать то, что выше описал (наверное, сумбурно). Я исходил из допущения, что разработчик а) знает о том, как работает ioc-контейнер в смысле того, что я выше описал; б) знает о конфигурировании сервисов в рамках приложения через ioc-контейнер. Но это же вроде классические для ioc-контейнеров понятия, т.е. ситуации:

IT>Если же используется DI фреймворк, то для того, чтобы понять что происходит необходимо запускать как минимум отладчик.


Возникнуть вроде и не должно.
Re[9]: О пользе Dependency Injection
От: microuser  
Дата: 15.01.21 15:52
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, microuser, Вы писали:


M>>С DI фреймворком ровным счетом ничего не меняется, только Shift-F12 нажимается не на конструкторе, а на названии класса. Дальше надо посмотреть лишь классы у которых в конструкторе есть параметр с типом Foo, и так же по цепочке раскручивается. Проблема надуманная, как мне кажется.


IT>И что это решает? Вот нашёл ты класс, который принимает Foo как параметр. Но преждем чем его принять тебе нужно создать этот Foo, а он при создании падает.


Так в данном примере вообще ничего искать не нужно, т.к. при использовании DI экземпляр Bar будет создаваться контейнером и все его зависимости будут так же создаваться контейнером, соответственно нужно посмотреть только код конфигурации этого контейнера. Кроме того современные контейнеры никогда к такой ситуации не приведут, т.к. Bar не сможет быть равен null, будет ошибка при попытке создания Foo о том что не удалось разрешить зависимость Boo и там же в стек трейсе будет видно почему не удалось.
Re[11]: О пользе Dependency Injection
От: #John Европа https://github.com/ichensky
Дата: 15.01.21 15:58
Оценка:
Здравствуйте, IT, Вы писали:

IT>Можно я ещё немного добавлю полезности? Спасибо!


IT>
IT>enum SourceType
IT>{
IT>    Foo,
IT>    ar
IT>}

IT>class Service
IT>{
IT>    public Service(IDependency1 dependency1, IDependency2 dependency2, SourceType sourceType)
IT>    {
IT>    }

IT>    public void DoSomeWork()
IT>    {
IT>        //...
IT>    }
IT>}
IT>


IT>Как DI фреймворк разрулит ситуацию для разных sourceType?


Тут создается зависимость на SourceType.
Суть DI паттерна как раз писать код так что бы не было зависимостей:
в конструкторе/методе мы объявляем контракты объектов, который можно передать как параметры, и нам не важно как реализованы эти объекты и что они будут делать.
Потому DI паттерн от фреймверков не зависит, фреймверки вообще можно не использовать для внедрения зависимостей.

Напр. тут мы внедряем зависимости без фреймверка, а просто вручную создаем все нужные нам объекты:

class Service1 : IService1
{
    public Service(IDependency1 dependency1, IDependency2 dependency2) { }
}
class Service2
{
    public Service(IService1) { }
}

void Main(){
  var dependency1 = new Dependency1();
  var dependency2 = new Dependency2();
  var service1 = new Service1(dependency1,dependency2);
  var service2 = new Service2(service1);
}
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[8]: О пользе Dependency Injection
От: IT Россия linq2db.com
Дата: 15.01.21 16:10
Оценка:
Здравствуйте, petroa, Вы писали:

IT>>Код кидает исключение. Твоя задача — найти причину. Если код без DI фрейворков, то эта задача из разряда примитивных.


P>Но в описываемой мною ситуации b не может быть null по определению,


Вот почему я даже не сомневался, что абстрагироваться от конкретной проблемы апологетам DI будет крайне трудно?
Давай по-другому. Bar приезжает, но поломаный и проблема возникает только в Foo. Нужно быстро найти того, кто мог сломать Bar перед тем как передать его в Foo.

P>Я хотел примерно передать то, что выше описал (наверное, сумбурно). Я исходил из допущения, что разработчик а) знает о том, как работает ioc-контейнер в смысле того, что я выше описал; б) знает о конфигурировании сервисов в рамках приложения через ioc-контейнер. Но это же вроде классические для ioc-контейнеров понятия, т.е. ситуации:

IT>>Если же используется DI фреймворк, то для того, чтобы понять что происходит необходимо запускать как минимум отладчик.
P>Возникнуть вроде и не должно.

Причём здесь знает или не знает? В концепции DI нет ничего сложного. В том или ином виде это используется уже десятки лет. Проблема в неявности. Это примерно как динамическая типизация против статической. При статической накосячить не даст компилятор. Проблемы динамической зачастую без отладчика не решаются.
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: О пользе Dependency Injection
От: IT Россия linq2db.com
Дата: 15.01.21 16:15
Оценка:
Здравствуйте, microuser, Вы писали:

M>Так в данном примере вообще ничего искать не нужно, т.к. при использовании DI экземпляр Bar будет создаваться контейнером и все его зависимости будут так же создаваться контейнером, соответственно нужно посмотреть только код конфигурации этого контейнера.


И что я там увижу? Список имён классов?

M>Кроме того современные контейнеры никогда к такой ситуации не приведут, т.к. Bar не сможет быть равен null, будет ошибка при попытке создания Foo о том что не удалось разрешить зависимость Boo и там же в стек трейсе будет видно почему не удалось.


По-поводу умения абстрагироваться я уже выше отписал.
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: О пользе Dependency Injection
От: petroa  
Дата: 15.01.21 16:16
Оценка:
IT>Вот почему я даже не сомневался, что абстрагироваться от конкретной проблемы апологетам DI будет крайне трудно?
IT>Давай по-другому. Bar приезжает, но поломаный и проблема возникает только в Foo. Нужно быстро найти того, кто мог сломать Bar перед тем как передать его в Foo.

Но каким образом он приезжает "поломанный", если он только что создан по правилам, определенным разработчиком же в конфигурации контейнера? Если его состояние не удовлетворяет получателя, то тоже совершенно всё очевидно где искать.

IT>Причём здесь знает или не знает? В концепции DI нет ничего сложного. В том или ином виде это используется уже десятки лет. Проблема в неявности. Это примерно как динамическая типизация против статической. При статической накосячить не даст компилятор. Проблемы динамической зачастую без отладчика не решаются.


Я как раз и пишу, что нет никакой неявности. Все совершенно явно описывается в конфигурации. Точно так же оно бы описывалось и руками, без контейнера ведь.

И просьба, все же, не надо про "я даже не сомневался, что апологетам DI будет крайне трудно", я в них не записывался
Re[12]: О пользе Dependency Injection
От: IT Россия linq2db.com
Дата: 15.01.21 16:16
Оценка:
Здравствуйте, #John, Вы писали:

J>Тут создается зависимость на SourceType.


Я знал, я знал!
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: О пользе Dependency Injection
От: IT Россия linq2db.com
Дата: 15.01.21 16:27
Оценка:
Здравствуйте, petroa, Вы писали:

P>Но каким образом он приезжает "поломанный", если он только что создан по правилам, определенным разработчиком же в конфигурации контейнера?


Мы тут выше обсуждали сценарий с Data Connection, которое живее всех живых в рамках сессии. Давай сделаем такое же допущение для Bar.

P>Я как раз и пишу, что нет никакой неявности. Все совершенно явно описывается в конфигурации. Точно так же оно бы описывалось и руками, без контейнера ведь.


Явно — это когда проверяется компилятором.
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: О пользе Dependency Injection
От: petroa  
Дата: 15.01.21 16:36
Оценка:
Здравствуйте, IT, Вы писали:

IT>Мы тут выше обсуждали сценарий с Data Connection, которое живее всех живых в рамках сессии. Давай сделаем такое же допущение для Bar.


Не читал особо, потому уточню. Bar — синглтон в рамках приложения, и ломается кем-то где-то, ты об этом? И в другом месте приезжает "поломанный"? Ну блин, как же это соотносится с ioc-контейнерм vs. условное ручное создание объектов. Хотя может неправильно понял, но честно, въезжать в какие-то контексты споров о сценариях с "Data Connection, которое живее всех живых в рамках сессии"... мы же в нашем контексте спорим.

IT>Явно — это когда проверяется компилятором.


Это идет вразрез с примерами, которые приводились, вроде "приезжает поломанным", или этот:

IT>
IT>class Foo
IT>{
IT>    public Foo(Bar b)
IT>    {
IT>        if (b == null)
IT>            throw ...
IT>    }
IT>}
IT>


Честно, я не очень понял почему у нас вдруг всплыл компилятор Как-то сильно в сторону, в другую оперу.
Re[12]: О пользе Dependency Injection
От: · Великобритания  
Дата: 15.01.21 19:05
Оценка: +1
Здравствуйте, petroa, Вы писали:

IT>>Явно — это когда проверяется компилятором.

P>Это идет вразрез с примерами, которые приводились, вроде "приезжает поломанным", или этот:
Он может приехать из какой-нибудь кастомной фабрики.

P>Честно, я не очень понял почему у нас вдруг всплыл компилятор Как-то сильно в сторону, в другую оперу.

Компилятор тут притом, что вот такие вещи "современные контейнеры никогда к такой ситуации не приведут, т.к. Bar не сможет быть равен null, будет ошибка при попытке создания Foo о том что не удалось разрешить зависимость Boo и там же в стек трейсе будет видно почему не удалось." в коде без контейнера будут тупо ошибками компиляции. А уж эти современные контейнерные стек-трейсы — это какое-то издевательство над здравым смыслом.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: О пользе Dependency Injection
От: Somescout  
Дата: 15.01.21 21:36
Оценка: :)
Здравствуйте, IT, Вы писали:

IT>>>Давай мы сразу определимся. Речь идёт не о DI как таковом, а о DI фреймворках и всяческих IoC контейнерах. Ты сейчас про что?

S>>О них в том числе. Я просто действительно не понимаю что именно вас в них смущает: у меня два проекта, когда из первого, построенного на DI потребовалось перенести компоненты во второй (без DI) — не возникло никаких проблем, я просто руками конструировал все объекты.

IT>Т.е. чтобы перенести код пришлось его не слабо так переписать. Правильно?


Нет, не правильно: код остался полностью без изменений. Только вместо вызова вида:
var instance = serviceProvider.Get<SomeObject>()

Появилось
var db = new DbContext();
var config = new AppConfig();
var instance = new SomeObject(db, config);


Вот и всё различие. Внутренности SomeObject не менялись.
ARI ARI ARI... Arrivederci!
Re[7]: О пользе Dependency Injection
От: Somescout  
Дата: 15.01.21 21:40
Оценка:
Здравствуйте, IT, Вы писали:

S>>Стоп. Давайте вы сначала покажете правильный (с вашей точки зрения) способ использования этого хелпера, а потом порассуждаем о достоинствах и недостатках. Иначе я буду просто предполагать, что вы предлагаете статический синглтон — и, думаю, не нужно говорить почему это плохая практика.


IT>Не-не-не. Нам твои DI фреймворки нафиг не нужны и нам без них хорошо. Покажи, что мы не правы, приведи код, где DI фремворки рулят.


Ок, по сравнению со статическим синглтоном, в DI нет завязки на глобальные объекты и глобальные состояния, управляемое время жизни у всех созданных объектов (например в рамках одного запроса будет использован ровно один контекст базы данных (если так сконфигурировано), кроме того все такие объекты будут освобождены после завершения запроса), предсказуемое время инициализации (синглтон будет инициализирован при первом обращении вызывая сайд-эффекты), можно сделать нормальную абстракцию, не привязываясь (опять же в отличии от глобальных состояний) к конкретным классам, а значит портируемость кода будет существенно выше.
ARI ARI ARI... Arrivederci!
Re[8]: О пользе Dependency Injection
От: Somescout  
Дата: 15.01.21 21:41
Оценка:
Здравствуйте, IT, Вы писали:

S>>Да я вроде уже в первом же комментарии это объяснял — вам не нужно конструировать контекст базы непосредственно внизу. А если абстрагироваться через интерфейсы, то компонент может вообще не знать с чем именно он работает — есть интерфейс для получения данных, он его и использует. А что за ним прячется: сама база, кэш или сервис — его не касается.


IT>При желании можно абстрагироваться даже от интерфейсов. Но я не буду говорить как, не дай боже вам это понравится.


Само собой не будете: вы уже который комментарий стесняетесь не то что код приводить, но даже хоть чуть-чуть в конкретику углубляться.
ARI ARI ARI... Arrivederci!
Re[12]: О пользе Dependency Injection
От: · Великобритания  
Дата: 15.01.21 22:30
Оценка:
Здравствуйте, Somescout, Вы писали:


S> Нет, не правильно: код остался полностью без изменений. Только вместо вызова вида:

S>
var instance = serviceProvider.Get<SomeObject>()

Лукавство. Ты покажи _весь_ код, откуда ты взял serviceProvider?

S> Появилось

S>
S> var db = new DbContext();
S> var config = new AppConfig();
S> var instance = new SomeObject(db, config);
S>

А вот это _весь_ код. Помещай его в main и запускай, будет работать. Притом быстро, без всяких рефлексий, рантайм-ошибок и километровых стек-трейсов.

S> Вот и всё различие. Внутренности SomeObject не менялись.

Не понял, а зачем их менять?
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: О пользе Dependency Injection
От: Министр Промышленности СССР  
Дата: 15.01.21 22:35
Оценка:
МП>>я имел в виду банальную задачу:
МП>>есть фарш исторического кода, который неправильно работает
МП>>ты разбираешься в какой момент всё идёт неправильно, отслеживаешь объекты где используются, откуда получаются
МП>>и вот на 7м-13м уровне вложенности вызывов ты понимаешь, тебе надо срочно знать откуда берётся значение вот в этом объекте
МП>>прыг F12 (у меня это решарперовский GoToDefinition)
МП>>ага есть конструктор прыг Alt+F7 (у меня это FindUsages) а хрен тебе — он вызывается неявно в рамках DI
МП>>и хорошо если ты это ещё знаешь
МП>>а то вполне можешь подумать "ага, значит инициализируется не здесь", и пойти исследовать фарш дальше вглубь!
МП>>и это убийственно

Y>ОК. Но при чём тут автоматический рефакторинг?


например, ввиду вышеизложенного, ты не можешь зачистить члены класса, которые вроде бы не используются
потому что на самом деле они могут использоваться через DI-фреймворк

и таким образом начинаешь стрематься на каждом шагу, который иначе бы сделал "в потоке"
Отредактировано 16.01.2021 2:19 Министр Промышленности . Предыдущая версия . Еще …
Отредактировано 15.01.2021 22:36 Министр Промышленности . Предыдущая версия .
Re[13]: О пользе Dependency Injection
От: Somescout  
Дата: 15.01.21 23:01
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Somescout, Вы писали:



S>> Нет, не правильно: код остался полностью без изменений. Только вместо вызова вида:

S>>
var instance = serviceProvider.Get<SomeObject>()

·>Лукавство. Ты покажи _весь_ код, откуда ты взял serviceProvider?

В смысле? Взял из конструктора:
public class CallerObj {
  private readonly IServiceProvider serviceProvider;
  
  public CallerObj(IServiceProvider serviceProvider) {
    this.serviceProvider = serviceProvider;
  }

  public void Something() {
    var instance = serviceProvider.Get<SomeObject>();
  }
}


Если вам интересен вариант когда провайдер создаётся вручную, то примерно так (псевдокод):
public void Something() {
  var serviceBuilder = new ServiceBuilder();
  serviceBuilder
    .Bind<IDbContext,DbContext>(Scope.Request) // Просто для примера - понято что области запроса в данном случае нет
    .Bind<IAppConfig, AppConfig>(Scope.Singleton);

  serviceBuilder.Bind<SomeObject>(Scope.Transient); // Тут зависит от реализации DI: NInject умеет создавать произвольный объект,
                                                    //   если для него зарегистрированы все зависимости, MS DI (из NetCore) 
                                                    //   требует явной регистрации всех создаваемых объектов

  var serviceProvider = serviceBuilder.Build();
  
  var instance = serviceProvider.Get<SomeObject>();
}


Понятно что этот способ (т.е. через ServiceProvider) используется исключительно в том случае, когда инициализация SomeObject дорогая и сам объект используется он не всегда (я использую его только в контроллере, когда лишь часть экшенов использует его), в обычном случае будет:

public class CallerObj {
  private readonly SomeObject someObject;
  
  public CallerObj(SomeObject someObject) {
    this.someObject = someObject;
  }

  public void Something() {
    ...
  }
}



S>> Появилось

S>>
S>> var db = new DbContext();
S>> var config = new AppConfig();
S>> var instance = new SomeObject(db, config);
S>>

·>А вот это _весь_ код. Помещай его в main и запускай, будет работать. Притом быстро, без всяких рефлексий, рантайм-ошибок и километровых стек-трейсов.

Ну да, сравниете с ручным созданием ServiceProvider — разница в несколько строк. И да, у меня почему-то ни разу не возникало ситуации, когда проблемы с DI были с "рантайм-ошибок и километровых стек-трейсов" — обычно просто сообщение, что требуемый объект не зарегистрирован.

И да, этот "весь код" явно ссылается на **реализации** используемых классов, затрудняя его переиспользование (за которое тут так ратуют), более того, если инициализация чуть сложнее (например нужно получить ConnectionString) — этот код ляжет не один раз в настройку DI, а во все его вызовы. Про всякие мелочи, вроде использование пулов или скоупы даже говорить бессмысленно.

S>> Вот и всё различие. Внутренности SomeObject не менялись.

·>Не понял, а зачем их менять?
Это вы у IT спросите. Я с самого начала писал что там ничего не менялось.
ARI ARI ARI... Arrivederci!
Отредактировано 15.01.2021 23:06 Somescout . Предыдущая версия . Еще …
Отредактировано 15.01.2021 23:02 Somescout . Предыдущая версия .
Re[14]: О пользе Dependency Injection
От: · Великобритания  
Дата: 15.01.21 23:45
Оценка:
Здравствуйте, Somescout, Вы писали:

S> В смысле? Взял из конструктора:

Этот антипаттерн называется Service Locator... Противоположность DI.

S> Если вам интересен вариант когда провайдер создаётся вручную, то примерно так (псевдокод):

Т.е. кода таки больше получилось.

S> Понятно что этот способ (т.е. через ServiceProvider) используется исключительно в том случае, когда инициализация SomeObject дорогая и сам объект используется он не всегда (я использую его только в контроллере, когда лишь часть экшенов использует его),

Вроде это банальный Lazy...

S> ·>А вот это _весь_ код. Помещай его в main и запускай, будет работать. Притом быстро, без всяких рефлексий, рантайм-ошибок и километровых стек-трейсов.

S> Ну да, сравниете с ручным созданием ServiceProvider — разница в несколько строк. И да, у меня почему-то ни разу не возникало ситуации, когда проблемы с DI были с "рантайм-ошибок и километровых стек-трейсов" — обычно просто сообщение, что требуемый объект не зарегистрирован.
А если не использовать фреймворк, то такого рода ошибки будут сразу в IDE подсвечиваться, как ошибки компиляции.

S> И да, этот "весь код" явно ссылается на **реализации** используемых классов, затрудняя его переиспользование (за которое тут так ратуют),

Такой код собирает конечное приложение, так называемый Composition Root. Если части приложения нужно переиспользовать, классы можно интегрировать в модуль с подходящими областями видимости и зависимостями, а не кидать всё в глобальный мусорный контейнер.

S> более того, если инициализация чуть сложнее (например нужно получить ConnectionString) — этот код ляжет не один раз в настройку DI, а во все его вызовы. Про всякие мелочи, вроде использование пулов или скоупы даже говорить бессмысленно.

Нет, тот же ConnectionString прокинется через ровно такой же DI.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 15.01.2021 23:47 · . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.