Help us improve
Share bugs, ideas, or general feedback.
From dex-skill-dotnet-di
.NET DI — ловушки регистрации, lifetime, Service Locator. Активируется при dependency injection, регистрация сервиса, AddScoped, AddSingleton, configure services, captive dependency, scoped в singleton, IServiceProvider, lifetime, DI, startup
How this skill is triggered — by the user, by Claude, or both
Slash command
/dex-skill-dotnet-di:dotnet-diThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Плохо: `AddSingleton<MyService>()` + `MyService(AppDbContext ctx)` — Scoped захвачен навсегда
Share bugs, ideas, or general feedback.
Плохо: AddSingleton<MyService>() + MyService(AppDbContext ctx) — Scoped захвачен навсегда
Правильно: IServiceScopeFactory + ручной scope, или перевести MyService в Scoped
Почему: DbContext живёт всё время приложения — change tracker растёт, данные stalе. ValidateScopes ловит только в Development по умолчанию
Плохо: AddTransient<IHeavyService, HeavyService>() где HeavyService : IDisposable — часто resolve в scope
Правильно: фабрика Func<IHeavyService> + ручной using, или Singleton если stateless
Почему: контейнер трекает все Transient IDisposable до конца scope и освобождает их только при его завершении
Плохо: services.AddSingleton<INotifier>(new EmailNotifier())
Правильно: services.AddSingleton<INotifier, EmailNotifier>() или фабричная лямбда
Почему: контейнер не управляет lifecycle вручную созданного экземпляра — Dispose() не будет вызван при завершении
Плохо: services.AddScoped<OrderService>()
Правильно: services.AddScoped<IOrderService, OrderService>()
Почему: невозможно замокать в тестах, декорировать через Scrutor, или заменить реализацию без изменения кода
Плохо: private readonly EmailService _email = new EmailService()
Правильно: инжекция через конструктор public OrderService(IEmailService email)
Почему: жёсткая привязка к реализации, невозможно замокать, нет управления lifecycle контейнером
Плохо: services.AddScoped<ICache, RedisCache>() в библиотечном коде — перезаписывает регистрацию хоста
Правильно: services.TryAddScoped<ICache, RedisCache>() — пропускает если уже зарегистрировано
Почему: Add* всегда добавляет (последняя побеждает при resolve одного), TryAdd* уважает явные регистрации потребителя
Плохо: services.AddScoped(typeof(IRepo<>), typeof(Repo<>)) — несовместимые generic constraints не видны компилятору
Правильно: проверять constraints вручную; добавить интеграционный тест на BuildServiceProvider()
Почему: контейнер не валидирует generic constraints при регистрации — exception только при первом resolve в runtime
Плохо: _serviceProvider.GetRequiredService<IOrderService>() внутри бизнес-логики
Правильно: инжекция через конструктор
Почему: зависимости скрыты, невидимы из конструктора. Тесты требуют настройки полного контейнера вместо одного мока. Исключение: фабрики, middleware, динамический resolve по типу
Плохо: services.Decorate<ICache, LoggingCache>() до services.AddScoped<ICache, RedisCache>()
Правильно: сначала Add*, затем Decorate
Почему: Decorate ищет существующую регистрацию — если её нет, выбрасывает InvalidOperationException
Плохо: [FromKeyedServices("primary")] + services.AddKeyedScoped<ICache, RedisCache>("primray") — опечатка
Правильно: константа const string PrimaryCache = "primary", используется в обоих местах
Почему: опечатка в ключе = InvalidOperationException в runtime, не compile-time ошибка
Плохо: captive dependency не обнаруживается на prod — ValidateScopes false по умолчанию вне Development
Правильно: включить ValidateOnBuild: true и ValidateScopes: true на staging или в интеграционных тестах
Почему: UseDefaultServiceProvider(o => { o.ValidateScopes = true; o.ValidateOnBuild = true; }) выбрасывает при старте, не в runtime
TryAdd*, не Add*, чтобы не перебивать регистрации хостаBuildServiceProvider()ValidateScopes + ValidateOnBuild в тестах и stagingnpx claudepluginhub dex-it/claude-code-marketplace --plugin dex-skill-dotnet-diCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.