[{"data":1,"prerenderedAt":109},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Faspnet-core\u002Fmiddleware":3},{"page":4,"siblings":93,"blog":106},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":84,"related":85,"seo":86,"seoDescription":87,"stem":88,"subtopic":6,"topic":89,"topicSlug":90,"updated":91,"__hash__":92},"qa\u002Fdotnet\u002Faspnet-core\u002Fmiddleware.md","Middleware",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,1,"\u002Fdotnet\u002Faspnet-core\u002Fmiddleware",[23,28,32,36,40,44,48,52,56,60,64,68,72,76,80],{"id":24,"difficulty":25,"q":26,"a":27},"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":29,"difficulty":25,"q":30,"a":31},"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":33,"difficulty":14,"q":34,"a":35},"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":37,"difficulty":14,"q":38,"a":39},"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":41,"difficulty":14,"q":42,"a":43},"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":45,"difficulty":14,"q":46,"a":47},"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":49,"difficulty":14,"q":50,"a":51},"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":53,"difficulty":25,"q":54,"a":55},"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":57,"difficulty":14,"q":58,"a":59},"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":61,"difficulty":14,"q":62,"a":63},"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":65,"difficulty":14,"q":66,"a":67},"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":69,"difficulty":25,"q":70,"a":71},"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":73,"difficulty":14,"q":74,"a":75},"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":77,"difficulty":14,"q":78,"a":79},"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":81,"difficulty":14,"q":82,"a":83},"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":11},"ASP.NET Core middleware interview questions — request pipeline, Use vs Run vs Map, custom middleware, ordering, and short-circuiting.","dotnet\u002Faspnet-core\u002Fmiddleware","ASP.NET Core","aspnet-core","2026-06-23","8vRg6odXkVV3Jro2R3wievDNQDEkeqxD0pQKKa6Jf0A",[94,95,98,102],{"subtopic":6,"path":21,"order":20},{"subtopic":96,"path":97,"order":12},"Routing","\u002Fdotnet\u002Faspnet-core\u002Frouting",{"subtopic":99,"path":100,"order":101},"Controllers & Actions","\u002Fdotnet\u002Faspnet-core\u002Fcontrollers-actions",3,{"subtopic":103,"path":104,"order":105},"Configuration","\u002Fdotnet\u002Faspnet-core\u002Fconfiguration",4,{"path":107,"title":108},"\u002Fblog\u002Fdotnet-aspnet-core-middleware-pipeline","How the ASP.NET Core Middleware Pipeline Works",1782244118073]