.NET Core Interview Prep

.NET Core / ASP.NET Core Interview Questions and Answers (2026)

.NET Core and ASP.NET Core interview questions usually test whether you understand what's actually happening under the minimal hosting model — the middleware pipeline, dependency injection lifetimes, and how configuration and environments fit together — not just whether you can recite API names. Here are the ones that come up most often.

  1. What is the ASP.NET Core hosting model, and what's the role of `Program.cs`/`WebApplicationBuilder`?

    ASP.NET Core apps are self-hosted console applications built around the generic host, which wires up dependency injection, configuration, logging, and the web server into a single unified startup pipeline. WebApplicationBuilder.CreateBuilder(args) sets up defaults (configuration sources, logging providers, Kestrel), you register services on builder.Services, then builder.Build() produces a WebApplication on which you configure the middleware pipeline and map endpoints before calling app.Run(). This minimal hosting model (introduced in .NET 6) replaced the older split Startup.cs/Program.cs pattern with a single top-level file, though the underlying host/DI/middleware concepts are unchanged. Since it's just a console app under the hood, it can be hosted behind IIS, Nginx, as a Windows Service, in a container, or run standalone.

  2. How does the middleware pipeline work, and why does ordering matter?

    Middleware components are chained in the order they're registered via app.Use...() calls, forming a pipeline each request passes through and a response passes back through in reverse. Each middleware can act before calling next() (short-circuiting the request if needed, e.g., authentication rejecting it early) and after (post-processing the response, e.g., logging status codes). Ordering is critical: UseExceptionHandler/UseHsts should be first to catch downstream errors; UseRouting must come before UseAuthorization/endpoint-specific middleware since routing determines which endpoint's metadata authorization checks against; UseAuthentication must precede UseAuthorization; static files are typically served early to bypass unnecessary processing. Misordering causes subtle bugs like authorization running against the wrong endpoint or CORS headers missing on error responses.

  3. What are the DI lifetimes (singleton, scoped, transient) and when do you pick each?

    Transient services are created every time they're requested — best for lightweight, stateless services. Scoped services are created once per client request (per HTTP request in a web app) and reused within that scope — the standard choice for things like DbContext, which shouldn't be shared across concurrent requests but should be consistent within one. Singleton services are created once for the app's lifetime and shared by all requests — appropriate for stateless, thread-safe services like configuration wrappers or caches. The classic bug is "captive dependency": injecting a scoped service into a singleton, which pins the scoped instance for the app's whole life since the singleton is constructed once — the DI container will throw at runtime in Development to catch this, or you resolve scoped services lazily via IServiceScopeFactory.

  4. What's the difference between Minimal APIs and Controllers?

    Minimal APIs (introduced in .NET 6) let you define HTTP endpoints directly with lambda expressions mapped via app.MapGet/MapPost/..., without controller classes, action method conventions, or (by default) the [ApiController] attribute's automatic model-validation behavior. They're lighter-weight, faster to start, and reduce ceremony for small APIs or microservices. Controllers (ControllerBase, attribute routing) give you a more structured, convention-based approach with built-in support for filters, model binding/validation via [ApiController], versioning libraries, and better organization for large APIs with many related actions. Minimal APIs can achieve most of the same behavior (filters, validation via endpoint filters or FluentValidation) but require more explicit wiring; Controllers remain preferable for large, complex APIs where convention and structure pay off.

  5. How does the configuration system work, and how do appsettings files layer?

    IConfiguration builds a single merged key/value store from multiple providers added in order, where later sources override earlier ones: appsettings.jsonappsettings.{Environment}.json → user secrets (Development only) → environment variables → command-line args. This lets you keep shared defaults in the base file, override per-environment values in appsettings.Production.json, and inject secrets via environment variables or a secrets manager in production without ever committing them. Strongly-typed access is preferred over magic strings via the Options pattern: builder.Services.Configure<MySettings>(builder.Configuration.GetSection("MySettings")), then inject IOptions<MySettings> (or IOptionsSnapshot/IOptionsMonitor for scoped/live-reloading access) rather than calling IConfiguration["MySettings:Key"] everywhere.

  6. What's the difference between Razor Pages and MVC?

    Razor Pages organizes code around individual pages: each page is a .cshtml file paired with a PageModel code-behind class (OnGet/OnPost handlers) that's self-contained, which suits page-focused, CRUD-heavy apps with less need for shared logic across many views. MVC separates Models, Views, and Controllers, where one controller handles multiple related actions/routes and views are organized in a shared folder structure — better suited to APIs or apps with more complex, cross-cutting navigation and reusable action logic. Both sit on top of the same Razor view engine and can coexist in the same project. Razor Pages is generally recommended by Microsoft as the default for new server-rendered page-based apps, while MVC remains common for APIs and larger enterprise apps with established conventions.

  7. What is Kestrel, and why do production deployments often put a reverse proxy in front of it?

    Kestrel is the cross-platform, high-performance web server built into ASP.NET Core, used to actually listen for and process HTTP requests. It's fast and lightweight but historically lacked some hardening and features expected of internet-facing servers — request filtering, advanced load balancing, TLS certificate management via OS tooling, and process management. Production setups commonly place Kestrel behind a reverse proxy like IIS, Nginx, Apache, or a cloud load balancer (e.g., Azure App Service's frontend), which handles TLS termination, request buffering, and forwards requests to Kestrel. This is configured via UseForwardedHeaders so Kestrel correctly sees the original client IP/scheme instead of the proxy's. Kestrel can also be used directly as an edge server when properly configured, which is increasingly common in containerized/cloud-native deployments.

  8. How do you handle environment-based configuration differences (Development, Staging, Production)?

    The ASPNETCORE_ENVIRONMENT environment variable (or DOTNET_ENVIRONMENT) drives IWebHostEnvironment.EnvironmentName, which controls which appsettings.{Environment}.json file loads and lets you branch middleware setup, e.g. if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } versus a generic error handler and HSTS in production. You should never hardcode secrets or environment-specific URLs in code; instead vary them per environment via configuration layering, and rely on environment checks (env.IsDevelopment(), env.IsStaging(), env.IsProduction(), or custom names) rather than #if DEBUG compiler directives, since the latter is baked in at compile time and can't differ between deployed instances of the same build.

  9. What are health checks and why do you add them?

    Health checks (Microsoft.Extensions.Diagnostics.HealthChecks) expose an endpoint (conventionally /health) that reports whether the app and its dependencies (database, cache, downstream APIs) are functioning, used by orchestrators (Kubernetes liveness/readiness probes, Azure App Service, load balancers) to decide whether to route traffic to an instance or restart it. You register them via builder.Services.AddHealthChecks().AddDbContextCheck<MyContext>().AddCheck<CustomCheck>(), then app.MapHealthChecks("/health"). You typically distinguish liveness checks (is the process alive) from readiness checks (can it actually serve traffic, e.g. DB is reachable) using tags, since a slow dependency shouldn't necessarily trigger a container restart but should stop new traffic from routing there.

  10. What is `IHostedService`/`BackgroundService`, and when do you use it?

    IHostedService lets you run long-running background work within the same process as your web app, managed by the host's lifecycle (started on app startup, stopped gracefully on shutdown). BackgroundService is an abstract base class implementing IHostedService that simplifies this to overriding a single ExecuteAsync(CancellationToken) method, commonly used for polling queues, scheduled cleanup tasks, or consuming messages from a bus. Because it shares the host's DI container, it must resolve scoped services (like DbContext) via IServiceScopeFactory.CreateScope() rather than injecting them directly into the singleton-lifetime hosted service. For work that must survive app restarts or scale independently, a separate worker service or external job scheduler is more appropriate than an in-process hosted service.

    public class QueueProcessor : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                await ProcessNextItemAsync();
                await Task.Delay(1000, token);
            }
        }
    }
  11. How does CORS work in ASP.NET Core, and what are common mistakes?

    CORS (Cross-Origin Resource Sharing) is a browser-enforced mechanism that lets a server explicitly allow requests from origins other than its own via response headers; it's configured with builder.Services.AddCors(options => options.AddPolicy("MyPolicy", p => p.WithOrigins("https://app.example.com").AllowAnyHeader().AllowAnyMethod())) and activated with app.UseCors("MyPolicy") positioned after UseRouting and before endpoint mapping/UseAuthorization. Common mistakes: using AllowAnyOrigin() together with AllowCredentials() (disallowed by the spec and will throw), forgetting that CORS doesn't protect server-to-server calls (only enforced by browsers), and misunderstanding that a CORS failure is a browser-side block after the server already processed the request — the server response happened, the browser just refuses to expose it to the calling script.

  12. How does model binding and validation work in ASP.NET Core?

    Model binding automatically maps incoming request data (route values, query string, form fields, JSON body, headers) to action method parameters or a bound model object, based on parameter attributes ([FromBody], [FromQuery], [FromRoute]) or convention (complex types default to body in APIs). Validation runs via data annotations ([Required], [StringLength], [Range]) or custom IValidatableObject logic, populating ModelState; with [ApiController] on a controller, an invalid ModelState automatically returns a 400 with a problem-details response before your action code even runs. In Minimal APIs this automatic validation doesn't happen by default — you either check manually, use endpoint filters, or bring in a library like FluentValidation or the newer built-in validation support to replicate that behavior.

Practicing for a real interview? Get live AI help with your answers, in the browser, free to start.

Start a free session