Skip to content
Journal

Business · Hiring

How to Hire a .NET Developer in 2026: C#, ASP.NET Core, and What to Screen For

The .NET platform has changed more in the last three years than in the decade before. Here is what a strong .NET developer looks like today, what questions reveal real skill, and what separates modern .NET engineers from those still working in a 2015 mindset.

Prathviraj Singh

Prathviraj Singh

8 min read

How to Hire a .NET Developer in 2026: C#, ASP.NET Core, and What to Screen For

Sponsored

Share

The biggest hiring mistake in .NET recruiting is treating the platform as a monolith. There is ”.NET Framework” (the Windows-only, IIS-dependent stack that enterprise teams have run for 20 years) and there is modern .NET (8, 9, and beyond), which is cross-platform, ships in containers, and is a genuinely different development experience. A developer who spent a decade on the first may need real adjustment time to be productive on the second. The job description needs to specify which world you are operating in.

.NET 8 is the current LTS release. If your team is building new services, .NET 8 is the right baseline. If you are maintaining a legacy enterprise system, .NET Framework experience may still be required. Know which one you need before you start the screen.

The two .NET profiles

Enterprise/legacy .NET engineers have depth in .NET Framework, WCF services, Entity Framework 6, Windows Server deployment, and often COM interop. This background is valuable for maintaining existing systems but can be a liability on a greenfield project where the team expects ASP.NET Core, Docker, Linux containers, and CI/CD pipelines that push to Kubernetes.

Modern .NET engineers are comfortable with ASP.NET Core, .NET 8+, Minimal APIs, Entity Framework Core, Dockerized deployment, and the Microsoft.Extensions ecosystem (logging, configuration, dependency injection). They treat the platform as cross-platform by default. These developers are more directly transferable to a modern engineering organization.

Neither profile is better in absolute terms. The question is which one matches your codebase and team.

The async/await question

ASP.NET Core is built around async I/O. Every HTTP handler, database call, and external API call goes through the async/await pattern. A developer who does not understand it will write blocking code inside async methods and wonder why the server under load performs poorly.

Ask: “When you await a Task, what happens to the thread? What is the benefit over blocking with .Result or .Wait()?”

A passing answer: the current thread returns to the thread pool while the awaited work completes. When the async operation finishes, the continuation resumes on a thread pool thread (or the original thread in some contexts). Blocking with .Result or .Wait() holds the thread and can cause deadlocks in ASP.NET, particularly in older contexts where SynchronizationContext is captured. Async frees the thread for other requests, improving throughput under load without needing more threads.

A developer who cannot give this answer at a conceptual level does not understand what they are building on.

Follow up: “What is ConfigureAwait(false) and when would you use it?” In library code that doesn’t need to run continuations on the original SynchronizationContext. The thread pool thread does not need to marshal back to the UI or request context. This is a common pattern in reusable library code to avoid deadlocks and improve performance. A senior developer in a library author role should know this instinctively.

Dependency injection lifetimes

Dependency injection is the default service registration pattern in ASP.NET Core. It is not optional knowledge.

Ask: “What is the difference between AddScoped, AddTransient, and AddSingleton in ASP.NET Core DI?”

The answer:

  • AddSingleton: one instance for the entire application lifetime. Good for stateless services, caches, and objects that are expensive to create and safe to share across threads.
  • AddScoped: one instance per HTTP request. Good for services that carry request-specific state, like a DbContext or a user context.
  • AddTransient: a new instance every time the service is requested. Good for lightweight, stateless services that may not be thread-safe.

The follow-up that separates experienced from novice: “What happens if you inject a scoped service into a singleton?” The scoped service gets captured in the singleton, which effectively makes it a singleton too. A DbContext registered as scoped and injected into a singleton service becomes a single shared context, which breaks Entity Framework Core’s design assumptions and causes bugs under concurrency. ASP.NET Core will throw an exception at startup if it detects this pattern in release builds.

Entity Framework Core vs Dapper

Most .NET backend roles involve database access. The two common options are Entity Framework Core (the ORM) and Dapper (the micro-ORM). A competent .NET developer should have an opinion on which fits a given situation.

Ask: “When would you choose Dapper over Entity Framework Core?”

Dapper makes sense for: read-heavy workloads where query performance matters and the queries are complex enough that EF Core’s generated SQL becomes harder to predict or optimize; bulk operations; stored procedures that return non-entity result sets; reporting queries with complex joins. EF Core makes sense for: CRUD-heavy apps where the code generation and migration tooling save real time; apps with complex object graphs where the change tracking is valuable; teams that want to stay in C# without writing raw SQL for common operations.

A developer who says “I always use EF Core” or “I never use EF Core” has not hit the situations where the other choice was clearly better. The best answer is situational.

C# language features that signal current knowledge

C# has evolved significantly since version 6. A developer who learned C# in 2014 and has not followed the language may be missing features that the modern codebase uses.

Ask them to write a switch expression (not a switch statement) over an enum with three cases. The syntax is:

var message = status switch
{
    Status.Active => "User is active",
    Status.Inactive => "User is deactivated",
    Status.Pending => "Awaiting verification",
    _ => throw new ArgumentOutOfRangeException(nameof(status))
};

Then ask about records: “What is a record in C# and when would you use one?” A record is a reference type designed for immutable data. It gets value-based equality, a copy constructor (with expression), and a compiler-generated ToString() by default. Good uses: DTOs in a request/response layer, domain value objects, immutable configuration snapshots.

Nullable reference types, introduced in C# 8, are another useful filter. Ask: “What does enabling nullable reference types in a project do, and why would you enable it?” It tells the compiler to distinguish between nullable and non-nullable reference types: string means never null, string? means possibly null. It surfaces potential null-reference exceptions at compile time rather than runtime. A developer who has worked in a team with quality standards will have enabled this in a recent project.

Minimal APIs vs MVC Controllers

ASP.NET Core added Minimal APIs in .NET 6. They are a lighter-weight way to define HTTP endpoints without controllers, routing attributes, or action result types:

app.MapGet("/users/{id}", async (int id, UserService service) =>
{
    var user = await service.GetByIdAsync(id);
    return user is null ? Results.NotFound() : Results.Ok(user);
});

Ask a candidate where they would use Minimal APIs instead of MVC controllers. A good answer: Minimal APIs work well for small services, microservices, or APIs with a limited number of endpoints where the controller overhead adds more code than it saves. MVC controllers make more sense for larger APIs where the separation of concerns (filters, action results, model validation via DataAnnotations, and the controller class structure) pays for itself. Neither is universally better. The candidate should have an opinion.

Take-home task

For a mid-level candidate, a practical take-home reveals more than a live screen.

The task: build a small ASP.NET Core Minimal API that exposes a POST /jobs endpoint. The endpoint accepts a JSON body with a url (string) and a callbackUrl (string). It responds immediately with 202 Accepted and a job ID. In the background, it fetches the URL, counts the number of words in the response body, and POSTs the result to the callbackUrl as JSON: { "jobId": "...", "wordCount": 123 }. The background processing should use an IHostedService or BackgroundService. The endpoint should validate inputs. Tests for the counting logic are expected.

What you learn: async request/response pattern (202 is deliberate), background processing in .NET, service registration, input validation, and whether they write tests. The word-count logic is trivial by design. The structure around it is what you are evaluating.

Where this fits the broader hiring sequence

The .NET-specific screen sits on top of a general engineering bar. The guide to hiring vetted software developers covers the general process. For roles with significant TypeScript or JavaScript work on the frontend, the TypeScript developer screen provides a complementary lens.

The core of a .NET screen is: do they know the modern platform or only the legacy one, can they explain async/await at the runtime level, and do they understand the DI lifetimes they are configuring every day? Those three questions eliminate most of the mismatches.

Frequently asked questions

What is the difference between .NET Framework and .NET Core/.NET 8?
.NET Framework is Windows-only, ships with the OS, and is in maintenance mode. .NET Core (now just called .NET, starting at version 5) is cross-platform, ships as a self-contained or framework-dependent app, and receives active development. .NET 8 is the current LTS release. For new projects, .NET 8 or later is the right choice. A candidate who defaults to .NET Framework for a greenfield project either has a specific legacy reason or has not kept up with the platform.
What is ASP.NET Core and how is it different from ASP.NET (classic)?
ASP.NET Core is a complete rewrite of ASP.NET for the modern .NET platform. It is cross-platform, built on the Kestrel web server, uses constructor-based dependency injection by default, and includes both MVC controllers and Minimal APIs. Classic ASP.NET (WebForms, older MVC) ran on IIS on Windows. The programming model and deployment story are fundamentally different.
Should I require Azure experience for a .NET developer role?
Not as a hard requirement, but it is a reasonable preference. .NET and Azure are both Microsoft products and the tooling integration is tight. Many .NET developers have Azure experience naturally. That said, .NET apps run fine on AWS, GCP, and any Linux host. If your infrastructure is AWS-native, Azure experience is a bonus, not a requirement.
What is the salary range for a .NET developer in 2026?
A mid-level ASP.NET Core developer (3-5 years) in the US typically ranges from $115,000 to $160,000. Senior engineers with architecture and cloud experience run $160,000 to $220,000. .NET commands a premium in enterprise markets (finance, healthcare, government) where the stack is dominant. For vetted remote options, the [developer cost guide](/blog/what-it-costs-to-hire-a-developer-2026/) covers international rate benchmarks.

Sources

Sponsored

Sponsored

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored