Why .NET and C# Still Sit Behind Every Project I Build
One language, seven very different products.
Mert Celal Yılmaz · Full Stack Developer · Updated:
.NET is Microsoft's open source runtime, and C# is the language that runs on top of it. Together they cover most of what you need to stand up an API, talk to a database and write business logic. .NET 9 brought real performance gains too, with the same code now running faster on less memory.
At ARCA Yazılım, where I've worked as a developer since July 2025, .NET 9 and ASP.NET Core are what I build backend on. Most of what I write are multi-tenant APIs: one codebase, multiple customers, each one seeing only their own data. A good part of the job is also building reusable REST services, so I'm not rewriting the same logic from zero on every new project.
Almost every project running through my hands right now has .NET behind it: the YODER donation platform, an AI-powered call assistant for hotel reservations, an apartment management system, a corporate business management platform, a cloud-based document management system, a multi-tenant personnel transport and fleet optimization platform, and the .NET 10 game server behind Harfsayı, a personal project. Different industries, different problems, same language underneath.
Sticking with one stack across that much variety says less about the language itself and more about the habits you build around it.
ASP.NET Core's middleware pipeline and dependency injection container working together is what actually makes multi-tenancy possible without repeating tenant checks everywhere. A middleware resolves which tenant a request belongs to from a header or subdomain, and the DI container then injects a tenant-scoped connection string or service instance for that request. Tenant resolution ends up living in one place at the framework level, instead of an 'if tenant == X' scattered through every handler.
The most common misunderstanding around async/await is treating it as something that just makes code run faster. What it actually buys you is not blocking a thread while waiting on I/O, a database call, an external API, so it protects the thread pool rather than raw CPU time. Do it halfway, calling .Result or .Wait() on an async method from synchronous code, and you can end up with a deadlock in certain contexts, which is why going async all the way through the call stack is the rule that actually matters.