Top ASP.NET Core Interview Questions & Answers

ASP.NET Core interviews cover the middleware pipeline, built-in dependency injection, and configuration patterns that define modern .NET web development.

Take Practice Interview Now
Improve your chances of getting selected — rehearse these answers out loud with an AI interviewer and get a scored report in minutes.
Start Free →

1. What is the ASP.NET Core middleware pipeline and how does it actually work?

The middleware pipeline is a chain of request delegates you wire up in `Program.cs`, and every incoming `HttpContext` flows through them in the order they're registered. Each middleware component can inspect or modify the request, decide to call `next()` to pass control down the chain, or short-circuit and return a response immediately. Because each one wraps the next like layers of an onion, code can run both on the way in and on the way back out, which is why things like response compression or logging often do work after calling `next()`. Order is critical — for example, exception handling middleware should be registered first so it can catch errors from everything downstream, and `UseRouting` has to come before `UseAuthentication`/`UseAuthorization`, which in turn need to come before endpoint execution. Under the hood it's built on `IApplicationBuilder.Use`, `Run`, and `Map` extension methods.

2. What are the three DI service lifetimes in ASP.NET Core, and when would you use each?

ASP.NET Core's built-in container supports transient, scoped, and singleton lifetimes, registered through `IServiceCollection` as `AddTransient`, `AddScoped`, or `AddSingleton`. Transient services get a brand-new instance every time they're resolved, so they're best for lightweight, stateless services with no shared state. Scoped services get one instance per request — or more precisely, per `IServiceScope` — which makes them the right choice for something like `DbContext`, since you want the same context and change tracker throughout a single request. Singleton services are created once and live for the entire application lifetime, so they're used for things like configuration objects or thread-safe caches. A common gotcha is the 'captive dependency' problem — injecting a scoped or transient service into a singleton effectively pins it to the singleton's lifetime, so if you need a scoped service inside a singleton you should resolve it through `IServiceScopeFactory` instead.

3. What's the difference between Minimal APIs and MVC controllers?

Minimal APIs, introduced in .NET 6, let you define endpoints directly against the `WebApplication` instance using calls like `app.MapGet` or `app.MapPost`, without a controller class, action attributes, or the usual MVC conventions. They're built directly on top of endpoint routing and are great for small services, microservices, or APIs where you don't need the full ceremony. MVC controllers, by contrast, give you a structured, class-based model with `ControllerBase`, attribute or convention-based routing, built-in support for filters, and automatic model validation via `[ApiController]`. MVC tends to scale better for larger codebases because it enforces more structure and testability patterns. Minimal APIs have been closing the gap — they now support DI, route groups, and endpoint filters — but things like automatic `ModelState` validation historically required more manual wiring than in MVC.

4. What is `DbContext` in EF Core, and how do migrations work?

`DbContext` represents a session with the database — it exposes `DbSet<T>` properties that map to tables, tracks changes to entities you load or add, and coordinates writing those changes back with `SaveChanges` in a unit-of-work style. It's typically registered with a scoped lifetime so each web request gets its own context and change tracker. Migrations are EF Core's way of evolving your database schema alongside your code-first model: running `dotnet ef migrations add <Name>` compares your current model against a snapshot and generates a migration class with `Up` and `Down` methods describing the schema changes. `dotnet ef database update` then applies any pending migrations to the actual database, and `Down` lets you roll a migration back if needed. This keeps schema changes versioned and reproducible across environments instead of manually editing the database.

5. What are the key differences between ASP.NET Core and the older ASP.NET Framework?

ASP.NET Core is cross-platform, running on Windows, Linux, and macOS, whereas ASP.NET Framework is tied to Windows and IIS. ASP.NET Core runs on the modern, open-source .NET runtime instead of the full .NET Framework, and it's built from modular NuGet packages rather than one monolithic `System.Web` assembly, so you only bring in what you actually use. It ships with a built-in, lightweight web server called Kestrel and a first-class dependency injection container, where Framework apps typically relied on IIS directly and third-party DI libraries. MVC and Web API, which were separate frameworks in the old world, are unified into a single framework in ASP.NET Core. Configuration also moved away from XML-based `web.config` toward JSON-based `appsettings.json` with a flexible, layered configuration provider model.

6. How does configuration work in ASP.NET Core with `appsettings.json`?

Configuration in ASP.NET Core is built on a provider model where multiple sources are layered on top of each other, and later-added providers override matching keys from earlier ones. By default `WebApplicationBuilder` wires up `appsettings.json`, then an environment-specific file, then environment variables, then command-line arguments, roughly in that order of increasing precedence. You can inject `IConfiguration` directly to read raw values, but the more idiomatic approach for typed settings is the options pattern — calling `services.Configure<MySettings>(configuration.GetSection("MySettings"))` and injecting `IOptions<MySettings>` wherever you need it. This layering also makes it easy to bring in secure sources like user secrets in development or Azure Key Vault in production without changing application code.

7. How does the environment-specific `appsettings` override pattern actually work?

`appsettings.json` is the base configuration file loaded for every environment, and `appsettings.{Environment}.json` — like `appsettings.Development.json` or `appsettings.Production.json` — is loaded afterward and layered on top of it. Because it's loaded second, any key present in both files gets its value from the environment-specific file, while keys that only exist in the base file are still inherited untouched. Which file gets picked up is driven by the `ASPNETCORE_ENVIRONMENT` environment variable, and `WebApplicationBuilder.CreateBuilder` wires this override behavior up automatically, so you don't have to configure it yourself. This pattern is what lets you point to a local database connection string and verbose logging in development while using a different connection string and warning-level logging in production, all without touching code. Sensitive values like production secrets are usually kept out of the checked-in file entirely and supplied through environment variables or a vault instead.

8. What is model binding, and how does model validation work?

Model binding is the process by which ASP.NET Core takes raw data from the incoming request — route values, query string parameters, form fields, headers, or a JSON body via `[FromBody]` — and maps it onto the parameters or complex types your action method expects, matching by property name. Validation typically happens through Data Annotation attributes like `[Required]`, `[StringLength]`, or `[Range]` placed on your model's properties, and the framework runs these checks as part of binding, populating `ModelState` with any errors. With `[ApiController]` applied to a controller, invalid `ModelState` automatically short-circuits into a `400 Bad Request` response before your action code even runs, so you don't need an explicit `if (!ModelState.IsValid)` check. In Minimal APIs this kind of automatic validation historically wasn't built in the same way, so people either check manually, use endpoint filters, or bring in something like FluentValidation. Custom validation logic can also be added by implementing `IValidatableObject` on the model itself.

9. What are action filters, and what are the different filter types in ASP.NET Core MVC?

Filters are pieces of code that run at specific points around action execution, letting you handle cross-cutting concerns like logging, caching, or exception handling without repeating that logic in every controller. They execute in a defined order: authorization filters run first to decide whether the user is allowed to proceed, then resource filters, then action filters wrap the actual action method execution with `OnActionExecuting` and `OnActionExecuted`, then exception filters catch unhandled errors, and finally result filters wrap the execution of the action's result. You implement them via interfaces like `IActionFilter` or `IAsyncActionFilter`, or more commonly by inheriting from `ActionFilterAttribute` and overriding the relevant methods. Filters can be applied at the action level, the controller level, or registered globally in `MvcOptions` so they apply everywhere. This gives you a clean way to inject behavior into the pipeline without cluttering the actual business logic in your actions.

10. When would you choose Razor Pages, MVC, or Web API for a project?

Razor Pages organizes an app around individual pages — each page is a `.cshtml` file paired with a `PageModel` code-behind class that has `OnGet`/`OnPost` handlers, which keeps page-focused logic co-located and is great for simpler, form-driven or CRUD-heavy server-rendered apps. MVC splits things into Model, View, and Controller with a controller typically handling multiple related actions and routes, which suits larger applications where you're sharing logic and layouts across many views. Web API is meant for building stateless HTTP endpoints that return data, usually JSON, using `ControllerBase` and the `[ApiController]` attribute, with no view rendering involved at all. Since ASP.NET Core unified MVC and Web API into one framework, the real distinction now is just `Controller` versus `ControllerBase` and whether you're returning views or data. In practice, pick Razor Pages for straightforward server-rendered CRUD screens, MVC when you have complex, view-heavy UI, and Web API when you're serving a SPA, mobile app, or other backend consumers.

11. What is Kestrel, and how does it fit into ASP.NET Core hosting?

Kestrel is the cross-platform web server built into ASP.NET Core — it's lightweight, fast, and handles raw HTTP requests, and every ASP.NET Core app uses it internally regardless of what's in front of it. In production it's common to run Kestrel behind a reverse proxy like IIS, Nginx, or Apache, which handles things Kestrel doesn't focus on, such as advanced request filtering, process management, and serving as a hardened public-facing edge. That said, Kestrel is capable enough to be exposed directly to the internet in many scenarios, especially with modern versions supporting HTTP/1.1, HTTP/2, and HTTP/3. You can tune it through the `Kestrel` section in `appsettings.json` or in code, configuring things like endpoint bindings, request size limits, and TLS certificates. The reverse-proxy pattern is still recommended in many production setups mainly for the extra layer of operational and security tooling it provides.

12. How does JWT bearer authentication work in ASP.NET Core?

JWT bearer authentication is configured with `AddAuthentication().AddJwtBearer()`, and it works by validating a signed token that the client sends in the `Authorization: Bearer <token>` header on each request. The middleware checks the token's signature against the configured signing key and validates claims like issuer, audience, and expiration according to `TokenValidationParameters`. If the token is valid, its claims are used to build a `ClaimsPrincipal` on `HttpContext.User`, which `[Authorize]` attributes and policies then use to make access decisions. It's inherently stateless — there's no server-side session to maintain — which makes it a natural fit for SPAs, mobile clients, and service-to-service calls between APIs. One important detail people often miss is that `UseAuthentication` has to be registered before `UseAuthorization` in the pipeline, otherwise the user's identity won't be populated when authorization runs.

13. How does cookie authentication work, and how is it different from JWT?

Cookie authentication, configured with `AddAuthentication().AddCookie()`, issues an encrypted authentication cookie when you call `SignInAsync`, and the browser then automatically attaches that cookie to subsequent requests, letting the server reconstruct the `ClaimsPrincipal` on each call. This makes it a natural fit for traditional server-rendered web apps where the browser is doing the heavy lifting of cookie management for you. JWTs, by contrast, are self-contained tokens the client is responsible for storing and attaching manually, which makes them better suited to SPAs, mobile apps, and cross-origin API calls where you can't rely on same-site cookie behavior. Cookie auth is also more exposed to CSRF, so you typically pair it with antiforgery tokens, whereas that's less of a concern with bearer tokens since they aren't sent automatically by the browser. Revocation is also easier with cookies, since the server can invalidate a session, while revoking an already-issued JWT before it expires generally requires extra infrastructure like a token blacklist.

14. What's the difference between the authentication and authorization middleware, and how do authorization policies work?

`UseAuthentication` is responsible for establishing who the caller is — it runs the configured schemes, such as cookies or JWT bearer, to validate credentials and populate `HttpContext.User` with a `ClaimsPrincipal`. `UseAuthorization` runs after that and decides whether the now-identified (or anonymous) user is actually allowed to access the requested resource, which is why it must be registered after `UseAuthentication` and after `UseRouting`, but before the endpoints execute. Simple checks like `[Authorize(Roles = "Admin")]` cover basic role-based scenarios, but policies give you more expressive control — you register them with `services.AddAuthorization(options => options.AddPolicy("MinimumAge", policy => ...))` and can back them with custom `IAuthorizationHandler` logic that evaluates claims, resource ownership, or any other business rule. You then apply a policy with `[Authorize(Policy = "MinimumAge")]` instead of hardcoding role checks throughout the app. This separation keeps 'who are you' and 'what can you do' as two distinct, composable concerns in the pipeline.

15. What is the purpose of the wwwroot folder and static file middleware?

`wwwroot` is the conventional web root folder in an ASP.NET Core project where publicly servable static assets live — CSS, JavaScript, images, and client-side libraries — and it's kept separate from the application's source code and server-side views for security, so files outside it aren't accidentally exposed over HTTP. `UseStaticFiles()`, registered early in the middleware pipeline, is what actually serves files from `wwwroot` directly to the browser without hitting a controller or Razor Page, matching a request path like `/images/logo.png` to the corresponding file on disk. You can serve additional directories beyond the default by configuring a second `UseStaticFiles()` call with a custom `PhysicalFileProvider` and request path prefix. Static file middleware also sets appropriate caching headers and content types automatically based on file extension, and it short-circuits the pipeline once it successfully serves a match, so requests for real static assets never reach your MVC or Razor Pages routing at all.

Take Practice Interview Now
Improve your chances of getting selected — rehearse these answers out loud with an AI interviewer and get a scored report in minutes.
Start Free →
Related topics
Node.jsSpring BootExpress.jsDjango