Создавая Mechie в течение многих лет, я заметил, что было немало недопониманий относительно того, как следует использовать ServiceCollection в приложении.

Самый большой вопрос заключается в том, когда я должен использовать каждый из различных типов регистрации. Прежде чем я углублюсь в детали, следует отметить несколько важных концепций. NetCore Environment в основном ориентирован на обработку веб-запросов, поэтому большинство различий помогут только в этих контекстах.

Еще один момент, на который следует обратить внимание, — это различия между контроллерами и службами. Основное отличие состоит в том, что контроллеры отвечают на веб-запросы напрямую, а сервисы — нет. Контроллеры и службы внедряют службы, но ни один из них не должен внедрять контроллеры.

Эта инъекция в основном выполняется через конструкторы служб и контроллеров, запрашивающих интерфейсы службы, которые они ищут. Хотя иногда это можно сделать в вызове метода, это может добавить ненужной сложности проектам, если к ним не относиться с осторожностью. Без осторожности циклические зависимости сломают приложение.

В чем разница между различными типами регистрации в Службе?

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

AddTransient — каждый раз, когда запрашивается этот класс, это будет совершенно новый экземпляр. Если два разных сервиса запросят его, они получат два разных экземпляра этого класса.

AddSingleton — при запуске приложения они создаются один раз и только один раз. Все разные запросы будут получать один и тот же экземпляр.

Итак, чтобы сэкономить на производительности, я всегда должен использовать AddSingleton?

Не всегда. Это уменьшит время запуска каждого запроса, но будет стоить времени запуска. Если бы у вас были сервисы, которые использовались очень редко, они бы конструировались каждый раз при запуске приложения. AddScoped кажется лучшим компромиссом, поскольку каждая служба создается только один раз для запроса и повторно используется, когда она используется в этом запросе. AddTransient будет дороже, так как каждый раз, когда он используется, он будет создавать его снова.

Чем это отличается в контексте выполнения лямбда-выражения?

Поскольку Lambda Recycling непредсказуем, лучше не полагаться на что-либо продолжительное между запросами. Если что-то поддерживается между запросами, Отлично, мы можем запуститься немного быстрее.

Службы AddTransient и AddScoped по-прежнему будут вести себя точно так же. Это потому, что их срок службы короче, чем у Lambda, в котором они работают.

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

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

Зачем мне тогда использовать AddSingleton?

В тех случаях, когда у вас есть система, управляющая локальными ресурсами лямбда, это было бы полезно. Если у вас есть система, которая управляет файлами в лямбда-выражении, или есть код, который не является потокобезопасным, использование службы Singleton предотвратит возникновение некоторых проблем в многопоточной среде.

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

Я столкнулся с проблемами здесь, когда использовал службу с ограниченной областью действия для обработки соединений с БД, и через ~ 10 минут соединение было повторно использовано базой данных. Это никогда не случалось регулярно с другими службами, потребляющими его. но когда служба singleton использовала его часто, мы достигали этого 10-минутного ограничения по времени. Чтобы предотвратить это, я смог разрешить эти службы, когда они были необходимы, в вызове метода, а не в обычном внедрении конструктора. Таким образом, мы всегда будем получать новую версию этой службы и не беспокоиться о тайм-ауте.

Я хочу внедрить службу, но в методе, не используя конструктор, как мне это сделать?

Это можно сделать! Во-первых, вам нужно убедиться, что служба вводит IServiceProvider. Эта служба предоставляет GetServiceметод, который мы можем использовать для разрешения служб во время выполнения.

Я использую GetService<T>() в качестве оболочки для поддержки типизации службы, я запрашиваю без необходимости вводить тип дважды.

Затем внутри сервиса мы можем просто вызвать этот метод GetService<T>() с нужным нам сервисом, и он будет самым свежим, который может получить поставщик услуг.

У меня есть странный случай, когда мне нужно предоставить что-то странное. Как это сделать?

Существуют способы предоставления странных услуг в тех случаях, когда вы пытаетесь модифицировать или переделывать существующий код.

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

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

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