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

CareerCTO · 2026-08-05 · 14 min read · Interviews

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](/blog/dotnet-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:

```csharp
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](/blog/asp-net-core-interview-questions-1.webp)

## 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](/blog/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](/blog/c-sharp-interview-questions-for-experienced)
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](/blog/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](/blog/asp-net-core-interview-questions-2.webp)

## 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](/build-a-profile) 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](/jobs) and
[browsing verified developer profiles](/graduates) 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](/blog/asp-net-core-interview-questions-3.webp)

## 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.

---

Source: https://careercto.dev/blog/asp-net-core-interview-questions
