View as Markdown
Interviews

ASP.NET Core Interview Questions: The Pipeline Questions Everyone Gets Wrong

CareerCTO14 min read

ASP.NET Core Interview Questions: The Pipeline Questions Everyone Gets Wrong — Interviews

Most ASP.NET Core interview failures come from three topics - middleware order, the hosting model, and configuration precedence - not from obscure trivia. This guide walks through the questions that expose real understanding and explains why the common wrong answers sound so convincing.

Ask an ASP.NET Core candidate to explain the middleware pipeline and most will recite UseRouting, UseAuthentication, UseAuthorization in the right order.

Ask them why that order matters, or what happens if you swap two lines, and the answers get shaky fast.

This is the pattern across ASP.NET Core interviews. Candidates memorize the sequence of method calls in Program.cs without understanding what each one does to the request.

That gap shows up the moment you ask a follow-up question instead of a recall question.

This guide is built around the three areas where that gap appears most often: middleware ordering, the hosting model, and configuration precedence.

We then widen out to dependency injection, EF Core, and testing, because a real interview will touch those too.

If you are mapping the wider .NET stack before your interviews, the .NET full stack developer roadmap is a useful companion.

It covers where ASP.NET Core sits relative to the database, frontend, and deployment skills a full stack role expects.

Why these three topics catch people out

Middleware order, hosting, and configuration are all "it just works until it doesn't" topics. The default templates set them up correctly, so a developer can ship features for years without reasoning about them directly.

That is exactly why interviewers ask about them. A candidate who has only used the defaults will describe what the code looks like.

A candidate who has debugged a production issue caused by one of these three will describe what the code does, and why the order is not arbitrary.

None of the three topics require memorizing anything obscure. They require understanding what problem each piece of the framework was built to solve.

That is a very different kind of preparation than reading a cheat sheet the night before.

Middleware ordering: the question everyone can recite but few can explain

The standard opener is "walk me through the ASP.NET Core middleware pipeline." Most candidates give a list.

The better question, and the one that actually separates candidates, is "what breaks if you move UseAuthorization above UseAuthentication?"

What the pipeline actually is

Middleware is not a list of independent steps. It is a chain of delegates, each one wrapping the next.

Every middleware component gets a chance to act before calling the next one in line, and again after that call returns. Picture nested layers, not a flat sequence.

This is why order changes behavior. A middleware placed early sees the request first on the way in, and last on the way out. One placed late only sees what earlier middleware chose to pass through.

The order that matters most

Here is the sequence most real applications need, and why each piece sits where it does.

Middleware Purpose Why it sits here
Exception handler Catches unhandled errors Must wrap everything else to catch failures anywhere downstream
HTTPS redirection Forces HTTPS Runs before anything that reads the request body or headers
Static files Serves files directly Short-circuits early so static assets skip the rest of the pipeline
Routing (UseRouting) Matches the request to an endpoint Authorization needs to know which endpoint was matched
CORS Applies cross-origin rules Runs after routing so it can see endpoint-specific CORS policies
Authentication (UseAuthentication) Identifies who is making the request Authorization needs an identity to check
Authorization (UseAuthorization) Decides if the identified user can proceed Needs both the matched endpoint and the identity

The pattern to explain out loud: routing decides which endpoint will handle the request. Authentication answers "who is this?" Authorization answers "is this person allowed to do this?"

You cannot answer the second and third questions before the first one is settled.

The trap answer

A common wrong answer is "authorization comes before authentication because you check permissions before letting someone in." That sounds intuitive but gets the two words backwards.

Authentication establishes identity. Authorization checks what that identity is allowed to do. You cannot check permissions for a user you have not identified yet.

If UseAuthorization runs before UseAuthentication, the authorization middleware has no identity to evaluate. Requests that should be allowed get rejected, or checks silently pass because there is nothing to fail against.

A short-circuit question worth asking

"What happens if a middleware never calls the next delegate in the chain?" The pipeline stops there.

Nothing downstream runs, including logging or error handling registered after it. This is intentional for static file serving, and a serious bug when it happens by accident in custom middleware.

What a correctly ordered Program.cs looks like

Candidates who can write the shape of this from memory tend to also understand it, rather than having copied it once and never revisited it:

var app = builder.Build();

app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseCors();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Notice that MapControllers(), or MapGet for minimal APIs, comes after UseRouting() and after authentication and authorization.

Endpoint mapping registers where requests can go. It has to sit downstream of the middleware deciding whether a request is even allowed to reach an endpoint.

Minimal APIs versus controllers

A newer interview angle: do minimal APIs change any of this? They do not.

Minimal APIs run through the same pipeline, and still need UseRouting() and UseAuthorization() in the same relative order. The difference is in how endpoints are declared, not in how requests are processed.

Health checks as a practical example

app.MapHealthChecks("/health") makes a good talking point. It needs to sit after UseRouting(), like any endpoint.

It is usually placed before authentication and authorization, because a load balancer checking whether the app is alive should not need to authenticate first. Get this wrong and your health check returns 401 instead of 200.

The hosting model: Kestrel, IIS, and what "in-process" actually means

The second area candidates fumble is the hosting model. Ask what Kestrel is and you usually get "the web server ASP.NET Core uses." True, but incomplete.

What Kestrel is and is not

Kestrel is the cross-platform web server built into ASP.NET Core. Every ASP.NET Core app uses Kestrel internally, even one deployed behind IIS.

WebApplication.CreateBuilder calls UseKestrel for you as part of the default setup. Kestrel alone can serve internet traffic directly, but most production deployments still put a reverse proxy in front of it.

In-process vs out-of-process

When you deploy to IIS, you choose a hosting model, and this is where confident wrong answers show up most.

Out-of-process hosting: IIS runs the ASP.NET Core Module, which starts your app as a separate process running Kestrel. IIS forwards requests to Kestrel and passes the response back.

In-process hosting: the app runs inside the same IIS worker process (w3wp.exe). Instead of Kestrel, it uses IISHttpServer to talk directly to IIS's native request pipeline.

In-process is the default in modern project templates, and generally faster because it avoids proxying every request between two processes.

Out-of-process still matters when the same app must also run unchanged on Linux or in a container, without IIS anywhere in the picture.

The trap answer

A common wrong answer: "in-process hosting means the app doesn't use Kestrel at all, ever." That is only true for that specific IIS deployment.

The same codebase, run with dotnet run or in a Docker container, still uses Kestrel directly. There is no IIS worker process to host it in-process in either of those environments.

Hosting model is a deployment-time choice, not a property baked into the code itself.

Another trap: assuming in-process is always correct. If you need identical behavior across IIS, Linux containers, and local development, letting Kestrel do the real work everywhere is sometimes the simpler choice.

Configuration precedence: the layer that silently overrides your settings

The third area, and possibly the most common source of "it works on my machine" bugs, is configuration precedence.

Ask a candidate "if the same key exists in appsettings.json and as an environment variable, which one wins?" and watch how confidently they answer either direction.

The default provider order

ASP.NET Core builds configuration from multiple sources, added in a specific order. Later sources override earlier ones when a key collides.

The default order, source by source:

  1. appsettings.json
  2. appsettings.{Environment}.json (for example appsettings.Development.json)
  3. User secrets (Development environment only)
  4. Environment variables
  5. Command-line arguments

Environment variables override anything set in the JSON files. Command-line arguments override everything else, including environment variables.

This is deliberate. It lets you deploy the same build to different environments and override settings without touching a file, and lets an operator override a setting for a single run without redeploying.

The trap answer

The common wrong answer is "appsettings.Development.json always wins in development, no matter what." It wins over the base appsettings.json, but still loses to an environment variable with the same key.

A candidate who insists JSON files always take priority has never had to debug a setting that looked correct in the file but was silently overridden by a variable set in the deployment pipeline.

Why this matters more than it sounds

A connection string that differs between what a developer sees locally and what a colleague sees, despite identical files in source control, is almost always a precedence bug.

The fix is not to guess. It is to know the order and check each layer until you find where the value is actually coming from.

This is also where IOptions<T> binding gets asked about. Configuration values are typically bound to a strongly typed class rather than read as raw strings scattered through the codebase.

Knowing why - centralized validation, and one less place for a typo to hide - is a reasonable follow-up answer.

IOptions, IOptionsSnapshot, and IOptionsMonitor

A sharper follow-up: what is the difference between these three, and when does it matter?

IOptions<T> reads configuration once, at startup, and never changes for the app's lifetime. IOptionsSnapshot<T> is scoped, so it re-reads configuration on every request.

IOptionsMonitor<T> is a singleton that can notify subscribers when configuration changes, which suits a background service reacting to a setting change without a restart.

Picking the wrong one is rarely a crash. It is a bug where a value change on disk is not picked up until the next deployment, and nobody notices for a while.

Layered diagram showing configuration sources stacking with the top layer overriding values below it

Dependency injection: lifetimes are where the real questions live

Once pipeline basics are covered, most interviews move to dependency injection. Nearly every candidate can name the three lifetimes.

Fewer can explain what goes wrong when you mix them incorrectly.

Lifetime Instance created Common mistake
Transient New instance every time it is requested Using it for something expensive to construct
Scoped One instance per HTTP request Injecting it into a singleton, which captures the first request's instance forever
Singleton One instance for the app's lifetime Storing per-request state on it, which leaks across users

The interview question worth preparing for: what happens if you inject a scoped service into a singleton?

.NET's built-in container throws an exception if you resolve a scoped service from the root container directly, or it captures a stale scoped instance if you resolve it once and reuse it.

Either way, the fix is the same: never let a longer-lived service hold a reference to a shorter-lived one.

If it needs one, inject IServiceScopeFactory and create a scope only when the dependency is actually needed.

This check is not just theoretical. Scope validation is enabled by default in the Development environment, so this class of mistake throws at startup instead of reaching production quietly.

That single default has saved a lot of developers from a bug that would otherwise only show up under concurrent load, well after the code shipped.

EF Core questions that come up alongside ASP.NET Core

Most backend roles pair ASP.NET Core with Entity Framework Core, and a chunk of interview time typically covers both.

For a deeper pass on relational database questions specifically, the SQL Server interview questions guide covers indexing, query plans, and transactions in more depth than fits here.

A few EF Core questions specific to the web layer:

  • What is the "N+1 query" problem, and how do you avoid it? Loading a list of entities, then lazily loading a related entity for each one in a loop, turns one query into N+1 round trips. Include() for eager loading fixes the common case.
  • Why register DbContext as scoped, not singleton? A DbContext tracks changes for a single unit of work. Sharing one instance across requests causes tracked-entity conflicts, because DbContext is not thread-safe.
  • What does AsNoTracking() do? It skips change tracking for a query, which is faster for read-only data you will not update in the same request.
  • What is a migration, and why does the team argue about them? A migration is a versioned, incremental change to the database schema, generated from your model changes. Teams argue about them because a migration applied against production data can fail in ways it never did against a small local database, especially when a column becomes non-nullable.

A good follow-up question here is what you would do differently for a schema change on a table with millions of rows compared to an empty development database.

The honest answer usually involves a nullable intermediate step, a backfill job, and a separate migration to enforce the constraint once the existing data is clean.

Action filters and where they fit in the pipeline

A question that catches out candidates who only think in terms of middleware: where do MVC action filters sit relative to the pipeline described above?

Filters run inside the MVC framework, after routing has already selected a controller action, not as separate middleware registered in Program.cs.

An authorization filter on a controller action, for example, runs after the UseAuthorization middleware has already let the request through the pipeline stage.

This distinction explains a real bug pattern. A developer adds an [Authorize] attribute expecting it to behave exactly like the pipeline middleware.

They are then confused when a custom filter checking the same thing runs at a different point in the request's journey.

Middleware guards the whole app. Filters guard a specific controller or action, and always run later, once the framework has already routed the request somewhere.

Testing and the parts candidates skip preparing for

Testing questions usually split into two: unit testing business logic, and integration testing the actual HTTP pipeline.

WebApplicationFactory<T> is the standard tool for integration tests that spin up your app in memory and send real HTTP requests through the full pipeline, including the routing and authorization you just explained.

It is worth mentioning by name if the interviewer asks how you would test that middleware order actually behaves the way you claim.

For unit tests, mocking HttpContext directly is painful, because it has many interdependent parts. Most developers instead test the logic inside a handler in isolation, injecting fakes for its dependencies.

WebApplicationFactory is reserved for the parts that genuinely need the whole pipeline running.

How this fits into the wider interview

None of this happens in isolation. A typical ASP.NET Core interview mixes these framework questions with general C# questions and a system design or process discussion.

The C# interview questions for experienced developers guide is the natural next stop for the language-level side of that mix.

It also helps to understand how the interview itself is structured before you walk in.

Companies vary a lot in how many rounds they run and what each round tests for.

The technical interview process design guide breaks down what a well-run loop looks like from the interviewer's side.

Illustration of a developer at a whiteboard tracing a request through layered boxes labeled with middleware names

A short list of follow-up questions worth practicing

These second-order questions come after the standard opener, and this is where preparation actually pays off:

  • If two middleware components both try to write to the response, what happens?
  • Why does UseExceptionHandler need to be registered before other middleware, not after?
  • What is the difference between IConfiguration and IOptionsSnapshot<T>, and when would reloading matter?
  • Can a singleton service safely read IHttpContextAccessor? What is the risk?
  • What does app.MapControllers() actually register, and why does it need to run after UseRouting?

Rehearsing the memorized version of any of these will not help. Understanding what problem each piece solves will carry you through whichever specific phrasing an interviewer chooses.

What this means for how you prepare

Salary expectations for ASP.NET Core roles vary widely by city, company size, and whether the role is product or services based.

Treat any number you hear as indicative only, and confirm current ranges directly with recruiters rather than relying on a fixed figure.

The pattern across all three core topics in this guide is the same: default project templates hide the reasoning behind sensible choices.

Interviews exist to check whether you understand the reasoning, not whether you can recite the defaults. Spend your prep time explaining "why" out loud, not just "what."

If you already have a working project or two, a verified profile on CareerCTO puts your work in front of employers reviewing candidates on more than a resume claim.

If you are the one hiring, CareerCTO's reviewed job board and browsing verified developer profiles work the same way.

Less time filtering noise, more time talking to people who can explain their code.

Close-up illustration of two overlapping gears representing authentication and authorization working together

Next step

Pick one of the three core topics above - middleware order, hosting model, or configuration precedence.

Explain it out loud to someone else without looking at your notes. If you stumble on the "why," that is the gap to close before your next interview, not the list of method names.

Keep reading