{"id":3979,"date":"2026-09-29T07:33:44","date_gmt":"2026-09-29T04:33:44","guid":{"rendered":"https:\/\/inferne.com\/blog\/dotnet-development\/"},"modified":"2026-09-29T14:53:55","modified_gmt":"2026-09-29T11:53:55","slug":"dotnet-development","status":"publish","type":"post","link":"https:\/\/inferne.com\/blog\/dotnet-development\/","title":{"rendered":".NET Development: APIs, Blazor and Cloud Apps on Modern .NET"},"content":{"rendered":"<p>Teams usually come to us for .NET development with a clear goal: an API or web platform that&#8217;s fast, strongly typed, easy to operate and built to last. Often there&#8217;s a constraint as well, like an existing C# team, a Microsoft-centered organization, or a .NET Framework system that the new platform will eventually have to replace.<\/p>\n<p>A well-built .NET service starts quickly and uses resources efficiently, deploys the same way every time, and reports what it&#8217;s doing through logs, metrics and traces. Modern .NET, the open-source, cross-platform successor to the .NET Framework, does all of that well if you use it deliberately.<\/p>\n<h2>What we build with .NET<\/h2>\n<ul>\n<li>High-throughput APIs for mobile apps, partner integrations and single-page front ends<\/li>\n<li>Line-of-business platforms with complex rules, such as finance, legal, healthcare and logistics workflows<\/li>\n<li>Background processing: imports, reconciliation, notifications, scheduled jobs and message consumers<\/li>\n<li>Real-time features with SignalR, like live dashboards and in-app notifications<\/li>\n<li>Internal tools and admin portals, sometimes in Blazor<\/li>\n<li>Replacements for .NET Framework systems (our <a href=\"\/blog\/asp-net-development\/\">ASP.NET development<\/a> article walks through that path step by step)<\/li>\n<\/ul>\n<h2>How we approach .NET development<\/h2>\n<p>Discovery starts with the shape of the load and the integrations: who calls the system and how often, which operations must be strictly consistent, and which can be eventually consistent. Our business analysts write those rules down as acceptance criteria before any code exists, because in line-of-business software the rules are most of the product.<\/p>\n<p>Then comes design. Our default is a modular monolith, meaning one deployable application with clearly separated modules and explicit contracts between them. We only split out separate services for a concrete reason, such as independent scaling, a separate team or a different release cadence. A modular monolith is cheaper to run and easier to debug, and if the boundaries were drawn well, it can still be split later.<\/p>\n<p>During the build, the compiler takes on part of QA&#8217;s job. Nullable reference types are enabled, warnings fail the build, and analyzers run in CI. Our QA testers own the regression suite that runs through whole user flows. Releases go through automated pipelines with health checks, and we keep a close eye on traces and error rates after each one.<\/p>\n<h2>Stack and architecture choices<\/h2>\n<h3>APIs<\/h3>\n<p>ASP.NET Core gives you two styles. Controllers suit large APIs with shared conventions and filters, while minimal APIs are lighter and now cover most needs. We pick one per project and stick with it. A lot of what used to need a library is now built in, including OpenAPI document generation, rate limiting, output caching, health checks and standard problem-details error responses.<\/p>\n<h3>Data<\/h3>\n<p>Entity Framework Core is our default, and keeping it fast is mostly a matter of habits: no-tracking queries for reads, projections instead of whole entities, split queries where joins multiply rows, and set-based bulk updates and deletes. Hot paths with complex SQL get Dapper alongside it. SQL Server and PostgreSQL are both first-class options, and which one fits depends on your hosting, your licensing and your team.<\/p>\n<h3>Identity and security<\/h3>\n<p>When you manage users yourself, accounts go through ASP.NET Core Identity. For staff and business customers, we use an OpenID Connect provider such as Microsoft Entra ID. Secrets live in a vault, never in configuration files in the repository. Data protection keys are persisted and shared across instances, so sign-in cookies and anti-forgery tokens keep working after restarts and when the app scales out.<\/p>\n<h3>Background work and dependencies<\/h3>\n<p>Simple background loops run as hosted services. Durable scheduled jobs go to a proven scheduler like Hangfire or Quartz.NET, and services talk to each other through a message broker with retries and dead-letter queues. We also check the license of every dependency. Some popular .NET libraries, MediatR and AutoMapper among them, now require a commercial license for many business uses, and that cost belongs in the budget conversation.<\/p>\n<h3>Cloud and hosting<\/h3>\n<p>Because modern .NET runs on Linux and in containers, you have a real choice of hosting: Azure App Service or Container Apps, AWS, Kubernetes, or plain virtual machines. If you&#8217;re on Azure, Microsoft Entra ID, Key Vault and managed identities fit together especially well. Native ahead-of-time compilation can cut startup time and memory for small services and functions. It also rules out reflection-heavy libraries and some framework features, MVC controllers included, so we only use it where cold starts matter.<\/p>\n<h2>Blazor: where it fits and where it does not<\/h2>\n<p>Blazor lets you build interactive web UI in C#. A page can be rendered statically on the server, made interactive on the server over a persistent SignalR connection, or run in the browser on WebAssembly. It can also start on the server and switch to WebAssembly on later visits. None of these modes is free:<\/p>\n<figure class=\"wp-block-image size-large\"><img width=\"900\" height=\"600\" src=\"https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-blazor-900x600.webp\" class=\"attachment-large size-large\" alt=\"Four server-to-browser pairs for Blazor&#039;s render modes: static page, live connection, WebAssembly download, and both.\" loading=\"lazy\" sizes=\"auto, (max-width: 760px) 100vw, 720px\" decoding=\"async\" srcset=\"https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-blazor-900x600.webp 900w, https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-blazor-510x340.webp 510w, https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-blazor-768x512.webp 768w, https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-blazor.webp 1400w\" \/><\/figure>\n<ul>\n<li>Interactive server mode keeps state on the server for every connected user and needs a stable connection. On a good network it feels instant, and on a poor mobile one it&#8217;s fragile.<\/li>\n<li>WebAssembly downloads the .NET runtime and your code before the page becomes interactive, which is a noticeable first-load cost for public sites.<\/li>\n<li>The pool of third-party components and experienced developers is smaller than what React or Angular have.<\/li>\n<\/ul>\n<p>Where we land: Blazor is an excellent choice for internal tools, admin panels and line-of-business apps built by a C# team, because one language across the stack pays off there. For public, mobile-heavy or SEO-critical products, we usually pair a .NET API with a JavaScript front end instead. Our <a href=\"\/blog\/frontend-development\/\">frontend development<\/a> article covers that approach.<\/p>\n<h2>Performance and quality<\/h2>\n<p>.NET is fast by default, and that makes it easy to waste. The problems we fix most often have nothing to do with the runtime. They&#8217;re blocking calls inside async code that starve the thread pool, chatty database access, missing caching and large allocations on every request. We measure before changing anything: OpenTelemetry traces in production, dotnet-counters and dotnet-trace for live diagnostics, and BenchmarkDotNet for the rare hot path that deserves micro-optimization.<\/p>\n<figure class=\"wp-block-image size-large\"><img width=\"900\" height=\"600\" src=\"https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-testing-900x600.webp\" class=\"attachment-large size-large\" alt=\"A test pyramid of unit cells, a containerized database and a browser on top, beside a caliper measuring bars.\" loading=\"lazy\" sizes=\"auto, (max-width: 760px) 100vw, 720px\" decoding=\"async\" srcset=\"https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-testing-900x600.webp 900w, https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-testing-510x340.webp 510w, https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-testing-768x512.webp 768w, https:\/\/inferne.com\/blog\/wp-content\/uploads\/2026\/09\/dotnet-development-testing.webp 1400w\" \/><\/figure>\n<p>Tests come in layers. Unit tests cover domain rules. Integration tests run the real HTTP pipeline in memory against a real database, started in a container with Testcontainers, so what passes in CI behaves the same way in production. Playwright tests walk through the critical user journeys in a real browser, and for any interface we ship, accessibility checks for semantic markup, keyboard navigation and screen readers are part of the definition of done. Security reviews focus on per-resource authorization, secrets management and vulnerable packages, which the .NET tooling flags during restore.<\/p>\n<h2>When .NET is the right platform, and when it is not<\/h2>\n<p>.NET is a strong choice when you need high throughput on modest hardware, when the system is long-lived and full of business rules, when you have a C# team or hiring market, or when you rely on Microsoft identity, SQL Server, Azure and Office tooling. Microsoft ships a new release every November and every other release gets long-term support, so upgrades follow a predictable rhythm.<\/p>\n<p>It&#8217;s less compelling in a few situations. A team that writes TypeScript everywhere can keep one language across front end and back end with <a href=\"\/blog\/nodejs-development\/\">Node.js<\/a>. Data science and machine learning work belongs in Python, even when a .NET service is the one calling it. A marketing site or content platform is faster to deliver on a CMS. And for consumer mobile apps we usually recommend native or <a href=\"\/blog\/react-native-app-development\/\">React Native<\/a> over .NET MAUI, which fits best when a .NET team is building internal apps.<\/p>\n<h2>How an engagement works<\/h2>\n<p>A new platform gets a dedicated product team: a business analyst, a product designer if the system has user-facing UI, .NET engineers and a QA tester. Work is planned in iterations that each end with a demo. Modernization work starts differently, with a focused assessment and a phased plan. In both cases the code lives in your repository from the first commit, and you also get infrastructure defined as code, runbooks for operating the system, and regular written reports on progress, risks and decisions.<\/p>\n<h2>Frequently asked questions<\/h2>\n<h3>Is .NET only for Windows and Azure?<\/h3>\n<p>No. Modern .NET is open source and runs on Linux, macOS and Windows, in containers and on any major cloud. The Azure integration is excellent, but you don&#8217;t need it.<\/p>\n<h3>Should we use minimal APIs or controllers?<\/h3>\n<p>Either works for most projects. We lean toward controllers for large APIs with many shared conventions and toward minimal APIs for smaller, focused services. Within one codebase, we pick a style and stay consistent.<\/p>\n<h3>Is Blazor ready for production?<\/h3>\n<p>Yes, and it suits internal and line-of-business apps built by C# teams. For a public-facing product, weigh its first-load and connection trade-offs against a JavaScript front end first.<\/p>\n<h3>How often do we need to upgrade .NET?<\/h3>\n<p>Plan to move from one long-term support release to the next. The support windows overlap, so you have time to upgrade calmly, and staying current keeps each upgrade small.<\/p>\n<h3>Can you work with our in-house .NET team?<\/h3>\n<p>Yes. We can take full ownership of a module, pair with your developers, or handle a focused piece like performance work or a migration, with shared code review and conventions.<\/p>\n<p>We&#8217;re happy to talk before you&#8217;ve settled on .NET. <a href=\"https:\/\/inferne.com\/#contact\">Write to us about the expected load, the integrations and your team<\/a>, and we&#8217;ll suggest where to start, whichever platform that points to.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Modern .NET for APIs, web apps and cloud services: where it shines, where Blazor fits and where it does not, and how we build fast, observable C# systems.<\/p>\n","protected":false},"author":4,"featured_media":3980,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[312],"tags":[379,344,381,380,345],"class_list":["post-3979","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web","tag-net","tag-asp-net-core","tag-azure","tag-blazor","tag-c"],"_links":{"self":[{"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/posts\/3979","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/comments?post=3979"}],"version-history":[{"count":3,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/posts\/3979\/revisions"}],"predecessor-version":[{"id":4133,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/posts\/3979\/revisions\/4133"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/media\/3980"}],"wp:attachment":[{"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/media?parent=3979"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/categories?post=3979"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/inferne.com\/blog\/wp-json\/wp\/v2\/tags?post=3979"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}