Skip to main content

Posts

C# 15 Union Types: Examples, Exhaustive Switch and Gotchas

Last updated: October 22, 2026 · Tested with .NET 11 RC2 (SDK 11.0.100-rc.2.26504.105, C# 15) and the .NET 10.0.12 runtime Short answer: C# 15 adds union types . You declare one with the union keyword and a list of case types. Any value of a case type converts to the union implicitly, and a switch expression over the union is checked for exhaustiveness: no _ => arm needed, and you get a warning if you forget a case. public record class Cat(string Name); public record class Dog(string Name); public record class Bird(string Name); public union Pet(Cat, Dog, Bird); // 1. Basics: implicit conversion and an exhaustive switch Pet pet = new Dog("Rex"); Console.WriteLine($"1. {Describe(pet)}"); static string Describe(Pet pet) => pet switch { Dog d => $"dog {d.Name}", Cat c => $"cat {c.Name}", Bird b => $"bird {b.Name}", }; That's the feature most C# developers have asked for under the name "disc...

Moq in C# Tutorial: Setup, Verify and Common Errors

Last updated: October 19, 2026 · Tested with Moq 4.21.0 and 4.20.72, xUnit 2.9.3, .NET 10 (SDK 10.0.401, runtime 10.0.12), Windows 11 Short answer: Create a mock with new Mock<IMyService>() , tell it what to return with Setup(...).Returns(...) (or ReturnsAsync for async methods), pass mock.Object into the class you test, and check the calls afterwards with Verify(..., Times.Once) . Below is a complete xUnit test suite I ran on Moq 4.21.0, the first Moq release in two years (September 24, 2026), plus the exact exception text for the ten mistakes people hit most. Things I found while testing: Upgrading to Moq 4.21.0 added a compiler warning (CS8602) to the usual ILogger verify code. With warnings as errors, the build fails. On 4.20.72 the same code had 0 warnings. You can't set up or verify logger.LogInformation(...) . It's an extension method, so you verify Log(...) instead. An async method you didn't set up doesn't return null . It returns a completed...

IExceptionHandler in ASP.NET Core: Global Error Handling

Last updated: October 18, 2026 · Tested with .NET 10 (SDK 10.0.401, ASP.NET Core 10.0.12), compared with ASP.NET Core 9.0.14, Windows 11 Short answer: Implement IExceptionHandler , register it with builder.Services.AddExceptionHandler<T>() , add builder.Services.AddProblemDetails() and call app.UseExceptionHandler() . Handlers run in registration order until one returns true , so put the catch-all last. I built three handlers (validation → 400, not found → 404, everything else → 500) on .NET 10 and tested them with curl. Four results you should know before you ship: Registering the global handler first turned every 404 into a 500. Browser requests ( Accept: text/html ) got an empty 500 until I added a fallback. The developer exception page never showed. .NET 10 stopped logging exceptions your handler handles ; .NET 9 logged them.

System.Text.Json vs Newtonsoft: .NET 10 Migration Gotchas

Last updated: October 8, 2026 · Tested with .NET 10 (SDK 10.0.401, runtime 10.0.12), Newtonsoft.Json 13.0.4, BenchmarkDotNet 0.15.8, Windows 11 Short answer: on .NET 10, use System.Text.Json for new code and for most migrations. It ships with the runtime, it is what ASP.NET Core uses by default, and in my benchmark it serialized a 20-line order about twice as fast as Newtonsoft.Json with a quarter of the allocations. Keep Newtonsoft.Json where you depend on its leniency: input with comments or non-ISO dates you can't change, JObject / dynamic -heavy code, existing TypeNameHandling payloads, or dictionaries keyed by custom types. Most migration bugs come from different defaults, not missing features. Below is every difference I hit, with the exact exception messages from real runs.

HttpClient in .NET 10: IHttpClientFactory, Timeouts, Retries

Last updated: October 8, 2026 · Tested with .NET 10 (SDK 10.0.401, runtime 10.0.12), Microsoft.Extensions.Http.Resilience 10.10.0 (Polly.Core 8.4.2), Windows 11 Short answer: don't create a new HttpClient() per request. Get clients from IHttpClientFactory ( AddHttpClient , named or typed), or keep one static HttpClient on a long-lived SocketsHttpHandler with PooledConnectionLifetime set so DNS changes are picked up. For retries and timeouts add AddStandardResilienceHandler() from Microsoft.Extensions.Http.Resilience and let it own the timeouts. Below is what I measured against a local Kestrel test server: 2,000 sockets left in TIME_WAIT by the per-request pattern, the exact timeout exceptions, real retry logs, a measured Retry-After delay, and one surprise: the standard handler silently replaces your HttpClient.Timeout .

CSharpier vs dotnet format: C# Code Formatting on .NET 10

Last updated: October 5, 2026 · Tested with CSharpier 1.3.0 (dotnet tool and CSharpier.MSBuild), dotnet format from SDK 10.0.401, Windows 11 Short answer: CSharpier is an opinionated formatter: it rewraps long lines, sorts usings and gives every file the same layout, with almost nothing to configure. dotnet format ships with the SDK and fixes spacing, indentation and code-style rules from .editorconfig , but it never wraps a long line. Use CSharpier for layout and keep dotnet format style and analyzers for code rules. Don't run dotnet format whitespace on top of CSharpier: with a common .editorconfig setting the two tools undo each other and your CI check fails either way. Below are the real before/after files, timings on 3,050 files, and the setup that worked.

Compile C# at Runtime in .NET: CSharpCodeProvider to Roslyn

Last updated: October 5, 2026 · Tested with .NET 10 (SDK 10.0.401, runtime 10.0.12), Microsoft.CodeAnalysis.CSharp 5.9.0, System.CodeDom 10.0.12, Windows 11 Short answer: CSharpCodeProvider cannot compile code on .NET Core or .NET 5+. Without the System.CodeDom package the code doesn't build (CS1069), and with it, CompileAssemblyFromSource throws PlatformNotSupportedException at runtime. The replacement is Roslyn: add Microsoft.CodeAnalysis.CSharp , build a CSharpCompilation , Emit it to a MemoryStream and load the bytes. Below is the working version on .NET 10, plus the four things that broke when I tried it: the reference list from most older examples fails with CS0012, compiled assemblies never unload unless you use a collectible AssemblyLoadContext , single-file publishing breaks references, and a CancellationToken does not stop code that never returns.

C# for Unity: Beginner to Advanced Guide (2026)

Learn C# for Unity from beginner to advanced in 2026 — MonoBehaviour lifecycle, coroutines, async, performance and DOTS. Start building games today. If you want to build games in 2026, learning C# for Unity is still the single highest-leverage skill you can pick up. Unity ships with C# as its only first-class scripting language, and the version of C# you write inside the editor today is a modern, fast, fully-featured language — not the cut-down dialect people remember from a decade ago. This guide walks you from your very first MonoBehaviour to advanced topics like the Job System, object pooling and allocation-free game loops, with runnable code you can paste straight into a project. Why C# for Unity Is Different From "Normal" C# Everything you know about .NET still applies — LINQ, generics, async , pattern matching, records. But Unity adds a layer on top that trips up almost every newcomer, and understanding it early will save you weeks. You don't own the ...

API Security Best Practices 2026: Secure REST APIs in C#

Learn API security best practices for 2026 with runnable C# and ASP.NET Core examples — JWT, rate limiting, BOLA fixes. Start hardening your REST API today. If you ship a REST API in 2026, you are running a public attack surface. Attackers no longer bother with your UI — they read your OpenAPI document, enumerate your endpoints, and hammer them directly. This guide covers the API security best practices that actually matter today, with runnable C# and ASP.NET Core examples you can drop into a real project. We will focus on the failures that show up in genuine breach reports: broken object-level authorization, weak token validation, missing rate limits, and secrets sitting in source control. Every example targets ASP.NET Core on .NET 8 or later, and each one explains why the control exists — because a security rule you do not understand is a security rule you will disable the first time it breaks a deployment. Why REST API Security Fails: The OWASP API Security Top 10 The OW...

Serilog .NET Tutorial: Structured Logging Best Practices

Learn Serilog structured logging in .NET with runnable C# examples, sinks, enrichers, and production best practices. Start logging smarter today. If you have ever opened a 400 MB text log file at 2 a.m. trying to figure out why one customer's checkout failed, you already understand why Serilog .NET exists. Traditional logging writes sentences. Serilog writes data. That single difference — structured logging instead of string concatenation — is what turns your logs from a wall of text into a queryable database of everything your application did in production. In this tutorial you will learn how to set up Serilog in a .NET 8/9 application, configure sinks and enrichers, use scopes and correlation IDs, and apply the production best practices that separate a hobby project from a system you can actually operate. Every example is runnable. What Is Structured Logging (and Why String Logs Fail) Consider the classic approach: // The old way — information is destroyed at write ti...