Technology · Languages & frameworks

.NET for the systems your business already runs on.

ASP.NET Core services, Entity Framework data layers and Windows-to-Linux modernisation — AI-native C# engineers who work inside Microsoft-heavy estates without fighting them.

.NETWhat we build with it
01ASP.NET Core APIs
02Framework-to-modern migration
03Domain-heavy back-ends
04Integration and messaging
05Data access with EF Core
06Azure-native services
Usually runs with
  1. C#
  2. ASP.NET Core
  3. EF Core
  4. MassTransit
  5. Kafka
  6. SQL Server
Why we use it

Many organisations already have a .NET estate.

Many large organisations in banking, insurance, manufacturing and the public sector already have a .NET estate: SQL Server underneath, Active Directory around it, and years of business rules inside it. We use .NET where that estate exists, because the most direct route to a better system is usually the one that keeps the team, the tooling and the data platform your organisation already trusts.

Modern .NET is a different platform from the .NET Framework most of those estates were built on. It runs on Linux, ships as a container and starts quickly. C# has grown into a precise, expressive language with records, pattern matching and nullable reference types that catch whole categories of bugs at compile time. That is the .NET we build with.

When we don’t: we do not reach for .NET on greenfield products where the team, the hosting and the hiring pool all point at TypeScript or Go, and we do not recommend it for the thin, latency-sensitive edge layer. Where an organisation is Microsoft-native end to end, though, choosing anything else is usually paying for novelty.

What we build with it

Six things we ship on .NET.

01

ASP.NET Core APIs

Minimal APIs and controller-based services with OpenAPI contracts, versioning, rate limiting and structured problem-details errors from the first endpoint.

02

Framework-to-modern migration

Moving .NET Framework 4.x applications to current .NET on Linux containers — WCF to gRPC or REST, Web Forms to Razor or a React front, System.Web dependencies retired one at a time.

03

Domain-heavy back-ends

Policy administration, claims, ledgers and pricing engines where the value is in the rules. We model the domain explicitly and keep it independent of the framework.

04

Integration and messaging

MassTransit or raw Kafka clients, Azure Service Bus, outbox patterns and idempotent consumers — the plumbing behind event-driven estates.

05

Data access with EF Core

Entity Framework Core with migrations under version control, compiled queries where it matters, and Dapper alongside it for the reports EF should not write.

06

Azure-native services

Container Apps, AKS, Functions, Key Vault and Managed Identity wired together with Bicep or Terraform — reviewed with our Azure practice.

Fit

When to choose it.

Right fit

Choose .NET when your organisation already runs SQL Server, Active Directory or Entra ID and Azure; when you have a C# team who will run the system after we leave; when the workload is a long-lived business back-end with heavy domain logic and strict typing pays for itself; or when a .NET Framework application needs to become a modern, containerised service without a rewrite.

Look elsewhere

Look elsewhere when the product is a content-heavy web front where Next.js and a headless CMS do the job with less ceremony; when you need very small, very fast binaries for infrastructure tooling, where Go fits better; or when your data science and ML work already lives in Python and the service is a thin wrapper around it.

In practice

A minimal API endpoint, the way we write it.

Program.cscsharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ClaimsDb>(o => o.UseNpgsql(cs));
builder.Services.AddOpenTelemetry().WithTracing(t => t.AddAspNetCoreInstrumentation());
var app = builder.Build();
// One handler, one query, typed result — no controller boilerplate
app.MapGet("/claims/{id:guid}", async (Guid id, ClaimsDb db, CancellationToken ct) =>
    await db.Claims.AsNoTracking().FirstOrDefaultAsync(c => c.Id == id, ct) is { } claim
        ? Results.Ok(claim.ToDto())
        : Results.Problem(statusCode: 404, title: "Claim not found"))
   .WithName("GetClaim").Produces<ClaimDto>().ProducesProblem(404);
+ app.MapHealthChecks("/healthz");
app.Run();
Reference architecture

How a .NET service estate is laid out.

Edge
Azure Front Door / API ManagementEntra IDRate limiting
Services
ASP.NET Core APIsBackground workersgRPC internal callsMassTransit / Kafka
Data
SQL Server or PostgreSQLRedisBlob storage
Platform
AKS or Container AppsGitHub ActionsOpenTelemetry → GrafanaKey Vault
Our standards

What the .NET codebases we hand over have.

  • Nullable reference types and warnings as errors on from the start — the compiler does the first code review.
  • Tests at three levels: xUnit unit tests, WebApplicationFactory integration tests against a real database in Testcontainers, and a small contract suite per public API.
  • Observability by default: OpenTelemetry traces, metrics and structured logs with correlation IDs, exported to whatever your platform team already runs.
  • Health and readiness endpoints that reflect real dependencies, so Kubernetes and load balancers make honest decisions.
  • Security baseline: Managed Identity over connection strings, secrets in Key Vault, dependency scanning in CI, and OWASP checks in every review.
  • Performance budgets per endpoint, measured with k6 in CI and with real traffic after launch — not guessed from a benchmark blog.
  • EF Core migrations under version control, applied by the pipeline rather than by hand against production.
  • Roslyn analyzers and formatting enforced — StyleCop or the built-in analyzers, an .editorconfig in the repo, and a build that fails on drift.
Typical pairings

What usually ships alongside the code.

  • Solution structure with a documented dependency direction between domain, application and infrastructure projects
  • OpenAPI specification and generated clients for the teams who consume the service
  • CI/CD pipeline with test, scan, build and environment promotion stages
  • Infrastructure as code for the Azure or AWS resources the service depends on
  • Runbook: deployment, rollback, dashboards and the alerts that page someone
  • Migration ledger for modernisation work — what moved, what was retired, what is still on the old runtime and why
Usually runs with
C#ASP.NET CoreEF CoreMassTransitKafkaSQL ServerPostgreSQLAzureKubernetesOpenTelemetry
FAQ

Frequently asked questions

Yes — usually inside a Software Modernisation or Legacy Re-engineering programme. We start with the Upgrade Assistant and a dependency inventory, then move by slice: shared libraries first, then services, then the UI, with both runtimes live until the last slice is verified.
By default. Modern .NET is cross-platform, and a Linux container is usually cheaper and simpler to operate than a Windows one. We keep Windows hosting only where a hard dependency — a COM component, a legacy driver — forces it, and we write that dependency down so it can be retired.
Whichever you already operate well. EF Core supports both, and we build .NET services on each. If you are choosing fresh and have no licensing reason to stay on SQL Server, we usually recommend PostgreSQL.
Yes. .NET and Azure tend to arrive together in enterprise estates, so our C# engineers are comfortable with AKS, Container Apps, Service Bus, Key Vault and Bicep. Our DevOps & Cloud team reviews the infrastructure.
That is often the better model. Staff augmentation puts C# engineers inside your team under your process; a dedicated team takes a whole workstream. Both start with a written brief and continue with regular check-ins with a named account lead.
Related

Neighbouring stacks and the services that use them.

C# engineers who respect your estate.

Tell us what runs today and what needs to change. An engineer reads it and replies in writing with how we would approach it.

✓ No pitch deck✓ Reply from an AI-native engineer✓ Written follow-up