Backend5 min read

C# & .NET

Build modern C# applications with .NET - ASP.NET Core minimal APIs, Entity Framework Core, LINQ, async/await, and C# 12 features.

C#.NETASP.NET CoreEntity FrameworkLINQ

skill: C# & .NET category: Backend tags: [C#, .NET, ASP.NET Core, Entity Framework, LINQ] readingTime: 5

.NET 9 and C# 12 have transformed .NET from a Windows-only enterprise platform to a cross-platform, high-performance runtime. ASP.NET Core consistently ranks among the fastest web frameworks in TechEmpower benchmarks. C#'s type system (nullable reference types, records, pattern matching) prevents many common bugs.

Workflow

  1. Build APIs with ASP.NET Core Minimal APIsMinimal APIs (introduced in .NET 6) reduce boilerplate vs. controllers. Route handlers are lambda functions; request/response types are automatically serialized.
  2. Use Entity Framework CoreEF Core provides LINQ-based ORM with code-first migrations. Models defined as C# classes generate database schemas automatically.
  3. Query with LINQLINQ (Language Integrated Query) enables type-safe database queries written as C# expressions - compiled and validated at build time.
  4. Apply modern C# featuresC# 12 (with .NET 8/9) adds primary constructors, collection expressions, required properties, and pattern matching improvements - reducing boilerplate significantly.
  5. Test with xUnit and MoqxUnit is the standard .NET testing framework. Moq generates mocks for interfaces, enabling unit tests without real infrastructure.

Output Format

.NET: minimal API MapGroup + TypedResults, EF Core DbContext + LINQ .Where().Select().ToListAsync(), C# 12 records + primary constructors, and xUnit with Moq + FluentAssertions.

app.MapGroup("/api/users").MapGet("/", async (IRepo repo) => await repo.GetAll())
DbSet<User> + LINQ: .Where().OrderBy().AsNoTracking().ToListAsync()
public record CreateUserRequest(string Email, string Name)
public class Service(IRepo repo) - primary constructor
_repoMock.Setup(r => r.GetById(id)).ReturnsAsync(user)

Examples

Input

Output

Edge Cases & Gotchas

  • EF Core change tracking overhead - By default, EF Core tracks all loaded entities for change detection. Use .AsNoTracking() on all read-only queries to skip tracking and improve performance by 10-50%.
  • async void vs. async Task - Never write async void methods (except event handlers) - exceptions from async void cannot be caught and will crash the process. Always return Task or Task<T>.
  • Dependency injection scopes - .NET DI has three lifetimes: Transient (new per injection), Scoped (per HTTP request), Singleton (app lifetime). Never inject a scoped service into a singleton - creates captured dependency bugs.
  • EF Core migration conflicts - Multiple developers adding migrations simultaneously create merge conflicts in the migrations snapshot. Establish a convention: one migration per PR, applied to main before creating the next.

When to Break These Rules

  • Use Python or Node.js instead of .NET for data science applications, ML pipelines, or teams with no .NET experience - the ecosystem matters more than language performance for most web applications.
  • Use .NET Blazor instead of React/Vue for .NET shops - Blazor WebAssembly enables C# in the browser, keeping the same language across the stack for teams with strong C# expertise.

Reference Files

  • https://learn.microsoft.com/en-us/aspnet/core/
  • https://learn.microsoft.com/en-us/ef/core/

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.