.NET Development and Framework

Modern .NET is a platform on a release rhythm — not the static framework that some teams still imagine when they hear the name. Once you accept the LTS-and-STS cadence, almost every architectural conversation inside a .NET shop changes. Lifecycle planning becomes a quarterly topic. Major version migrations become routine rather than projects. And the question stops being “which version are we on” and becomes “what is our story for the next two.”

A recurring theme in this collection is evolution over time. The runtime, the BCL, and the SDK each move on their own track, and the interesting work happens at the seams. Dynamic PGO, tiered compilation, and the steady improvements to the JIT have changed what performance-sensitive code looks like — patterns that were defensible in .NET Framework era are now actively slower than the idiomatic version. Articles trace these shifts release by release rather than treating any single version as the canonical reference.

The BCL has been quietly transformed by additions like SearchValues<T>, FrozenDictionary, Span<T>, Memory<T>, and the surrounding ecosystem of ref struct types. These are not niche features — they are the new defaults for anyone writing hot-path code. Articles cover when reaching for them pays back, when the older API is still the right answer, and the surprising corners where they interact badly with closures, async, or older library boundaries.

SDK ergonomics deserve their own attention. Central Package Management, project-level PackageReference graphs, source generators, AOT, and the slow but real maturing of the workload model all shape what a maintainable solution looks like. Articles cover the project-system trade-offs that compound silently across a multi-year codebase.

The LTS/STS rhythm itself is treated as a planning concern. Articles cover how to schedule upgrades against a real release window, when to skip an STS release, and how to keep the upgrade muscle exercised so that the next migration is not the one that breaks things.

My Analyzer Shipped Without Checking Its Own Source

My Analyzer Shipped Without Checking Its Own Source

NetEvolve.Analyzer enforces null-check idioms and file organization on other people’s code, but had never run against its own. Fixing that surfaced 39 warnings, a silent Visual Studio MEF failure, and a follow-up NE0008 bug where DateOnly and TimeOnly got flagged blind to which target framework actually has them, the same multi-targeting blindness in a different corner of the codebase.
Cyber Resilience Act for .NET Library Authors: Read the Fine Print

Cyber Resilience Act for .NET Library Authors: Read the Fine Print

The EU Cyber Resilience Act’s headline deadline is December 2027, but the reporting clock starts more than a year earlier. Article 14 vulnerability reporting applies from September 2026. Here is the engineering map I built for my own NuGet release pipeline: what the CRA regulates, the 24/72-hour cadence, SBOM tooling for .NET, and where the open-source carve-out holds.
Incremental Source Generators Done Right: Ship It Without Breaking Consumers

Packaging Generators

Parts 1 through 3 of this series made the generator correct, incremental, and proven by tests. None of it reaches a single consumer if the NuGet package is laid out wrong — and the failure modes are silent: a DLL in lib/ instead of analyzers/dotnet/cs simply never loads, a missing dependency throws only inside the compiler, and a marker attribute delivered carelessly breaks InternalsVisibleTo in ways users cannot diagnose. This final part covers the packaging contract: the netstandard2.0 rule, the package layout, dependency bundling, attribute delivery, debugging the shipped bits, and the analyzer hygiene rules that keep you honest.
Incremental Source Generators Done Right: Prove the Cache Hits

Prove the Cache Hits

You followed the equality rules, you shaped the pipeline correctly, and your generator still might be re-running on every keystroke — because nobody ever asked the driver. Roslyn records exactly why each pipeline step re-executed, and you can assert against those reasons in a plain xUnit test. This is the test that turns “my generator is incremental” from a claim into a regression-protected fact, plus the catalog of anti-patterns it catches in the wild.
Incremental Source Generators Done Right: Pipeline Patterns That Scale

Pipeline Patterns

Part 1 of this series established the equality contract: every value flowing through an incremental generator pipeline must be comparable by value, or the cache misses and the generator re-runs on every keystroke. This part is about the pipeline itself — ForAttributeWithMetadataName as the entry point, where to filter, where to transform, how to combine providers without accidentally subscribing to the entire Compilation, and the Collect trap that silently breaks everything you fixed in part 1. It ends with a complete worked generator you can steal.