.NET Core Interview Questions and Answers (2026, .NET 10)

Job posts in Seattle, Austin and New York still say “.NET Core developer,” but the .NET Core interview questions you’ll hear in 2026 are about .NET 10, ASP.NET Core, dependency injection, middleware and EF Core. The “Core” name was dropped after 3.1.

In this tutorial, I’ll answer 40 .NET Core interview questions with short answers first, then the detail an interviewer wants to hear. Each group is labeled Junior, Mid or Senior.

For the trickiest ones, like DI lifetimes and middleware order, I ran a small .NET 10 program so you can see the proof, not just my word for it.

Table of Contents

.NET Platform Interview Questions (Junior)

Q1. What is .NET Core, and what is it called now? (Junior)

Short answer: .NET Core was the cross-platform, open-source rewrite of .NET. Starting with .NET 5, Microsoft dropped “Core” from the name, so today it’s just .NET, and the current long-term release is .NET 10.

ASP.NET Core and EF Core kept “Core,” so job posts still use it. C# is the main language on top of it; if you need a refresher, my article on what C# is and how it runs on .NET covers the basics.

Q2. What’s the difference between .NET and .NET Framework? (Junior)

Short answer: .NET Framework 4.8.x is Windows-only and only gets fixes. Modern .NET runs on Windows, Linux and macOS, ships a new version every November and is where every new feature lands.

.NET Framework 4.8.x.NET 10
PlatformsWindows onlyWindows, Linux, macOS
Web stackASP.NET (System.Web), Web Forms, MVC 5ASP.NET Core (Kestrel, minimal APIs, Blazor)
Side-by-side installsNo, one per machineYes, and self-contained apps
New featuresNone, servicing onlyEvery yearly release
ContainersWindows containers onlySmall Linux images, Native AOT

.NET Standard 2.0 only matters now for a library that must serve both a .NET Framework 4.8 app and a .NET 10 app. There won’t be a new .NET Standard version.

If a team asks why they should migrate, I’d say performance, Linux hosting costs and support for new C# versions. Web Forms and WCF server don’t exist in .NET 10, so those parts need a rewrite.

Q3. What do LTS and STS mean, and which .NET version should you use in 2026? (Junior)

Short answer: LTS (long-term support) releases get three years of free patches, STS (standard-term support) releases get two. In 2026, new projects should target .NET 10, the current LTS.

VersionTypeReleasedEnd of support
.NET 10LTSNovember 11, 2025November 14, 2028
.NET 9STSNovember 12, 2024November 10, 2026
.NET 8LTSNovember 14, 2023November 10, 2026

Here’s a detail that impresses interviewers: .NET 8 and .NET 9 both reach end of support on November 10, 2026. Even-numbered releases are LTS, and the last six months of any release are security-fixes only.

Q4. Which .NET CLI commands should you know? (Junior)

Short answer: dotnet new, dotnet build, dotnet run, dotnet test, dotnet publish and dotnet add package. In .NET 10 you can also run a single file with dotnet run app.cs.

I used that single-file feature for the demos here. A #:package line at the top pulls a NuGet package, and #:sdk Microsoft.NET.Sdk.Web turns the file into a web app. For a full project setup, see how to create a console application in Visual Studio Code.

Runtime Interview Questions: CLR, JIT, GC and Native AOT (Junior to Mid)

Q5. What does the CLR do? (Junior)

Short answer: The Common Language Runtime loads your compiled IL, JIT-compiles it to machine code, manages memory with the garbage collector, and enforces type safety and exception handling.

Questions about value and reference types usually follow. Be ready to explain boxing and unboxing in C#, because it’s where the CLR’s two memory models meet.

Q6. What’s the difference between JIT, ReadyToRun and Native AOT? (Mid)

Short answer: JIT compiles IL to machine code at run time. ReadyToRun precompiles most code but keeps the JIT. Native AOT compiles everything ahead of time into one native executable with no JIT at all.

Native AOT gives faster startup and lower memory, which is great for containers and serverless. The trade-off is no runtime reflection or dynamic code, so minimal APIs work (partially), but MVC controllers, Razor Pages, session state and Blazor Server don’t.

Q7. How does the garbage collector work, and where does IDisposable fit? (Mid)

Short answer: The GC frees managed memory in generations (0, 1 and 2, plus the large object heap). It doesn’t close files, sockets or database connections on time, so those types implement IDisposable and you wrap them in using.

Interviewers love the follow-up about finalizers. My guide to Dispose and Finalize in C# shows the full pattern and why you rarely write a finalizer yourself.

Q8. What’s the difference between framework-dependent and self-contained deployment? (Mid)

Short answer: A framework-dependent app needs the .NET runtime installed on the server and is small. A self-contained app ships its own runtime, so it’s bigger but runs on a machine with nothing installed.

You pick it at publish time, for example dotnet publish -c Release -r linux-x64 --self-contained. Native AOT is a third option that’s always self-contained.

Dependency Injection Interview Questions (Mid)

Q9. What is dependency injection in ASP.NET Core? (Junior)

Short answer: A class asks for what it needs through its constructor, and the built-in container (IServiceProvider) creates and passes those objects in. You register services on builder.Services in Program.cs.

It works best when a class depends on an abstraction, so you can swap the real thing for a fake in tests. That’s why every DI answer leads back to interfaces in C#.

Constructor injection is the default, and C# 12 primary constructors make it shorter. If constructors are fuzzy, review constructors in C# before the interview.

Q10. What’s the difference between AddSingleton, AddScoped and AddTransient? (Mid)

Short answer: Singleton: one instance for the whole app. Scoped: one instance per scope, which in ASP.NET Core means per HTTP request. Transient: a new instance every time it’s requested.

This is the most-asked ASP.NET Core question, so I proved it. The program below resolves each service twice inside two scopes, which is exactly what two HTTP requests look like to the container:

#:package Microsoft.Extensions.DependencyInjection@10.0.13
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddSingleton<PricingRules>();
services.AddScoped<ShoppingCart>();
services.AddTransient<TaxCalculator>();
using var root = services.BuildServiceProvider();

for (int request = 1; request <= 2; request++)
{
    using var scope = root.CreateScope();   // = one HTTP request
    Console.WriteLine($"Request {request}");
    Show<PricingRules>(scope.ServiceProvider);
    Show<ShoppingCart>(scope.ServiceProvider);
    Show<TaxCalculator>(scope.ServiceProvider);
}

static void Show<T>(IServiceProvider sp) where T : IHasId =>
    Console.WriteLine($"  {typeof(T).Name,-14} #{sp.GetRequiredService<T>().Id}  #{sp.GetRequiredService<T>().Id}");

interface IHasId { int Id { get; } }
class Counted<T> : IHasId { static int count; public int Id { get; } = ++count; }
class PricingRules : Counted<PricingRules>;
class ShoppingCart : Counted<ShoppingCart>;
class TaxCalculator : Counted<TaxCalculator>;

Output:

Request 1
  PricingRules   #1  #1
  ShoppingCart   #1  #1
  TaxCalculator  #1  #2
Request 2
  PricingRules   #1  #1
  ShoppingCart   #2  #2
  TaxCalculator  #3  #4
VS Code running Lifetimes.cs: .NET dependency injection lifetimes, singleton, scoped and transient instance numbers across two scopes
Singleton keeps #1, scoped changes per request, transient changes on every resolve

PricingRules stays #1 everywhere. ShoppingCart is #1 twice in request 1 and #2 twice in request 2. TaxCalculator gets a new number on every call, #1 through #4.

LifetimeOne instance perTypical example
Singletonapplicationconfiguration cache, HttpClient factory, HybridCache
ScopedHTTP request (scope)EF Core DbContext, unit of work, current user
Transientresolvelightweight, stateless helpers

Q11. What is a captive dependency, and how do you catch it? (Senior)

Short answer: A captive dependency is a longer-lived service holding a shorter-lived one, usually a singleton that takes a scoped DbContext in its constructor. The scoped object then lives forever and is shared across requests.

#:package Microsoft.Extensions.DependencyInjection@10.0.13
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddScoped<OrderDbContext>();
services.AddSingleton<PriceCache>();    // singleton asks for scoped

using var loose = services.BuildServiceProvider();
using var s1 = loose.CreateScope();
using var s2 = loose.CreateScope();
int a = s1.ServiceProvider.GetRequiredService<PriceCache>().Db.Id;
int b = s2.ServiceProvider.GetRequiredService<PriceCache>().Db.Id;
Console.WriteLine($"No validation: scope 1 DbContext #{a}, scope 2 #{b}");

using var strict = services.BuildServiceProvider(validateScopes: true);
try { strict.GetRequiredService<PriceCache>(); }
catch (InvalidOperationException ex) { Console.WriteLine(ex.Message); }

class OrderDbContext { static int count; public int Id { get; } = ++count; }
class PriceCache(OrderDbContext db) { public OrderDbContext Db => db; }

Output:

No validation: scope 1 DbContext #1, scope 2 #1
Cannot consume scoped service 'OrderDbContext' from singleton 'PriceCache'.
VS Code running Captive.cs: captive dependency in .NET DI, the same DbContext in two scopes and the ValidateScopes InvalidOperationException
Without validation both scopes share DbContext #1; ValidateScopes throws instead

Without validation, both scopes got DbContext #1, which is a thread-safety bug waiting to happen. With validateScopes: true, the container threw “Cannot consume scoped service ‘OrderDbContext’ from singleton ‘PriceCache’.”

ASP.NET Core turns scope validation on in the Development environment, so you’ll usually see this at startup. The fix is to inject IServiceScopeFactory into the singleton and create a scope when you need the DbContext.

Q12. What are keyed services? (Mid)

Short answer: Added in .NET 8, keyed services let you register several implementations of one interface under different keys, then pick one with [FromKeyedServices("key")].

For example, AddKeyedSingleton<IShippingRates, UpsRates>("ups") and another for “fedex”. Before .NET 8 you’d write a factory or inject IEnumerable<T> and filter it.

Middleware Pipeline Interview Questions (Mid)

Q13. What is middleware, and what’s the difference between Use, Run and Map? (Junior)

Short answer: Middleware is a component in the request pipeline that can handle a request, change it, and call the next one. Use calls next, Run ends the pipeline, and Map branches it by path.

Each piece is a RequestDelegate, so knowing delegates in C# makes the whole model click.

Q14. Does middleware order matter? Prove it. (Mid)

Short answer: Yes. Middleware runs top to bottom on the way in and bottom to top on the way out, so the first one registered sees the request first and the response last.

I ran a real minimal API in memory with TestServer, no port needed, and logged each step:

#:sdk Microsoft.NET.Sdk.Web
#:package Microsoft.AspNetCore.TestHost@10.0.13
using Microsoft.AspNetCore.TestHost;

var builder = WebApplication.CreateBuilder();
builder.WebHost.UseTestServer();      // in-memory server, no port
builder.Logging.ClearProviders();
var app = builder.Build();

app.Use(Step("1 RequestTimer"));
app.Use(Step("2 CorrelationId"));
app.MapGet("/orders/{id}", (int id) =>
{
    Console.WriteLine("3 Endpoint runs");
    return $"Order {id} shipped to Austin, TX";
});

await app.StartAsync();
var body = await app.GetTestClient().GetStringAsync("/orders/1042");
Console.WriteLine($"Response: {body}");
await app.StopAsync();

static Func<HttpContext, RequestDelegate, Task> Step(string name) => async (ctx, next) =>
{
    Console.WriteLine($"{name,-16}-> in");
    await next(ctx);
    Console.WriteLine($"{name,-16}<- out");
};

Output:

1 RequestTimer  -> in
2 CorrelationId -> in
3 Endpoint runs
2 CorrelationId <- out
1 RequestTimer  <- out
Response: Order 1042 shipped to Austin, TX
VS Code running Pipeline.cs: ASP.NET Core middleware order with app.Use and a minimal API endpoint, in and out messages from TestServer
RequestTimer runs first in and last out; the endpoint runs in the middle

The output nests like parentheses: 1 in, 2 in, endpoint, 2 out, 1 out. That’s why the exception handler goes first, so it can catch anything thrown later.

Microsoft’s recommended order is: exception handler and HSTS, HTTPS redirection, static files, routing, CORS, authentication, authorization, then your custom middleware and endpoints. WebApplication adds UseRouting for you when you don’t call it.

Q15. How do you handle exceptions globally in ASP.NET Core? (Mid)

Short answer: Call app.UseExceptionHandler() early in the pipeline, register AddProblemDetails() so errors come back as RFC 7807 JSON, and optionally add an IExceptionHandler class for custom logic.

Inside the endpoint itself you still use try-catch in C# for errors you can actually recover from, like a retry. Don’t wrap every action in try-catch just to log; that’s what the handler is for.

Configuration and Options Pattern Interview Questions (Mid)

Q16. Where does ASP.NET Core read configuration from, and in what order? (Mid)

Short answer: WebApplication.CreateBuilder loads appsettings.json, then appsettings.{Environment}.json, then user secrets (in Development), then environment variables, then command-line arguments. Later sources win.

So Store__City=Denver as an environment variable overrides the JSON file. That’s how Azure App Service settings replace values without changing the deployed files.

Q17. What’s the difference between appsettings.json and secrets.json? (Junior)

Short answer: appsettings.json is committed with the code. secrets.json (user secrets) lives in your user profile, never in the repo, and only loads in Development.

In production, secrets belong in Azure Key Vault or environment variables, not in either file. Interviewers want to hear that you’ve never pushed a connection string to GitHub.

Q18. How does the options pattern work, and IOptions vs IOptionsSnapshot vs IOptionsMonitor? (Mid)

Short answer: You bind a configuration section to a plain class and inject IOptions<T>. IOptions reads once (singleton), IOptionsSnapshot re-reads per request (scoped), and IOptionsMonitor gets change notifications (singleton).

Here I bind a “Store” section from in-memory configuration, which is just a C# dictionary of keys like Store:City:

#:package Microsoft.Extensions.Options.ConfigurationExtensions@10.0.13
#:package Microsoft.Extensions.DependencyInjection@10.0.13
using System.Globalization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

CultureInfo.CurrentCulture = new CultureInfo("en-US");
// The same keys you'd put in appsettings.json under "Store"
var config = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?>
{
    ["Store:City"] = "Seattle",
    ["Store:SalesTaxRate"] = "0.1035",
    ["Store:FreeShippingOver"] = "75"
}).Build();

var services = new ServiceCollection();
services.AddOptions<StoreOptions>().Bind(config.GetSection("Store"));
using var sp = services.BuildServiceProvider();

StoreOptions store = sp.GetRequiredService<IOptions<StoreOptions>>().Value;
Console.WriteLine($"City: {store.City}");
Console.WriteLine($"Sales tax: {store.SalesTaxRate:P2}");
Console.WriteLine($"Free shipping over: {store.FreeShippingOver:C0}");

public class StoreOptions
{
    public string City { get; set; } = "";
    public decimal SalesTaxRate { get; set; }
    public decimal FreeShippingOver { get; set; }
}

Output:

City: Seattle
Sales tax: 10.35%
Free shipping over: $75
VS Code running Options.cs: .NET options pattern binding a Store section to StoreOptions and reading it with IOptions
The binder converted “0.1035” and “75” into decimals on StoreOptions

The binder turned the string “0.1035” into a decimal, shown as 10.35%. Add .ValidateDataAnnotations().ValidateOnStart() and a bad value fails at startup instead of on the first request.

Program.cs, Hosting and Kestrel Interview Questions (Mid)

Q19. What happened to Startup.cs, ConfigureServices and Configure? (Junior)

Short answer: Since .NET 6, the templates use minimal hosting: one Program.cs where builder.Services replaces ConfigureServices and the code after builder.Build() replaces Configure.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();        // was ConfigureServices

var app = builder.Build();
app.UseExceptionHandler();                    // was Configure
app.MapGet("/health", () => "OK");
app.Run();

Startup.cs still works if you call it from the generic host, so older apps don’t break. But if an interviewer asks about it, show that you know the Program.cs version.

Q20. What is the Generic Host, and what’s a Worker Service? (Mid)

Short answer: The Generic Host (IHost) wires up DI, configuration, logging and app lifetime for any .NET app. A Worker Service is a host with no web server that runs BackgroundService classes.

BackgroundService is an abstract class in C# where you override ExecuteAsync. It’s a good fit for queue processors or a nightly job that will send emails with attachments.

Q21. What is Kestrel, and do you still need IIS? (Mid)

Short answer: Kestrel is ASP.NET Core’s built-in, cross-platform web server. On Windows, IIS can host the app in-process through the ASP.NET Core Module; on Linux you usually put Nginx, YARP or a cloud load balancer in front.

Kestrel is fast enough to face the internet directly, but a reverse proxy still helps with TLS termination, multiple sites on one IP and request filtering.

Q22. How do you deploy ASP.NET Core to containers and Azure App Service? (Mid)

Short answer: For containers, dotnet publish /t:PublishContainer builds an image without a Dockerfile, and .NET 8+ images listen on port 8080 as a non-root user. For Azure App Service, publish from Visual Studio, the CLI or a GitHub Actions workflow.

Senior candidates should mention health checks (MapHealthChecks), deployment slots for zero-downtime swaps, and keeping secrets in Key Vault references.

Minimal APIs vs Controllers: Web API Interview Questions (Mid)

Q23. When would you use minimal APIs instead of controllers? (Mid)

Short answer: Minimal APIs are lighter and work with Native AOT, so they’re great for microservices and new APIs. Controllers still make sense for large apps that rely on filters, model binding conventions and an existing MVC codebase.

Both return JSON through System.Text.Json. If you’ve ever fought escaped quotes in output, my post on how to convert an object to JSON without escape characters explains the encoder settings.

var orders = app.MapGroup("/api/orders").RequireAuthorization();
orders.MapGet("/{id:int}", async (int id, OrderDbContext db) =>
    await db.Orders.FindAsync(id) is Order o ? Results.Ok(o) : Results.NotFound());

Q24. How do you document an API with OpenAPI (Swagger) in .NET 10? (Mid)

Short answer: Call builder.Services.AddOpenApi() and app.MapOpenApi(). Since .NET 9 the templates use Microsoft.AspNetCore.OpenApi instead of Swashbuckle, and in .NET 10 the generated document is OpenAPI 3.1 by default.

You can still add Swagger UI or Scalar for a browsable page. .NET 10 also added built-in minimal API validation with builder.Services.AddValidation().

Q25. What are Razor Pages, Blazor and SignalR used for? (Junior)

Short answer: Razor Pages is page-focused server rendering, Blazor builds interactive UI in C# (server or WebAssembly), and SignalR pushes real-time messages to browsers, like live order tracking.

SignalR’s hub methods feel a lot like events in C# that cross the network. For a quick server-to-browser stream, .NET 10 also has TypedResults.ServerSentEvents.

Authentication and Authorization Interview Questions (Mid to Senior)

Q26. Authentication vs authorization: how does JWT bearer authentication work? (Mid)

Authentication answers “who are you?” and builds the ClaimsPrincipal; authorization answers “what may you do?” with roles, claims or policies. That’s why UseAuthentication comes before UseAuthorization.

Short answer: The client sends Authorization: Bearer <token>. AddJwtBearer validates the signature, issuer, audience and expiry, then turns the claims into HttpContext.User.

Keep access tokens short-lived and never put secrets or personal data in the payload, because anyone can base64-decode it. Signing isn’t encryption.

Q27. How do you protect an API with Microsoft Entra ID? (Senior)

Short answer: Register the API in Microsoft Entra ID (formerly Azure AD), then use Microsoft.Identity.Web: AddAuthentication().AddMicrosoftIdentityWebApi(builder.Configuration) with an “AzureAd” config section, and require scopes or app roles per endpoint.

For apps with their own sign-in, ASP.NET Core Identity in .NET 10 now supports passkeys. If you’ve built a custom flow like an OTP in ASP.NET, be ready to explain why you’d move to a standard provider.

Q28. Which security measures do you add to every ASP.NET Core app? (Senior)

Short answer: HTTPS with HSTS, a strict CORS policy, antiforgery for cookie-based forms, rate limiting (AddRateLimiter), secrets in Key Vault, and authorization on by default with a fallback policy.

Entity Framework Core Interview Questions (Mid to Senior)

Q29. What is EF Core, and what does change tracking do? (Junior)

Short answer: EF Core is Microsoft’s ORM: you query with LINQ and save with SaveChangesAsync. Change tracking remembers loaded entities so it can generate UPDATE statements; AsNoTracking() skips that for read-only queries.

Queries come back as a List in C# or a single entity. Remember that AddDbContext registers the context as scoped, which ties back to the lifetime question above.

Q30. What is the N+1 problem, and how do you fix it? (Senior)

Short answer: N+1 is one query for a list plus one extra query per row, usually from lazy loading inside a loop. Fix it with Include, a Select projection to a DTO, or AsSplitQuery() for big graphs.

// 1 query instead of 1 + N
var report = await db.Customers
    .Where(c => c.State == "CA")
    .Select(c => new { c.Name, OrderCount = c.Orders.Count })
    .AsNoTracking()
    .ToListAsync();

Q31. How do you apply EF Core migrations in production? (Senior)

Short answer: Create them with dotnet ef migrations add, then in production apply a reviewed SQL script (dotnet ef migrations script --idempotent) or a migration bundle from your pipeline. Avoid calling Migrate() at app startup on multiple instances.

Async/Await and Logging Interview Questions (Mid)

Q32. How does async/await help an ASP.NET Core app? (Mid)

Short answer: While an await waits on I/O, the thread goes back to the pool to serve other requests. It doesn’t make one request faster, but it lets the server handle many more at once.

You can still make independent calls overlap. I called a fake 1-second tax API three times, first one after another, then with Task.WhenAll:

using System.Diagnostics;

var sw = Stopwatch.StartNew();
await GetRateAsync("Texas"); await GetRateAsync("Ohio"); await GetRateAsync("Utah");
Console.WriteLine($"One after another: {sw.Elapsed.TotalSeconds:F1} s");

sw.Restart();
decimal[] rates = await Task.WhenAll(GetRateAsync("Texas"), GetRateAsync("Ohio"), GetRateAsync("Utah"));
Console.WriteLine($"Task.WhenAll:      {sw.Elapsed.TotalSeconds:F1} s -> {string.Join(", ", rates)}");

// Pretend each call is a 1-second HTTP request to a sales tax API
static async Task<decimal> GetRateAsync(string state)
{
    await Task.Delay(1000);   // frees the thread while it waits, unlike Thread.Sleep
    return state switch { "Texas" => 6.25m, "Ohio" => 5.75m, _ => 6.10m };
}

Output:

One after another: 3.0 s
Task.WhenAll:      1.0 s -> 6.25, 5.75, 6.10

Sequential took 3.0 seconds and Task.WhenAll took 1.0. Never use .Result or .Wait() on a task in a request; it blocks a thread and can starve the pool.

Q33. What’s the difference between concurrency and parallelism, and what are async streams? (Senior)

Short answer: Concurrency is juggling several tasks that overlap in time (like the awaits above); parallelism is running work on several CPU cores at once (Parallel.ForEachAsync). Async streams (IAsyncEnumerable<T> with await foreach) return items as they arrive.

Q34. How does logging work with ILogger, and where does Serilog fit? (Mid)

Short answer: You inject ILogger<T> and write structured messages with named placeholders. Providers (console, Application Insights, Serilog) decide where they go, and the minimum level filters the noise.

#:package Microsoft.Extensions.Logging.Console@10.0.13
using Microsoft.Extensions.Logging;

using var factory = LoggerFactory.Create(b => b
    .AddSimpleConsole(o => o.SingleLine = true)
    .SetMinimumLevel(LogLevel.Information));
ILogger logger = factory.CreateLogger("Orders");

logger.LogDebug("Cart contents: {Items}", 3);    // below the minimum level, so it's skipped
logger.LogInformation("Order {OrderId} placed by {Customer}", 1042, "Jenna Moore");
logger.LogWarning("Inventory low for {Sku} in {City}", "SKU-778", "Denver");
logger.LogError(new TimeoutException("Payment gateway timed out"), "Payment failed for order {OrderId}", 1043);

Output:

info: Orders[0] Order 1042 placed by Jenna Moore
warn: Orders[0] Inventory low for SKU-778 in Denver
fail: Orders[0] Payment failed for order 1043 System.TimeoutException: Payment gateway timed out
VS Code running Logging.cs: .NET ILogger structured logging to the console with info, warn and fail levels
LogDebug is filtered out; info, warn and fail lines reach the console

The Debug line never printed because the minimum level was Information. Use {OrderId} placeholders, not string interpolation, so a sink like Serilog or Application Insights can store OrderId as a searchable field.

Serilog plugs in with builder.Host.UseSerilog(). Older apps often used log4net.

Performance and Caching Interview Questions (Senior)

Q35. IMemoryCache, IDistributedCache, HybridCache or output caching: which one? (Senior)

Short answer: Use IMemoryCache for one server, IDistributedCache (Redis) to share across servers, HybridCache for both layers plus stampede protection, and output caching to store whole HTTP responses.

CacheStoresGood for
IMemoryCacheobjects in this processsingle instance, small data
IDistributedCachebytes in Redis or SQL Serverweb farms, sessions
HybridCachememory + optional distributedmost new code (GetOrCreateAsync)
Output cachingfull HTTP responsesGET endpoints (CacheOutput())

HybridCache lives in the Microsoft.Extensions.Caching.Hybrid package and you register it with AddHybridCache(). Only one caller per key runs the factory, so a cold cache doesn’t hammer your database.

Q36. How would you speed up a slow ASP.NET Core API? (Senior)

Short answer: Measure first (Application Insights, dotnet-counters), then fix the biggest cost: usually database round trips, missing indexes or N+1 queries, then caching, response compression and async I/O.

Smaller wins come from avoiding allocations in hot paths, such as knowing the difference between string and StringBuilder in C#, and using IHttpClientFactory instead of creating HttpClient per call.

Testing Interview Questions: xUnit and WebApplicationFactory (Mid)

Q37. How do you unit test and integration test an ASP.NET Core app? (Mid)

Short answer: Unit test classes with xUnit (or NUnit/MSTest) and fakes for their interfaces. Integration test the whole pipeline with WebApplicationFactory<Program> from Microsoft.AspNetCore.Mvc.Testing, which runs the app on an in-memory TestServer.

public class OrdersApiTests(WebApplicationFactory<Program> factory)
    : IClassFixture<WebApplicationFactory<Program>>
{
    [Fact]
    public async Task Get_order_returns_200()
    {
        var client = factory.CreateClient();
        var response = await client.GetAsync("/orders/1042");
        response.EnsureSuccessStatusCode();
    }
}

With top-level statements, the test project needs to see Program, so many teams add public partial class Program { }; that’s a partial class in C#. The middleware demo above used the same TestServer underneath.

Behavioral .NET Interview Questions (All Levels)

US companies spend real time on these, often one full round. Answer with the STAR format: situation, task, action, result, and give numbers when you have them.

Q38. Tell me about a production bug you fixed. (All levels)

Short answer: Pick a real one with a clear cause, like a captive DbContext causing random errors under load. Explain how you found it (logs, traces), the fix, and what you changed so it can’t happen again.

Q39. How would you migrate a .NET Framework app to .NET 10? (Senior)

Short answer: Inventory dependencies, move class libraries first (to .NET Standard 2.0 or multi-target), then the web layer, one slice at a time behind a reverse proxy (the strangler pattern) so both apps run side by side.

Q40. How do you disagree with a teammate’s design? (All levels)

Short answer: Ask questions first, bring data like a quick benchmark or a spike, agree on the trade-off, and once the team decides, commit to it. Interviewers look for respect and ownership, not winning.

Which .NET Core Interview Questions to Study for Your Level?

LevelFocus onQuestions
Junior (0-2 years)platform, CLI, DI basics, Program.csQ1-Q4, Q9, Q13, Q17, Q19
Mid (2-5 years)lifetimes, middleware order, options, EF Core, asyncQ10, Q14-Q18, Q23-Q24, Q29, Q32
Senior (5+ years)captive dependencies, N+1, caching, security, migrationQ11, Q27-Q28, Q30-Q31, Q35-Q36, Q39

My advice: run the six demos above yourself. Saying “I’ve seen ValidateScopes throw on this exact case” lands far better than reciting a definition.

For the C# side of the same interview loop, these pair well with this guide:

Frequently Asked Questions

Is .NET Core still used in 2026?

Yes, under the name .NET. Every version since .NET 5 is the continuation of .NET Core, and .NET 10 is the current LTS release, supported until November 14, 2028.

Which .NET version should I learn for interviews?

Learn .NET 10 with C# 14. It’s the LTS release most US teams are moving to, and .NET 8 and .NET 9 both leave support on November 10, 2026.

Are Startup.cs questions still asked?

Sometimes, for older codebases. Explain that ConfigureServices became builder.Services and Configure became the code after builder.Build() in Program.cs.

What’s the most common ASP.NET Core interview question?

The difference between AddSingleton, AddScoped and AddTransient, usually followed by the captive dependency problem. The official service lifetimes guide on Microsoft Learn is worth reading the night before.

Do I need to know Azure for a .NET job in the US?

For most backend roles, yes at a basic level: App Service, Key Vault, Microsoft Entra ID and Application Insights come up often, along with containers.