Skip to content

C# development

C# is a language, not a plan. What usually needs deciding is whether your codebase is held back by the language version it was written against, the platform it runs on, or the architecture underneath it. Those are three different bills.

01Capabilities

Where the C# code itself is the deciding factor

This page is about the language. Platform questions, runtimes, hosting, desktop and service workloads, belong on our .NET page, and web application questions belong on our ASP.NET page. What follows is the work where the C# code itself is the thing that matters.

  • Domain

    Business systems where the rules are the product

    Order management, dispatch, inspection and service workflows, the shape of system that runs an automotive service operation. C# is at its best when a domain carries a lot of rules and those rules have to still be readable five years later.

  • Jobs

    Background processing and long-running work

    Queue consumers, scheduled jobs, import and reconciliation pipelines. The hard bugs we inherit in this area are usually async and cancellation bugs rather than business-logic bugs, which is exactly where language-level discipline pays for itself.

  • Libraries

    Shared domain libraries across several front ends

    One C# implementation of the rules, consumed by a web API, a worker service and a mobile client, instead of three copies that drift apart. Designing the package boundary and the versioning policy is the real work, not writing the code.

  • Modernization

    Language-level modernization of existing C#

    Codebases written against C# 5 or 6 that compile fine and cost far too much to change. Nullable reference types, pattern matching, records, async all the way down, and analyzers that stop the old habits returning. This is a separate exercise from a framework migration and often much cheaper, see legacy modernization.

03Fit

When the language is not what is holding you back

C# is a strong default for rule-heavy business systems and a poor one for several problems it gets used for anyway. Before the language question there is usually a routing question, because half of what people call a C# decision is a platform or a web framework decision wearing the wrong label. Five of the six rows below point away from a C# project with us, and one of them points outside unicrew entirely.

Six codebases, and the call we would make on each
Your situationWhat we recommend
A rule-heavy transactional system in a Microsoft estate, expected to outlive the team that builds it Use C#Strong typing, a mature async model, and tooling that makes a large refactor survivable rather than heroic.
The real question is hosting, runtimes, or a desktop or service workload Different pageNot a language question at all. Our .NET page covers the platform side of this.
The real question is a web application: routes, authentication, a Web Forms estate Different pageOur ASP.NET page. There the framework decision dominates the language one.
The product is really a data or machine-learning pipeline We argue againstThe library gap is not close, and Python owns that ground. Writing it in C# buys you nothing you can point at.
A hard latency floor, a fixed memory budget, or code that runs on a device We argue againstGarbage collection is the wrong trade. C++ for a performance-critical component, or C on constrained hardware.
A working internal tool in another language, and a corporate standard says move it to C# Leave it aloneRewriting a healthy codebase to match a standard is cost with no product outcome. Spend it on something a user would notice.

Scope

What we own when we work in C# is the design and its consequences. That means the domain model, the async and concurrency behaviour, the upgrade path, and whether your own developers can keep changing the code after we stop. We work under an ISO 27001:2022 certified information-security management system. unicrew has been building this kind of system since 2012, with 100+ senior in-house engineers across six countries. Where the honest answer is a smaller piece of work than the one you came for, you get that answer.

The expensive part of an old C# codebase is almost never the syntax. It is that nobody can say which references are allowed to be null, so every change gets made carefully rather than confidently. Nullable reference types answer that question mechanically, and it is the one upgrade I would run before any framework move. The catch is that they surface the whole problem at once, so it has to be sequenced against real work rather than switched on in a single commit.

Oleksandr TrofimovChief Technology Officer, unicrew

04Delivery

Picking up a codebase written against an older C#

Language-level work has a sequence. Running it in the wrong order turns a modernization into a stabilisation project with a modernization budget.

  1. Establish what the compiler is being toldTarget framework, language version, warning settings, analyzer configuration, and how much of the build runs with warnings suppressed. This tells you more about a codebase in an hour than the documentation will in a week.
  2. Get the money paths under testCharacterisation tests around the behaviour the business actually depends on, before anything is refactored. Nullable annotations and mechanical rewrites are only safe changes when something is watching the outcome, which is why they go through the same QA and test automation practice as our own builds.
  3. Turn the guardrails on with a budgetNullable reference types and analyzers enabled at warning level, with an agreed count that is only allowed to go down. Switch everything to errors on day one and the whole thing gets switched back off by Friday.
  4. Fix correctness before performanceBlocking on async code, fire-and-forget tasks, disposables that outlive their scope, shared state with no memory model behind it. These produce the intermittent failures people blame on infrastructure, and they are far cheaper to fix than to keep diagnosing.

06Stack

What a C# system is usually wired into

The technologies that turn up around the same codebases, each with its own page if that is the decision you are actually making.

07Questions

The questions that decide the scope

Short answers to what actually gets asked, before anyone opens the repository.

Yes, and on an inherited codebase that is often the sensible shape, because your people hold the domain knowledge. What we will not do is supply developers and treat the result as somebody else's problem. An architect outside the delivery team reviews the design, and the code goes through the same QA practice we use on our own projects. Capacity is managed teams; an outcome is custom software development.

C# is the language, .NET is the platform it runs on, ASP.NET is the web framework above that. Language version, code quality, async correctness or a large refactor: this page. Runtimes, hosting, desktop or service workloads: .NET. A web application, its routes, or getting off Web Forms: ASP.NET. Real engagements touch all three, so pick the closest and we will sort it out on the call.

Often yes, and it is one of the few modernization steps that pays back quickly. A language-version upgrade is much smaller than a framework migration and does not change what the application does. Nullable reference types alone surface a category of null bugs that has been costing you support time for years. The caveat is the wall of warnings, so it has to be sequenced against real work.

Mostly a question about your estate and your people, since the languages have converged. If you already run Active Directory, SQL Server and Windows infrastructure, C# will be cheaper end to end. If your operations, monitoring and hiring already sit on the JVM, Java will be. Where neither is true we choose on the team you can hire and keep. Anyone answering this without asking about your infrastructure is guessing.

A scoping call with an engineer rather than a salesperson. For an existing codebase we ask for read access to the repository, because half an hour with the build output moves an estimate more than an hour of description. What comes back is written: what we would do first, what we would not touch, and where the risk sits. Most engagements start within two to four weeks.

Three shapes, and which fits depends on how settled the scope is. Time and materials is billed hourly and quoted per project, which suits work still moving. Fixed price is outcome based, and we only offer it once the first read is done. Team extension is billed monthly per engineer. The rate depends on the seniority mix, so it is quoted rather than listed.

Not sure which of the three bills you are paying?

Send us the repository and the version you are pinned to. You will get an engineer's read on where the cost actually sits. That includes the parts we would leave exactly as they are.

Book a scoping call

Thank you

Thanks for your message. We will get in touch with you shortly.