C# & .NET
Build modern C# applications with .NET - ASP.NET Core minimal APIs, Entity Framework Core, LINQ, async/await, and C# 12 features.
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
- 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.
- Use Entity Framework CoreEF Core provides LINQ-based ORM with code-first migrations. Models defined as C# classes generate database schemas automatically.
- Query with LINQLINQ (Language Integrated Query) enables type-safe database queries written as C# expressions - compiled and validated at build time.
- Apply modern C# featuresC# 12 (with .NET 8/9) adds primary constructors, collection expressions, required properties, and pattern matching improvements - reducing boilerplate significantly.
- 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/