Підрозділ 21.Q
Питання для самоконтролю
Питання для самоконтролю — Розділ 21. Generic Host та Dependency Injection 21.1. Generic Host 1. Назвіть три ролі Generic Host в .NET застосунку. Які проблеми він вирішує порівняно зі стандартним підходом "все
Питання для самоконтролю — Розділ 21. Generic Host та Dependency Injection
21.1. Generic Host
Назвіть три ролі Generic Host в .NET-застосунку. Які проблеми він вирішує порівняно зі стандартним підходом "все в
Main()"? Що відбувається без хоста при спробі реалізувати DI, конфігурацію та логування вручну?Розгляньте код:
var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddSingleton<IPatientService, PatientService>(); services.AddHostedService<SchedulerWorker>(); }) .Build(); await host.RunAsync();Що автоматично налаштовує
Host.CreateDefaultBuilder? Що робитьBuild()? ЧомуRunAsync()блокує до отримання Ctrl+C?Що таке
IHostedService? Назвіть два методи інтерфейсу та поясніть їх параметрCancellationToken. Як він відрізняється відBackgroundService? У яких випадках краще реалізовуватиIHostedServiceнапряму?Опишіть порядок запуску та зупинки хоста: коли викликаються
StartAsyncкожногоIHostedService? У якому порядку викликаютьсяStopAsync? Що відбувається з Singleton-ами, що реалізуютьIDisposable?Реалізуйте
BackgroundService-класHeartbeatWorker, що кожні 30 секунд записує в лог рядок "alive" і коректно завершується при зупинці хоста (обробляєCancellationTokenу циклі).Порівняйте Generic Host і
WebApplication(мінімальний ASP.NET Core). Що спільного і чим вони відрізняються? Коли варто використовувати Generic Host без ASP.NET Core?Що таке fluent API в контексті
IHostBuilder? Поясніть методиConfigureServices,ConfigureAppConfiguration,ConfigureLogging. Чи можна викликатиConfigureServicesдвічі в ланцюжку і що відбудеться?
21.2. IServiceCollection
Що таке
ServiceDescriptor? Назвіть три поля, що він містить. Які три форми реєстрації сервісів існують вIServiceCollection? Наведіть приклад кожної.Розгляньте код:
services.AddSingleton<ILogger, FileLogger>(); services.AddSingleton<ILogger, ConsoleLogger>(); var logger = provider.GetService<ILogger>(); var allLoggers = provider.GetServices<ILogger>();Що поверне
GetService<ILogger>()? Що повернеGetServices<ILogger>()? Яким чином використатиallLoggersдля відправки логу всім реалізаціям одночасно?Поясніть різницю між
AddSingleton,TryAddSingletonтаAddSingletonз перевіркою. КолиTryAddSingletonзахищає від подвійної реєстрації? Наведіть сценарій, де це важливо.Що відбувається після виклику
BuildServiceProvider()? Чи можна реєструвати нові сервіси післяBuild? Що таке "фіксація колекції" (locking)?Що таке
ValidateOnBuild? Яку помилку він виловлює ще на старті? Напишіть приклад неправильної реєстрації (де залежність не зареєстрована), щоValidateOnBuildзнайде при запуску.Що таке антипаттерн Service Locator? Порівняйте з Constructor DI за критеріями: явність залежностей, тестованість, відстеження залежностей. Наведіть приклад коду обома способами та поясніть, чому один кращий.
Коли
IServiceProviderу коді є прийнятним (не антипаттерном)? Назвіть 3 легітимних сценарії і поясніть кожен.
21.3. Service Lifetimes
Порівняйте три lifetime-и: Singleton, Scoped, Transient. Заповніть таблицю: скільки екземплярів на процес/scope/resolve, чи потрібна thread-safety, типовий use case.
Розгляньте код:
services.AddSingleton<MySingletonService>(); services.AddScoped<MyDbContext>(); services.AddTransient<MyHelperService>();MySingletonServiceу конструкторі приймаєMyDbContext. Що станеться? Яка ця проблема називається і чому вона небезпечна?Поясніть "captive dependency" (захоплена залежність) детально: чому Singleton, що тримає Scoped, є помилкою? Що конкретно відбувається зі Scoped-сервісом у цьому випадку (чи він знищується, чи живе нескінченно)?
Що таке
IServiceScopeFactory? Напишіть реалізацію Singleton-сервісуReportGeneratorService, що використовуєIServiceScopeFactoryдля правильного доступу до Scoped-залежностіIReportRepositoryвсередині методуGenerateReport().Правило "lifetime залежності не може бути коротшим за lifetime споживача" — поясніть усі заборонені комбінації (Singleton→Scoped, Singleton→Transient, Scoped→Transient). Які з них дозволені і чому?
Розгляньте сценарій:
services.AddTransient<IEmailSender, SmtpEmailSender>();SmtpEmailSenderреалізуєIDisposableі відкриває TCP-з'єднання. Яка проблема виникне, якщоIEmailSenderрезолвиться з кореневогоIServiceProvider(не зі scope)? Як це виправити?Для кожного lifetime наведіть конкретний приклад класу в медичній системі (клінічна ІС), де він є природним вибором: Singleton → ?, Scoped → ?, Transient → ?. Обґрунтуйте кожен вибір.
Напишіть клас
InstanceCounterз полемpublic int Id { get; }, що у конструкторі отримує унікальний ID черезInterlocked.Increment. Зареєструйте його як Singleton, Scoped і Transient в одному тестовому застосунку та продемонструйте різницю в ID між трьома resolve-ами.
21.4. Options Pattern
Що таке проблема "магічних рядків" при роботі з
IConfiguration? Чомуconfiguration["Database:ConnectionString"]є поганою практикою? Як Options Pattern вирішує цю проблему?Поясніть три кроки впровадження Options Pattern: POCO клас, реєстрація в DI, отримання через конструктор. Напишіть повний приклад для
DatabaseOptionsз полямиConnectionString,CommandTimeout,MaxRetries.Порівняйте
IOptions<T>,IOptionsSnapshot<T>іIOptionsMonitor<T>за: lifetime, коли перечитує config, підтримка hot reload, використання в Singleton/Scoped. Коли кожен з них є правильним вибором?Розгляньте код:
public class SmtpService { private readonly SmtpOptions _opts; public SmtpService(IOptions<SmtpOptions> options) { _opts = options.Value; } }Якщо
SmtpServiceзареєстрований як Singleton і config змінюється під час роботи — чи побачитьSmtpServiceнові значення? Що треба змінити, щоб побачив?Що таке Named Options? Напишіть приклад реєстрації двох різних конфігурацій
SmtpOptions("primary" і "backup") та отримання потрібної черезIOptionsMonitor<SmtpOptions>.Get("primary").Як валідувати Options за допомогою Data Annotations? Напишіть клас
AppointmentOptionsз атрибутами[Required],[Range]і покажіть, як підключитиValidateDataAnnotations()таValidateOnStart()так, щоб помилки конфігурації виявлялися на старті.Поясніть пріоритет джерел конфігурації (від нижчого до вищого):
appsettings.json,appsettings.{Environment}.json, User Secrets, змінні середовища, аргументи командного рядка. Навіщо саме такий порядок? Наведіть реальний сценарій, де кожен рівень корисний.Дизайн задача: потрібно реалізувати перемикання між production і staging режимами без перекомпіляції коду, де staging конфігурація перекриває тільки окремі поля. Опишіть рекомендовану стратегію з файлами
appsettings.jsonіappsettings.Staging.json, змінними середовища та чому Options Pattern тут кращий заIConfigurationнапряму.