[{"data":1,"prerenderedAt":106},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Fdependency-injection\u002Fservice-lifetimes":3},{"page":4,"siblings":93,"blog":103},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":12,"path":20,"questions":21,"questionsCount":84,"related":85,"seo":86,"seoDescription":87,"stem":88,"subtopic":6,"topic":89,"topicSlug":90,"updated":91,"__hash__":92},"qa\u002Fdotnet\u002Fdependency-injection\u002Fservice-lifetimes.md","Service Lifetimes",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,"\u002Fdotnet\u002Fdependency-injection\u002Fservice-lifetimes",[22,27,31,35,39,43,47,51,55,59,63,67,71,76,80],{"id":23,"difficulty":24,"q":25,"a":26},"three-lifetimes","easy","What are the three service lifetimes in .NET Core DI and when do you use each?","The DI container supports three lifetimes that control when a service instance is\ncreated and how long it lives.\n\n```csharp\n\u002F\u002F Singleton — one instance for the entire application lifetime:\nbuilder.Services.AddSingleton\u003CICache, MemoryCache>();\n\u002F\u002F Same instance returned for every request and every constructor injection.\n\u002F\u002F Use for: stateless or thread-safe services, expensive-to-create objects,\n\u002F\u002F in-memory caches, configuration wrappers, HttpClient via IHttpClientFactory.\n\n\u002F\u002F Scoped — one instance per HTTP request (or per explicit scope):\nbuilder.Services.AddScoped\u003CIOrderService, OrderService>();\n\u002F\u002F Same instance within a single request; new instance for the next request.\n\u002F\u002F Use for: DbContext, unit-of-work objects, per-request state like current user.\n\n\u002F\u002F Transient — new instance every time the service is resolved:\nbuilder.Services.AddTransient\u003CIEmailValidator, EmailValidator>();\n\u002F\u002F New instance injected into every constructor and every GetService\u003CT>() call.\n\u002F\u002F Use for: lightweight stateless services, or services with non-thread-safe state.\n```\n\nQuick reference:\n\n| Lifetime | Created | Disposed | Shared across requests? |\n|---|---|---|---|\n| Singleton | App start | App shutdown | Yes |\n| Scoped | Per request | End of request | Within one request |\n| Transient | Per resolve | End of scope | Never |\n\n**Rule of thumb:** Default to Scoped for application services. Use Singleton only for\nthread-safe, expensive, or shared state. Use Transient for lightweight stateless helpers.\n",{"id":28,"difficulty":24,"q":29,"a":30},"singleton-details","When should you use Singleton lifetime and what are the thread-safety requirements?","**Singleton** services are instantiated once and shared across all requests for the\nlifetime of the application. Because multiple concurrent requests share the same instance,\nit **must be thread-safe**.\n\n```csharp\n\u002F\u002F Good singleton — immutable or thread-safe state:\nbuilder.Services.AddSingleton\u003CIConfiguration>(); \u002F\u002F already singleton in ASP.NET Core\nbuilder.Services.AddSingleton\u003CIHttpClientFactory>(); \u002F\u002F thread-safe, manages pool\nbuilder.Services.AddSingleton\u003CIMemoryCache, MemoryCache>(); \u002F\u002F thread-safe\n\n\u002F\u002F Good: expensive-to-create object shared across requests:\nbuilder.Services.AddSingleton\u003CIConnectionMultiplexer>(sp =>\n    ConnectionMultiplexer.Connect(sp.GetRequiredService\u003CIConfiguration>()[\"Redis\"]));\n\n\u002F\u002F Bad singleton — mutable state without synchronization:\npublic class RequestCounter \u002F\u002F registered as Singleton\n{\n    private int _count; \u002F\u002F shared across all requests — race condition!\n    public void Increment() => _count++; \u002F\u002F not thread-safe\n}\n\n\u002F\u002F Fix: use thread-safe primitives:\npublic class RequestCounter\n{\n    private long _count;\n    public void Increment() => Interlocked.Increment(ref _count);\n    public long Get() => Interlocked.Read(ref _count);\n}\n\n\u002F\u002F Bad: singleton holding a scoped dependency (captive dependency):\npublic class PricingEngine \u002F\u002F Singleton\n{\n    public PricingEngine(AppDbContext db) { } \u002F\u002F AppDbContext is Scoped — BUG\n}\n```\n\n**Rule of thumb:** If a singleton holds shared mutable state, protect it with\n`Interlocked`, `lock`, or concurrent collections. Never let a singleton hold a\nScoped service — that creates a captive dependency.\n",{"id":32,"difficulty":24,"q":33,"a":34},"scoped-details","How does Scoped lifetime work in ASP.NET Core and what is the \"scope\" boundary?","**Scoped** services get one instance per DI **scope**. In ASP.NET Core, the framework\nautomatically creates a scope for each HTTP request and disposes it when the response\ncompletes. Two injections of the same scoped service within one request share the same\ninstance.\n\n```csharp\n\u002F\u002F AppDbContext is the canonical scoped service — one connection per request:\nbuilder.Services.AddScoped\u003CAppDbContext>();\n\n\u002F\u002F Both inject the same instance within a single request:\npublic class OrderService\n{\n    public OrderService(AppDbContext db) { _db = db; }\n}\n\npublic class InventoryService\n{\n    public InventoryService(AppDbContext db) { _db = db; }\n    \u002F\u002F Same AppDbContext instance as OrderService within this request\n}\n\n\u002F\u002F Creating a scope manually (needed in background services, tests, CLI):\nusing (var scope = app.Services.CreateScope())\n{\n    var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    await db.Database.MigrateAsync(); \u002F\u002F own scope, own connection\n} \u002F\u002F AppDbContext disposed here\n\n\u002F\u002F HttpContext.RequestServices exposes the request scope:\npublic class MyController : ControllerBase\n{\n    [HttpGet]\n    public IActionResult Get()\n    {\n        \u002F\u002F Resolved from the request scope (same as constructor injection):\n        var svc = HttpContext.RequestServices.GetRequiredService\u003CIOrderService>();\n        return Ok();\n    }\n}\n```\n\n**Rule of thumb:** Scope boundaries are your unit-of-work boundary. Register `DbContext`\nand anything that wraps a database connection as Scoped to get automatic per-request\nisolation and disposal.\n",{"id":36,"difficulty":24,"q":37,"a":38},"transient-details","When should you use Transient lifetime and what are its trade-offs?","**Transient** services are created fresh on every resolve — every constructor injection\nand every `GetService\u003CT>()` call yields a new instance. They're disposed at the end of\nthe enclosing scope (usually the HTTP request).\n\n```csharp\n\u002F\u002F Transient registration:\nbuilder.Services.AddTransient\u003CIEmailValidator, RegexEmailValidator>();\n\n\u002F\u002F Demonstration — each injection gets its own instance:\npublic class SignupService\n{\n    private readonly IEmailValidator _v1;\n    private readonly IEmailValidator _v2;\n\n    public SignupService(IEmailValidator v1, IEmailValidator v2)\n    {\n        \u002F\u002F v1 and v2 are different RegexEmailValidator instances\n        Console.WriteLine(ReferenceEquals(v1, v2)); \u002F\u002F false\n    }\n}\n\n\u002F\u002F Trade-offs:\n\u002F\u002F Safe for non-thread-safe objects — each consumer gets its own copy\n\u002F\u002F Good for lightweight, stateless helpers\n\u002F\u002F Can create many instances per request — avoid for expensive-to-construct types\n\u002F\u002F If the service holds resources (connections, file handles), disposal overhead\n\u002F\u002F multiplies with each resolve\n\n\u002F\u002F IDisposable transients — the scope owns disposal:\npublic class CsvWriter : IDisposable\n{\n    private readonly StreamWriter _writer;\n    public CsvWriter() => _writer = new StreamWriter(\"output.csv\");\n    public void Dispose() => _writer.Dispose();\n}\n\u002F\u002F Disposed at end of request scope — the container tracks IDisposable transients\n```\n\n**Rule of thumb:** Use Transient for cheap, stateless, non-thread-safe services.\nPrefer Singleton for stateless thread-safe services — Transient's per-resolve cost\nadds up fast in high-throughput endpoints.\n",{"id":40,"difficulty":14,"q":41,"a":42},"captive-dependency","What is a captive dependency and how do you detect and fix it?","A **captive dependency** occurs when a service with a longer lifetime holds a reference\nto a service with a shorter lifetime. The short-lived service effectively becomes\nlong-lived — living beyond its intended scope and potentially sharing state across\nrequests.\n\n```csharp\n\u002F\u002F Captive dependency: Singleton captures a Scoped service\npublic class ProductCache  \u002F\u002F Singleton\n{\n    private readonly AppDbContext _db; \u002F\u002F Scoped — lives per request\n\n    public ProductCache(AppDbContext db)\n    {\n        _db = db; \u002F\u002F db now lives forever — same instance across ALL requests\n        \u002F\u002F Any request-specific state in db leaks across requests → data corruption\n    }\n}\n\n\u002F\u002F Detection — enable ValidateScopes in development:\nbuilder.Host.UseDefaultServiceProvider(options =>\n{\n    options.ValidateScopes = app.Environment.IsDevelopment();\n});\n\u002F\u002F Without this, the bug silently causes intermittent data corruption in production.\n\n\u002F\u002F Fix 1: resolve scoped service per operation via IServiceScopeFactory:\npublic class ProductCache\n{\n    private readonly IServiceScopeFactory _factory;\n    public ProductCache(IServiceScopeFactory factory) => _factory = factory;\n\n    public async Task RefreshAsync()\n    {\n        using var scope = _factory.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        _products = await db.Products.ToListAsync();\n        \u002F\u002F scope and db disposed at end of using block\n    }\n}\n\n\u002F\u002F Fix 2: change the lifetime — if the class truly needs Scoped, register it Scoped:\nbuilder.Services.AddScoped\u003CProductCache>();\n\u002F\u002F Now it gets a fresh AppDbContext per request automatically\n```\n\n**Rule of thumb:** Captive dependencies are the most dangerous DI lifetime bug —\nthey corrupt request state silently. Enable `ValidateScopes` in development to catch\nthem at startup.\n",{"id":44,"difficulty":14,"q":45,"a":46},"iscope-factory","What is IServiceScopeFactory and when do you need it?","**`IServiceScopeFactory`** creates explicit DI scopes on demand — essential for any\ncode that runs outside the ASP.NET Core request pipeline (background services, hosted\nservices, console programs) where no automatic scope exists.\n\n```csharp\n\u002F\u002F Background service — no HTTP request scope exists:\npublic class DataSyncHostedService : BackgroundService\n{\n    private readonly IServiceScopeFactory _scopeFactory;\n    private readonly ILogger\u003CDataSyncHostedService> _logger;\n\n    public DataSyncHostedService(\n        IServiceScopeFactory scopeFactory,\n        ILogger\u003CDataSyncHostedService> logger)\n    {\n        _scopeFactory = scopeFactory;\n        _logger = logger;\n    }\n\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        while (!stoppingToken.IsCancellationRequested)\n        {\n            \u002F\u002F Create a fresh scope for each sync cycle:\n            using (var scope = _scopeFactory.CreateScope())\n            {\n                var db       = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n                var syncSvc  = scope.ServiceProvider.GetRequiredService\u003CISyncService>();\n\n                await syncSvc.SyncAsync(stoppingToken);\n                \u002F\u002F db and syncSvc disposed when scope is disposed (end of using)\n            }\n\n            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);\n        }\n    }\n}\n```\n\n`IServiceScopeFactory` is itself registered as a Singleton by the framework, so it can\nbe injected into Singleton services safely. The scopes it creates are independent and\nproperly bounded.\n\n**Rule of thumb:** Any Singleton that needs a Scoped service should inject\n`IServiceScopeFactory` and create a new scope per operation. Never inject Scoped\nservices directly into a Singleton constructor.\n",{"id":48,"difficulty":14,"q":49,"a":50},"disposal","How does the DI container handle IDisposable and IAsyncDisposable services?","The DI container **automatically disposes** services that implement `IDisposable` or\n`IAsyncDisposable` when their owning scope ends — Singleton at app shutdown, Scoped\nand Transient at the end of the request scope.\n\n```csharp\npublic class DatabaseConnection : IDisposable, IAsyncDisposable\n{\n    private SqlConnection _conn;\n\n    public DatabaseConnection(string connectionString)\n        => _conn = new SqlConnection(connectionString);\n\n    public void Dispose()\n    {\n        _conn?.Dispose();\n        _conn = null;\n    }\n\n    public async ValueTask DisposeAsync()\n    {\n        if (_conn is not null)\n        {\n            await _conn.DisposeAsync();\n            _conn = null;\n        }\n    }\n}\n\nbuilder.Services.AddScoped\u003CDatabaseConnection>();\n\u002F\u002F Disposed (DisposeAsync preferred) at the end of each HTTP request automatically.\n\n\u002F\u002F Singletons are disposed at app shutdown:\nbuilder.Services.AddSingleton\u003CIConnectionMultiplexer>(sp =>\n    ConnectionMultiplexer.Connect(\"localhost\"));\n\u002F\u002F ConnectionMultiplexer.Dispose() called when app.StopAsync() completes.\n\n\u002F\u002F Transients are tracked by the scope and disposed with it:\n\u002F\u002F If a Transient IDisposable is resolved from the root scope (e.g., app.Services),\n\u002F\u002F it won't be disposed until app shutdown — this is a memory leak.\n\u002F\u002F Always resolve Disposable Transients from a child scope.\n```\n\n**Rule of thumb:** Let the container own disposal — never call `Dispose()` on injected\nservices yourself. For root-scope transients that are `IDisposable`, create an explicit\nchild scope so disposal happens promptly.\n",{"id":52,"difficulty":14,"q":53,"a":54},"background-service-scopes","Why can't a BackgroundService inject Scoped services directly?","**`BackgroundService`** is registered as a **Singleton** (it runs for the app's lifetime).\nInjecting a Scoped service directly into its constructor creates a **captive dependency** —\nthe Scoped service becomes effectively Singleton and doesn't get disposed per request.\n\n```csharp\n\u002F\u002F WRONG — captive dependency; AppDbContext lives for the app lifetime:\npublic class OrderProcessor : BackgroundService\n{\n    private readonly AppDbContext _db; \u002F\u002F Scoped — wrong lifetime here\n\n    public OrderProcessor(AppDbContext db) \u002F\u002F container throws or creates a captive\n    {\n        _db = db;\n    }\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        \u002F\u002F _db is reused across ALL processing cycles — EF change tracker corrupts\n        while (!ct.IsCancellationRequested)\n            await ProcessNextOrderAsync(_db);\n    }\n}\n\n\u002F\u002F CORRECT — create a scope per work unit:\npublic class OrderProcessor : BackgroundService\n{\n    private readonly IServiceScopeFactory _factory;\n\n    public OrderProcessor(IServiceScopeFactory factory) => _factory = factory;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        while (!ct.IsCancellationRequested)\n        {\n            using var scope = _factory.CreateScope();\n            var db    = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n            var queue = scope.ServiceProvider.GetRequiredService\u003CIOrderQueue>();\n\n            await ProcessNextOrderAsync(db, queue);\n            \u002F\u002F db and queue properly disposed after each iteration\n        }\n    }\n}\n```\n\n**Rule of thumb:** `BackgroundService` constructors should only accept Singleton services\nplus `IServiceScopeFactory`. Create a new scope for every unit of work that needs Scoped\nservices (DbContext, unit-of-work, per-operation state).\n",{"id":56,"difficulty":14,"q":57,"a":58},"root-scope","What is the root scope in .NET DI and why is it a source of memory leaks?","The **root scope** is the `IServiceProvider` created by `builder.Build()`. It's the\ntop-level container that lives for the entire application lifetime. Resolving Scoped or\nTransient `IDisposable` services from the root scope leaks them until app shutdown.\n\n```csharp\nvar app = builder.Build();\n\n\u002F\u002F Resolving Scoped service from root scope — leaks until app shutdown:\nvar db = app.Services.GetRequiredService\u003CAppDbContext>();\n\u002F\u002F db is Scoped, but the root scope never ends → memory + connection leak\n\n\u002F\u002F Always create a child scope for one-off operations:\nusing (var scope = app.Services.CreateScope())\n{\n    var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    await db.Database.MigrateAsync(); \u002F\u002F db disposed at end of using block\n}\n\n\u002F\u002F With ValidateScopes = true, resolving a Scoped service from root throws:\nbuilder.Host.UseDefaultServiceProvider(options =>\n{\n    options.ValidateScopes = app.Environment.IsDevelopment();\n});\n\u002F\u002F InvalidOperationException: Cannot resolve scoped service from root provider.\n\n\u002F\u002F Safe: resolving Singleton from root is always fine:\nvar config = app.Services.GetRequiredService\u003CIConfiguration>(); \u002F\u002F OK\nvar cache  = app.Services.GetRequiredService\u003CIMemoryCache>();   \u002F\u002F OK\n```\n\n**Rule of thumb:** Never call `app.Services.GetRequiredService\u003CT>()` for Scoped or\nTransient services. Always wrap one-off resolutions in `CreateScope()`. Enable\n`ValidateScopes` to catch root-scope violations at startup in development.\n",{"id":60,"difficulty":14,"q":61,"a":62},"blazor-lifetimes","How do service lifetimes differ in Blazor Server vs Blazor WebAssembly?","Blazor's DI model differs from ASP.NET Core's request pipeline because Blazor Server\nkeeps a persistent SignalR circuit per browser tab, and Blazor WebAssembly runs entirely\nin the browser.\n\n```csharp\n\u002F\u002F Blazor Server — \"Scoped\" = per circuit (browser tab session), not per HTTP request:\nbuilder.Services.AddScoped\u003CIUserState, UserState>();\n\u002F\u002F Same instance across all component renders within one browser tab.\n\u002F\u002F A new tab → new circuit → new IUserState instance.\n\u002F\u002F This is a LONGER lifetime than ASP.NET Core Scoped (which is per-request).\n\n\u002F\u002F Singleton in Blazor Server — shared across ALL connected browser tabs!\nbuilder.Services.AddSingleton\u003CISharedCache, MemoryCache>();\n\u002F\u002F All users share this — only safe for truly shared, thread-safe state.\n\n\u002F\u002F Blazor WebAssembly — no server; runs in browser:\n\u002F\u002F Singleton = lives until the browser tab is closed or refreshed.\n\u002F\u002F Scoped    = same as Singleton in WASM (one scope for the whole app lifetime).\n\u002F\u002F Transient = new instance per injection, just like everywhere else.\nbuilder.Services.AddSingleton\u003CICartService, CartService>(); \u002F\u002F per tab in WASM\n\n\u002F\u002F Per-component transient state:\nbuilder.Services.AddTransient\u003CIComponentState, ComponentState>();\n\u002F\u002F New instance per component that injects it — use [CascadingParameter] instead\n\u002F\u002F for parent-to-child state sharing in Blazor.\n```\n\n**Rule of thumb:** In Blazor Server, treat Scoped as per-user-session and Singleton\nas shared-across-all-users. Never store user-specific state in a Singleton in Blazor Server.\n",{"id":64,"difficulty":14,"q":65,"a":66},"lifetime-mismatch-detection","How do you detect and prevent lifetime mismatch bugs at development time?","Lifetime mismatches are subtle bugs — they often don't fail immediately but cause data\ncorruption or state leaks in production. .NET provides built-in tooling to catch them.\n\n```csharp\n\u002F\u002F 1. Enable ValidateScopes + ValidateOnBuild (development only):\nbuilder.Host.UseDefaultServiceProvider((ctx, options) =>\n{\n    options.ValidateOnBuild = ctx.HostingEnvironment.IsDevelopment();\n    options.ValidateScopes  = ctx.HostingEnvironment.IsDevelopment();\n});\n\n\u002F\u002F 2. Write integration tests that build the real container:\npublic class DependencyInjectionTests\n{\n    [Fact]\n    public void AllServicesResolvable()\n    {\n        \u002F\u002F Use the real IServiceCollection from your app:\n        var services = new ServiceCollection();\n        Startup.ConfigureServices(services);\n\n        using var provider = services.BuildServiceProvider(\n            new ServiceProviderOptions\n            {\n                ValidateOnBuild = true,\n                ValidateScopes  = true,\n            });\n\n        \u002F\u002F If any registration is broken, BuildServiceProvider throws here:\n        Assert.NotNull(provider.CreateScope()\n            .ServiceProvider.GetRequiredService\u003CIOrderService>());\n    }\n}\n\n\u002F\u002F 3. Use the ASP.NET Core test host (validates real DI graph):\nawait using var factory = new WebApplicationFactory\u003CProgram>()\n    .WithWebHostBuilder(builder =>\n        builder.UseEnvironment(\"Development\")); \u002F\u002F triggers ValidateScopes\nvar client = factory.CreateClient();\n\u002F\u002F First request will throw if DI is misconfigured\n```\n\n**Rule of thumb:** Make DI validation part of CI — either via integration tests that\nbuild the real container or by running the app in Development mode with `ValidateScopes`\nand `ValidateOnBuild` enabled.\n",{"id":68,"difficulty":14,"q":69,"a":70},"transient-vs-singleton-perf","What are the performance implications of choosing Transient vs Singleton for stateless services?","**Singleton** is almost always faster for stateless services — allocation, garbage\ncollection, and constructor cost happen once at startup rather than on every resolve.\nTransient multiplies that cost by every request and every inject site.\n\n```csharp\n\u002F\u002F Scenario: a stateless email validator resolved thousands of times per second.\n\n\u002F\u002F Transient — new RegexEmailValidator() on every resolution:\nbuilder.Services.AddTransient\u003CIEmailValidator, RegexEmailValidator>();\n\u002F\u002F Cost per resolution: heap allocation + Regex compilation (if not pre-compiled)\n\u002F\u002F   + GC pressure accumulates under high throughput.\n\n\u002F\u002F Singleton — one instance created at startup, shared for app lifetime:\nbuilder.Services.AddSingleton\u003CIEmailValidator, RegexEmailValidator>();\n\u002F\u002F Cost per resolution: dictionary lookup only — no allocation.\n\u002F\u002F Safe because RegexEmailValidator has no mutable state.\n\n\u002F\u002F Benchmark illustration (not real numbers — for illustration only):\n\u002F\u002F 1M resolutions: Transient ~300ms | Singleton ~5ms\n\n\u002F\u002F Transient is correct when the service holds non-thread-safe mutable state:\npublic class CsvBuilder \u002F\u002F not thread-safe — each caller needs its own instance\n{\n    private readonly StringBuilder _sb = new();\n    public void AddRow(string[] cells) => _sb.AppendJoin(',', cells);\n    public string Build() => _sb.ToString();\n}\nbuilder.Services.AddTransient\u003CCsvBuilder>(); \u002F\u002F correct: new per injection\n\n\u002F\u002F Singleton is wrong for non-thread-safe types:\nbuilder.Services.AddSingleton\u003CCsvBuilder>(); \u002F\u002F Bad: shared StringBuilder corrupts\n```\n\n**Rule of thumb:** For stateless, thread-safe services, prefer Singleton. The allocation\ncost of Transient is negligible for lightweight types, but it becomes measurable in\nhot paths. Profile before over-optimizing, but design stateless helpers to be Singleton-safe.\n",{"id":72,"difficulty":73,"q":74,"a":75},"scoped-outside-request","hard","How do you use Scoped services outside the ASP.NET Core request pipeline?","Outside the HTTP request pipeline — CLI tools, unit tests, EF migrations, integration\ntest setup, worker services — no scope exists automatically. You must create one\nexplicitly via `IServiceScopeFactory` or `IServiceProvider.CreateScope()`.\n\n```csharp\n\u002F\u002F Pattern 1: one-off operation after app.Build() (e.g., run EF migrations):\nvar app = builder.Build();\n\nusing (var scope = app.Services.CreateScope())\n{\n    var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    await db.Database.MigrateAsync();\n    \u002F\u002F scope and db disposed at end of using block\n}\n\nawait app.RunAsync();\n\n\u002F\u002F Pattern 2: integration test setup with WebApplicationFactory:\npublic class OrdersIntegrationTest : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly WebApplicationFactory\u003CProgram> _factory;\n\n    public OrdersIntegrationTest(WebApplicationFactory\u003CProgram> factory)\n        => _factory = factory;\n\n    [Fact]\n    public async Task SeedDatabase_ThenQueryViaApi()\n    {\n        \u002F\u002F Create a scope for direct DB access in the test:\n        using var scope = _factory.Services.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        db.Orders.Add(new Order { Id = 1, Total = 99.99m });\n        await db.SaveChangesAsync();\n\n        \u002F\u002F Now hit the real API endpoint:\n        var client   = _factory.CreateClient();\n        var response = await client.GetAsync(\"\u002Forders\u002F1\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n\n\u002F\u002F Pattern 3: console \u002F worker service (no HTTP pipeline at all):\nvar host = Host.CreateDefaultBuilder(args)\n    .ConfigureServices(services =>\n    {\n        services.AddScoped\u003CAppDbContext>();\n        services.AddScoped\u003CIDataImporter, CsvDataImporter>();\n    })\n    .Build();\n\nusing (var scope = host.Services.CreateScope())\n{\n    var importer = scope.ServiceProvider.GetRequiredService\u003CIDataImporter>();\n    await importer.ImportAsync(\"data.csv\");\n}\n```\n\n**Rule of thumb:** Any code that runs outside a request scope must create its own scope\nusing `CreateScope()`. Dispose the scope as soon as the unit of work is complete so\nScoped services (DbContext, connections) are released promptly.\n",{"id":77,"difficulty":73,"q":78,"a":79},"singleton-thread-safety-patterns","What patterns ensure thread safety in Singleton services?","Singleton services are shared across all concurrent requests, so any mutable shared\nstate must be protected. The right tool depends on the access pattern.\n\n```csharp\n\u002F\u002F Pattern 1: immutability — no synchronization needed:\npublic class RegionConfig \u002F\u002F Singleton\n{\n    \u002F\u002F Populated once at construction; never mutated afterward:\n    private readonly IReadOnlyDictionary\u003Cstring, string> _regions;\n\n    public RegionConfig(IConfiguration config)\n        => _regions = config.GetSection(\"Regions\")\n            .GetChildren()\n            .ToDictionary(s => s.Key, s => s.Value ?? \"\");\n\n    public string? GetEndpoint(string region)\n        => _regions.TryGetValue(region, out var url) ? url : null;\n}\n\n\u002F\u002F Pattern 2: Interlocked for counters and simple values:\npublic class RequestMetrics \u002F\u002F Singleton\n{\n    private long _totalRequests;\n    private long _failedRequests;\n\n    public void RecordSuccess() => Interlocked.Increment(ref _totalRequests);\n    public void RecordFailure()\n    {\n        Interlocked.Increment(ref _totalRequests);\n        Interlocked.Increment(ref _failedRequests);\n    }\n    public long Total   => Interlocked.Read(ref _totalRequests);\n    public long Failures => Interlocked.Read(ref _failedRequests);\n}\n\n\u002F\u002F Pattern 3: ConcurrentDictionary for concurrent read-write maps:\npublic class InMemoryCache\u003CTKey, TValue> where TKey : notnull \u002F\u002F Singleton\n{\n    private readonly ConcurrentDictionary\u003CTKey, TValue> _store = new();\n\n    public TValue GetOrAdd(TKey key, Func\u003CTKey, TValue> factory)\n        => _store.GetOrAdd(key, factory); \u002F\u002F thread-safe by design\n\n    public bool TryRemove(TKey key, out TValue? value)\n        => _store.TryRemove(key, out value);\n}\n\n\u002F\u002F Pattern 4: ReaderWriterLockSlim for infrequent writes, frequent reads:\npublic class RoutingTable \u002F\u002F Singleton\n{\n    private Dictionary\u003Cstring, string> _routes = new();\n    private readonly ReaderWriterLockSlim _lock = new();\n\n    public string? Resolve(string path)\n    {\n        _lock.EnterReadLock();\n        try   { return _routes.TryGetValue(path, out var dest) ? dest : null; }\n        finally { _lock.ExitReadLock(); }\n    }\n\n    public void Reload(Dictionary\u003Cstring, string> newRoutes)\n    {\n        _lock.EnterWriteLock();\n        try   { _routes = newRoutes; }\n        finally { _lock.ExitWriteLock(); }\n    }\n}\n```\n\n**Rule of thumb:** Prefer immutable state for singletons — no locks needed. When you\nneed mutable shared state, use `Interlocked` for scalars, `ConcurrentDictionary` for\nmaps, and `ReaderWriterLockSlim` for rarely-written, frequently-read structures.\n",{"id":81,"difficulty":14,"q":82,"a":83},"scoped-lifetime-grpc","How does service lifetime work in gRPC services with ASP.NET Core?","gRPC services in ASP.NET Core are treated like controllers — the framework creates a\n**new instance per RPC call** (equivalent to per-request). DI lifetime rules apply\nthe same way as in HTTP middleware and controllers.\n\n```csharp\n\u002F\u002F gRPC service — one instance per RPC call by default:\npublic class OrderGrpcService : OrderService.OrderServiceBase\n{\n    private readonly IOrderRepository _orders; \u002F\u002F Scoped — safe; new per RPC call\n    private readonly ILogger\u003COrderGrpcService> _logger;\n\n    public OrderGrpcService(IOrderRepository orders, ILogger\u003COrderGrpcService> logger)\n    {\n        _orders = orders;\n        _logger = logger;\n    }\n\n    public override async Task\u003COrderReply> GetOrder(\n        OrderRequest request, ServerCallContext context)\n    {\n        _logger.LogInformation(\"GetOrder called for id={Id}\", request.Id);\n        var order = await _orders.GetByIdAsync(request.Id);\n        return order is null\n            ? throw new RpcException(new Status(StatusCode.NotFound, \"Order not found\"))\n            : new OrderReply { Id = order.Id, Total = (double)order.Total };\n    }\n}\n\n\u002F\u002F Registration — same as any ASP.NET Core service:\nbuilder.Services.AddScoped\u003CIOrderRepository, EfOrderRepository>();\nbuilder.Services.AddGrpc();\napp.MapGrpcService\u003COrderGrpcService>();\n\n\u002F\u002F Streaming RPCs — the single service instance handles the entire stream:\n\u002F\u002F For server-streaming methods, the same Scoped IOrderRepository instance is used\n\u002F\u002F throughout the stream lifetime — which is the duration of the RPC call, not per message.\n\n\u002F\u002F Warning: Singleton state shared across all concurrent gRPC calls — same rules as HTTP:\nbuilder.Services.AddSingleton\u003CIGrpcMetrics, GrpcMetrics>(); \u002F\u002F must be thread-safe\n```\n\n**Rule of thumb:** In gRPC services, treat each RPC call as an HTTP request.\nScoped services are safe because the framework creates a fresh DI scope per call.\nSingleton services must still be thread-safe — concurrent streams share them.\n",15,null,{"description":11},"Service lifetime interview questions — Singleton vs Scoped vs Transient, captive dependencies, IServiceScopeFactory, disposal, and ValidateScopes.","dotnet\u002Fdependency-injection\u002Fservice-lifetimes","Dependency Injection","dependency-injection","2026-06-23","Hkr_1apWc4rCJ3x7rdTiH-fvfTFNci5Uh5mZdiXes7k",[94,98,99],{"subtopic":95,"path":96,"order":97},"DI Basics","\u002Fdotnet\u002Fdependency-injection\u002Fdi-basics",1,{"subtopic":6,"path":20,"order":12},{"subtopic":100,"path":101,"order":102},"Options Pattern","\u002Fdotnet\u002Fdependency-injection\u002Foptions-pattern",3,{"path":104,"title":105},"\u002Fblog\u002Fdotnet-service-lifetimes","Service Lifetimes in .NET Core DI",1782244118521]