Let's talk

Backend

Hire .NET Developers

.NET engineers who are equally at home in modern .NET and in the Framework estates still running the business.

.NET earns its place where correctness, tooling and long support horizons matter more than fashion. It is also where a great deal of unglamorous value sits, because a large share of working enterprise software is still on .NET Framework 4.x, out of support in all but name, and running something nobody can afford to switch off.

.NET Framework 4.8 is the end of that line — it ships as a Windows component and will not gain new features — so every Framework application is now on a clock set by the operating system rather than by the team maintaining it. That single fact shapes most .NET hiring we are asked about.

What actually blocks a Framework migration

It is almost never the language. Three dependencies do the blocking, and a candidate who has done this work names them without being prompted.

System.Web is the first. It was never ported, and the trouble is not HttpContext itself but HttpContext.Current — ambient static access reached from deep inside business logic that has no business knowing a request exists. Every one of those call sites has to become a parameter or an injected abstraction, and finding them is the migration.

WCF is the second: there is no in-box equivalent, so a service contract either moves to gRPC or minimal APIs, or it stays on a compatibility layer someone has to own. WebForms is the third, and it has no path at all — a page with logic in code-behind is rewritten, not converted, which makes it the item that decides whether the project is a migration or a rebuild.

Why a big-bang cutover fails here specifically

Framework applications tend to be long-lived, which means they have accumulated behaviour nobody can describe and several integrations nobody can test. A rewrite bets that all of that can be rediscovered on a deadline.

The approach that works is incremental: put the new application in front, route one path at a time to it, and leave the rest on the old stack until its replacement has run in production. That requires shared authentication and shared session state across two runtimes, which is real work and should appear in the estimate rather than as a surprise in week six.

The other reason it works is reversibility. Routing one path forward means routing it back takes a configuration change, not a rollback plan.

Async, and the deadlock that only happens in the old stack

Classic ASP.NET has a synchronisation context that resumes continuations on the original request thread. Blocking on an async call — .Result, .Wait() — inside that context deadlocks, which is why ConfigureAwait(false) was a survival habit in library code for a decade.

ASP.NET Core removed the context, and the same code stops deadlocking. That is not a fix, it is a symptom disappearing: sync-over-async still consumes a thread per blocked call and still degrades under load. Engineers who learned the workaround without the reason often carry the pattern forward, and it is worth probing for in an interview.

EF Core is not EF6 with a new name

Lazy loading is off unless proxies are enabled, which turns silent extra queries into null references — noisier, and better. Client-side evaluation of a where clause the provider cannot translate used to happen quietly; it now throws, which is the single most useful behaviour change in the library. And a query with two collection includes produces a cartesian product unless it is split, which is the most common cause of an EF Core query that was fast in testing and is not in production.

Migrations also behave differently enough that an EF6 model and its migration history do not carry across cleanly, and pretending otherwise is how a migration project loses a week.

There is a legitimate use for the old stack, though, and it is worth naming because it comes up on every modernisation. One of the tools we maintain is a .NET Framework console application built precisely to move data out of SQL Server and into PostgreSQL, with a designer-generated model and providers for both databases registered at once. A short-lived, single-purpose migration utility is exactly the place to keep using the framework the old system was written in — it has to read the old schema faithfully, it runs once, and rewriting it in modern .NET buys nothing.

Where .NET is the wrong choice

If the team has no Windows or Azure gravity, no existing .NET code and no C# experience, choosing it for a small web service is choosing a hiring problem. If the workload is data science or model training, the ecosystem is thin compared with Python and there is no reason to fight that. And if the honest requirement is a static site or a content-driven marketing presence, an application framework of any kind is the wrong tool.

What we interview for, and how a migration is proved

We ask whether a candidate has migrated an application or only worked on one already migrated — the difference shows immediately. How did they break a monolith into shippable stages, what did they do about a dependency with no modern equivalent, and how did they know the behaviour was identical afterwards.

That last question matters most. The answer we look for is characterisation tests written against the old system before anything moved: capture real inputs and the outputs the legacy code actually produces — including the wrong ones, which are now contracts other systems depend on — and run them against the new implementation. A migration is proved by that suite, not by a regression sign-off from the people who wrote the original.

Teams are built for companies in the United States and the Gulf — the UAE, Saudi Arabia, Qatar, Kuwait, Bahrain and Oman. The engineers are in Pune, which matters mostly for the clock. Dubai is ninety minutes behind us and Riyadh two and a half hours, so a Gulf team shares almost the whole working day. New York is nine and a half hours behind, so American engagements run on a written handover and one fixed overlap window rather than on a standing call — a real constraint, and better stated than discovered.

What these engineers do

  • ASP.NET Core 8 and 9, minimal APIs and MVC with dependency injection used cleanly
  • Entity Framework Core, migrations and query tuning on SQL Server or PostgreSQL
  • Blazor and Razor for internal tooling where a separate SPA is not worth its cost
  • Migration from .NET Framework 4.x to modern .NET without a single big-bang cutover
  • Azure App Service, Service Bus and Application Insights in production

Delivered AI-first

Legacy migration is where AI assistance pays for itself in .NET. Assistants are effective at translating Framework-era patterns into their modern equivalents - Web API controllers to minimal APIs, WebForms code-behind into services, System.Web dependencies into abstractions, old EF6 mappings into EF Core - and at generating the characterisation tests that prove behaviour did not change. Every converted file is reviewed, and the tests decide whether the translation held. The measurable effect is throughput per engineer, not fewer reviews.

.NET engineers in client teams

Tell us what the .NET work is.

Roughly what it involves, the seniority you need, and when it has to start. We will say what it takes to staff it, or say honestly that we are not the right people for it.

A person reads every enquiry and replies within one working day.