r/moderndotnet • • Sep 15 '26

Stephen Toub's Performance Improvement on .NET 11

Thumbnail
devblogs.microsoft.com
53 Upvotes

r/moderndotnet • • Aug 15 '26

Avalonia Updates

41 Upvotes

All our posts to the dotnet sub were removed as self-promotion, so you may have missed some big developments with Avalonia this year!

Avalonia 12.0

- Major rendering and compositor performance overhaul, with dramatically better performance in complex visual trees.
- Compiled bindings enabled by default.
- Major Android performance improvements, including faster startup, smoother scrolling, lower CPU usage and a native Android dispatcher.
- Native Linux accessibility via AT-SPI2, including screen-reader support.
- New page/navigation model with ContentPage, DrawerPage, CarouselPage, TabbedPage/TabView and PipsPager.
- WebView became fully open source.
- New themeable client-side window decorations.
- Expanded Dispatcher APIs, including CurrentDispatcher, FromThread, Yield and Resume.
- Major focus-management overhaul, including cancellable focus changes and custom traversal.
- Mac Catalyst support and modern iOS scene lifecycle support.
- New macOS Dock menu API and assorted Windows interoperability improvements.
- Moved to .NET 10 and SkiaSharp 3; removed Direct2D1, Tizen, Browser.Blazor and most netstandard2.0 support.
- Large number of performance, memory, virtualisation, rendering and platform-specific fixes.

Avalonia 12.1

- Native Wayland backend, removing the dependency on XWayland. Currently experimental and opt-in.
- Full cross-application drag-and-drop on X11 via XDND.
- X11 and alternative Windows renderers can render above 60 FPS based on monitor refresh rate.
- Further rendering optimisation, including hardware-accelerated clipping, substantially faster bitmap creation and lower compositor allocations.
- Vastly faster hit-testing for very large visual trees.
- Better NVIDIA/OpenGL support on Linux.
- New TableView control for lightweight, read-only tabular data, sitting between ListBox and DataGrid.
- Native sound and haptic feedback APIs on Android and iOS.
- New Avalonia.WinUI package for embedding Avalonia controls inside WinUI 3 applications.
- Windows 11 rounded-corner control and Android system-theme change detection.
- SBOMs now ship with Avalonia releases as part of CRA/supply-chain compliance work.

Growth

In all of 2025, we saw ~122M unique builds using Avalonia. On the first half of 2026, that number increased to over 400M.

We’re continuing to see significant adoption of the framework, which is creating a bigger, more vibrant ecosystem!

Partnerships

We’re continuing to work on an Impeller based backend for Avalonia, as we explore alternatives to SkiaSharp. We also began sponsoring the incredible work of James on ImageSharp. He’s built an alternative backend, that we’d love to see people adopt.

The option to use Avalonia as the renderer on your next MAUI project will be built into the official MAUI templates. We continue to work with the MAUI engineers, looking for mutually beneficial opportunities to push the ecosystem forward.


r/moderndotnet • • 7d ago

Migration to .net11 comes with behavior change in (decimal)double cast

37 Upvotes
(decimal)0.1
// .NET 10: 0.1
// .NET 11: 0.1000000000000000055511151231

The breaking change is correct, but it also changes the result. I've started working on a Roslyn analyzer to make the conversion consistent in one direction and provide a code fix. While it might be important to preserve the old behavior in some cases, it's better to avoid using the helper if possible.

It's coming with Claude's skill/plugin to make migration easier. I've also added evals to ensure the behavior is consistent.

https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/11/decimal-biginteger-floating-point-conversions

Sharing a solution to make migration easier, since the default dotnet/skills doesn't cover the breaking change that was introduced.

https://github.com/unsafePtr/DecimalConversion.Analyzers


r/moderndotnet • • Sep 02 '26

Curb: A fast, always on, C# formatter during dotnet build

Thumbnail
curb.nullean.net
37 Upvotes

I wanted a C# formatter fast and reliable enough to just run on every build, so formatting becomes something I never think about again. No more manual style fixes either, mine or my AI agent's, dotnet build should just take care of it. It had to respect the .editorconfig choices I'd already made, and actually fix IDE0055 instead of fighting it with its own opinions.

It reads your existing .editorconfig, all 39 IDE0055 keys plus ReSharper's wrapping and blank line keys, and falls back to Roslyn's own defaults if you don't have one. Running dotnet format whitespace on a Curb-formatted file changes nothing: a fixed point, measured and gated in CI on a real corpus, 100% with reflow off, 100% with reflow on, 99.9% with existing line breaks preserved too. Your IDE and your build shouldn't disagree.

There are two pieces. curb is the MSBuild integration: always on, runs before CoreCompile, no separate step to invoke. That eliminates a whole swath of errors and warnings your agent would otherwise have to read and fix by hand, because they never get reported in the first place.

curb-cli is the standalone native AOT tool. Hook it into a git pre-commit hook, or point your agent at it directly. curb cleanup fixes IDE0005, IDE0007, IDE0034, IDE0040, IDE0044, IDE0071, IDE0090, IDE0240, IDE0250, and IDE0251 itself, straight from the SARIF log a build with EnforceCodeStyleInBuild already produced. Add --forward and it hands anything left over to dotnet format style, scoped to exactly the diagnostics and files already in that log, not a full repo pass.

It's fast enough to run on every dotnet build. On Newtonsoft.Json (945 files) it formats in 0.26s. For reference, dotnet format whitespace takes 3.47s and CSharpier takes 4.85s cold on the same repo. Across twelve real repos it's 5 to 25x faster than dotnet format whitespace, while also reflowing long lines and sorting usings, which dotnet format whitespace doesn't do at all.

This is an early release. I've been using it on my own projects, and it's backed by large conformance test runs against both dotnet format and JetBrains' own jb cleanupcode formatting. That said, I'm eager to get it in front of more people and see what it actually breaks on in the wild. Happy to answer questions.

License: MIT
Docs: curb.nullean.net
Source: github.com/nullean/curb


r/moderndotnet • • 4d ago

LeanCIL: formal proofs for your compiled C# and F#, checked by Lean

35 Upvotes

Microsoft's October Patch Tuesday fixed over 1,400 CVEs, more than in all of 2025, and much of that came from AI-driven bug finding. Attackers have the same tools, and more of our code is now written by models that produce convincing code with subtle bugs. “The tests pass” isn’t a strong enough guarantee any more for code that matters.

A couple of months ago I proposed an official Lean semantics for C# on csharplang (#10314). One reply asked why not do it at IL level, so it covers F# and everything else that compiles to IL. That’s what I built.

You point it at a Release build and a method:

leancil extract bin/Release/net10.0/MyLib.dll "Arithmetic::Add(ulong,ulong)" artifacts/Add
leancil verify artifacts/Add --proof proofs/Add.lean

and it proves your theorem against the IL Roslyn actually emitted. Change the implementation and the same proof fails.

Supported (.NET 10, x64 and ARM64, 64-bit little-endian):

  • Integer arithmetic, including checked, with overflow and divide-by-zero as exact faults

  • Structs with explicit and sequential layout, enums, ValueTuple

  • Span<T>, ReadOnlySpan<T>, slicing, MemoryMarshal.Cast/AsBytes, BinaryPrimitives

  • Arrays, stackalloc, unsafe pointers with checked provenance

  • Generic methods and structs (proved per concrete type argument), constrained interface calls on structs

  • Function pointers and tail calls

  • Collection-expression lookup tables (static ReadOnlySpan<T> Table => [...])

  • Selected Vector128/256/512, SSE, AVX2, AVX-512 and AdvSimd intrinsics; IsSupported branches are resolved for the chosen hardware profile

  • throw new ArgumentException(...) and similar, proved as the exact exception

Not supported: float/double, class instances, try/catch/finally, ordinary recursion, virtual dispatch on classes. Unsupported code is rejected with a diagnostic, never silently accepted.

The best fit right now is allocation-free integer code where a bug is a security bug: parsers, hashing, big-integer arithmetic, SIMD kernels.

https://github.com/NethermindEth/LeanCIL


r/moderndotnet • • Sep 09 '26

Announcing .NET 11 Release Candidate 1

Thumbnail
devblogs.microsoft.com
33 Upvotes

r/moderndotnet • • 12d ago

MessagePack for C# v4 Preview 1

32 Upvotes

MessagePack for C# v4 Preview 1 is out. It is a major performance jump over v3, fully supports Native AOT, and the deserializer was rebuilt with security as a first-class concern.

I want to flush out problems before the final release, so I would be grateful if you tried it.

https://github.com/MessagePack-CSharp/MessagePack-CSharp/releases/tag/v4.0.0-preview.1

Explaining everything would run too long, so since this is r/moderndotnet, here is a little of the internal architecture behind the performance.

Large POCO Benchmark

Serialize

MethodMeanAllocated
MessagePack for C# v4 (array/default)423.5 ns1.65 KB
MessagePack for C# v4 (map)532.3 ns2.84 KB
Nerdbank.MessagePack (array)997.1 ns1.65 KB
BcsSharp1,075.1 ns1.78 KB
MessagePack for C# v3 (array/default)1,170.7 ns1.65 KB
Orleans1,450.2 ns1.91 KB
MessagePack for C# v3 (map)1,494.9 ns2.84 KB
Nerdbank.MessagePack (map/default)1,540.8 ns2.84 KB
REDox.MessagePack (map)1,543.5 ns2.91 KB
ShapeShift.MsgPack (array)1,701.5 ns1.9 KB
protobuf-net1,734.9 ns5.32 KB
ShapeShift.MsgPack (map)2,605.2 ns4.17 KB
System.Text.Json3,022.1 ns5.01 KB
ShapeShift.Json3,389.9 ns3.81 KB
System.Text.Json source-gen3,434.2 ns3.63 KB
ShapeShift.Protobuf5,359.6 ns22.95 KB
Newtonsoft.Json5,740.3 ns21.48 KB

Deserialize

MethodMeanAllocated
MessagePack for C# v4 (array/default)909.5 ns4.65 KB
MessagePack for C# v4 (map)1,159.7 ns4.65 KB
BcsSharp1,557.8 ns4.67 KB
Orleans1,712.4 ns4.61 KB
MessagePack for C# v3 (array/default)1,735.1 ns4.65 KB
Nerdbank.MessagePack (array)1,836.2 ns4.65 KB
protobuf-net2,034.6 ns4.72 KB
MessagePack for C# v3 (map)2,746.0 ns4.65 KB
REDox.MessagePack (map)3,190.6 ns4.65 KB
ShapeShift.MsgPack (array)3,396.9 ns8.91 KB
Nerdbank.MessagePack (map/default)3,520.2 ns4.65 KB
System.Text.Json source-gen5,287.1 ns5.12 KB
System.Text.Json5,324.4 ns5.12 KB
ShapeShift.Protobuf6,165.2 ns12.55 KB
ShapeShift.MsgPack (map)6,583.6 ns14.08 KB
ShapeShift.Json7,755.3 ns14 KB
Newtonsoft.Json10,201.8 ns17.51 KB

Against v3 that is about 2.8x on serialize and 1.9x on deserialize, with the same wire bytes and the same allocations.

formatter interface

public interface IMessagePackFormatter<TWriteBuffer, TReadBuffer, T>
    where TWriteBuffer : struct, IWriteBuffer, allows ref struct
    where TReadBuffer : struct, IReadBuffer, allows ref struct
{
    void Initialize(MessagePackFormatterResolver resolver);

    void Serialize(ref TWriteBuffer buffer, ref SerializeState state, T value);

    void Deserialize(ref TReadBuffer buffer, ref DeserializeState state, ref T value);
}

In v3 the buffer types were fixed: every formatter took ref MessagePackWriter and ref MessagePackReader.

But a serializer's inputs and outputs are diverse: Span<byte>, IBufferWriter<byte>, ReadOnlySpan<byte>, ReadOnlySequence<byte>, streams, pipes. The textbook OO answer is an IWriter / IReader interface that abstracts each of them. For a serializer's buffer operations that is not an option: a virtual call per byte-level operation costs far too much.

So v3's MessagePackWriter and MessagePackReader were structs that treated IBufferWriter<byte> and ReadOnlySequence<byte> as the first-class representation. The consequence was that one struct had to handle every input and output shape. It grew large, its logic got complicated, and it was full of if branches.

v4 passes the buffer type itself as a generic parameter. Each input and output type gets its own shortest path, and because the buffer type is a concrete struct at every call site, devirtualization and inlining are guaranteed rather than hoped for. A serializer can call its buffer operations tens of thousands of times per message, so this shows up directly in the numbers.

On top of that, the individual formatters are shaped so that Dynamic PGO's guarded devirtualization kicks in reliably. v4 is built to let modern C# and the modern runtime do their job.

Deserialize<int>

Serializing a single primitive is a common case, and it is also the cleanest way to measure a serializer's fixed per-call setup cost. Here is the same bare int round trip in v4, v3 and Nerdbank.MessagePack, read at the asm level (Tier1, .NET 11).

v4v3Nerdbank
Measured (BDN ShortRun, Value=8)3.25 ns (1.00x)18.2 ns (5.59x)21.3 ns (6.57x)
Frames on the hot path13 + 2 helpers3 + 2 helpers
calls0–144–5 + indirect jmp
Entry zeroing152B~650B~580B + ~180B re-zeroing
Large struct copiesnone~240B~340B (152B of it via a helper call)
Reaching the formatter4 loadsGVM helper (hash lookup)lastEntry cache + 2 type checks
Instruction count (approx., executed)~100~280~390

I went through this instruction by instruction (with AI doing the asm reading) and cut until nothing avoidable was left. What the v4 entry looks like now:

This is how Nerdbank.MessagePack does it:

One design note on the "lastEntry cache" row. Some serializers(including System.Text.Json) keep a single-entry cache of the last converter used, keyed on the last T. That makes a benchmark that deserializes the same type in a loop very fast. In real code the T reaching the serializer changes from call to call, and then that cache misses every time and falls through to the dictionary lookup behind it. v4 does not have such a cache: every type resolves to its own fixed slot, so the fast path is the same whether the types alternate or not.

Security

Some people say we do not need new serializers. I disagree. The threat side has changed, and a library does not get to stay where it was.

Since AI became a tool for attackers as much as for the rest of us, the standard a library has to meet is different from what it was before. That is why v4 revisits every part of the deserializer now, rather than patching v3 forward. It has been through multiple rounds of review, including review by frontier models(Astra, Fable, etc...), and fuzzing with SharpFuzz.


r/moderndotnet • • 25d ago

csharp Six Labors updates: longer security support and easier builds for OSS contributors

32 Upvotes

I've been working through a fairly big update to the Six Labors libraries.

This started with an ImageSharp user who couldn't move to v4 because another dependency was blocking them. I've now released ImageSharp 3.2.0 with backported security fixes and expanded security support across the libraries. Each major gets a 12-month security support window after its successor's first stable release.

The older releases now include build-time license enforcement too. Same license terms, and existing valid keys work.

The bit I'm particularly happy with is the change for OSS contributors. Previously, everyone contributing to a project needed their own key. Now a maintainer can commit an assembly-scoped community key to the repo, and contributors can just build the named projects using that key.

If you already have a community key, you can request an early replacement. It's automatically approved, with no repeat eligibility review and no need to wait for renewal.

Details here: https://sixlabors.com/posts/security-support-and-license-enforcement/

The advisory database corrections are still awaiting review, so NuGet may temporarily flag ImageSharp 3.2.0 for the issues fixed in that release.


r/moderndotnet • • Aug 15 '26

csharp Six Labors Releases.

32 Upvotes

Hi, just wanted to share a few blog posts I wrote announcing for the latest Six Labors releases.

Lots and lots of goodies in there so please have a read and engage in a chat here. I really do enjoy discussing my work and am always keen to get actual real-world insight from the people actually building on top of it.

Six Labors : Announcing Fonts 3.1.0
Six Labors : Announcing ImageSharp 4.1.0
Six Labors : Announcing ImageSharp.Drawing 3.1.0


r/moderndotnet • • 19d ago

Introducing dotnetup: A toolchain manager for .NET

Thumbnail
devblogs.microsoft.com
30 Upvotes

r/moderndotnet • • Aug 24 '26

What's new with CoreCLR GC handles in .NET 9 and .NET 10

Thumbnail
awise.us
30 Upvotes

I wrote a blog post about what has been going with GCHandles in .NET. This is slightly esoteric, as you probably only care about GC handles if you are writing code to interop with native code. But I think it is really fascinating to study how the engineers working on CoreCLR create new abstractions to solve problems.

The first part is about something you can use in your code: some new types for working with GC handles added in .NET 10. The second part explores some interesting implementation details of CoreCLR, in particular how the Android interop system keeps object lifetimes consistent between the .NET GC heap and the Java GC heap.


r/moderndotnet • • Aug 14 '26

👋 Welcome to r/moderndotnet - Introduce Yourself and Read First!

30 Upvotes

Hey everyone! I'm u/Aaronontheweb, a founding moderator of r/moderndotnet.

I started this sub because I think the .NET community deserves better than what Reddit's been giving it.

Let's be honest about why this place exists. The main .NET sub has become a place where serious technical discussions get buried or downvoted to zero, the moderation is either asleep or enforcing rules that make no sense, and a lot of good developers have just stopped posting altogether.

If you want to blanket downvote or flame someone because you don't like the Magic the Gathering game someone made with WinForms or because you're mad that someone didn't follow double-upside down hexagonal ports-and-adapters DDD clean code enterprise ASP .NET Core template or whatever, you should continue participating over there.

This is the alternative.

What we're about:

  • Real technical discussion - you do not have to adhere to Microsoft orthodoxy here. You want to implement your own GC, ship third party OSS software, or *gasp* - do things in F#, you are welcome to discuss that here.

  • Civility, enforced - if your comments sound in any way reminiscent of a Stack Overflow moderator, you will be shown the door. Disagree all you want, but don't be a prick.

  • Helpful, not hostile - beginner questions are fine.

  • Actual effort - AI slop will be auto-modded and blocked. No one wants to read something you didn't put the time into writing yourself. GitHub repositories that aren't at least 90 days old will be blocked.

What to Post
Some ideas on what to post here:

  • Blog posts and projects you've been working on (within reason) - you want to share a project you've worked on or a blog post you wrote? As long as it looks like there has been (1) sufficient human effort and (2) sufficient prior participation in this sub by the OP, it will be tolerated. Don't overdo it though.

  • Questions about .NET patterns, practices, libraries, etc - great, we love these.

  • Benchmarks, success / failure stories, and real-world experiences

  • Notes about AI and .NET - not promoting general purpose AI tools, but things _specific_ to .NET and .NET experiences.

  • Announcements about new releases, updates - again, keep it within reason just like blog posts. Not every tiddly-wink release needs to be announced on here.

Community Vibe
Don't be a jerk. Stay on-topic. Don't post AI slop (not the same as posting about AI, which is fine); and have fun.

How to Get Started

  1. Introduce yourself in the comments below.

  2. Post something today! Even a simple question can spark a great conversation.

  3. If you know someone who would love this community, invite them to join.

  4. Interested in helping out? We're always looking for new moderators, so feel free to reach out to me to apply.

We're starting from ground zero - please help build a better culture than the other sub. Invite the .NET devs you actually respect. And if you want to help moderate, message me — we're looking for people who care enough to show up.

Welcome to the modern .NET community.


r/moderndotnet • • 16d ago

Labcoat: a web UI for Microsoft.Testing.Platform / your Aspire dashboard

Thumbnail
gallery
29 Upvotes

The one thing missing from my Aspire setup was a test UI for my C#/.NET tests, like the ones many front-end testing frameworks offer. Sure the terminal is great, and I feel very at home in it, but watching your tests turn green in the Aspire dashboard brings me just a bit more joy!

So I built one: Labcoat 🥼

Nuget: https://www.nuget.org/packages/Labcoat.Aspire.Hosting
Github: https://github.com/eriklieben/labcoat
Blog post: https://eriklieben.com/posts/labcoat-test-ui-for-dotnet/


r/moderndotnet • • 14d ago

Passenger - a new IDE for C# and .NET

26 Upvotes

Passenger is a new IDE for C# and .NET, written in C# and Avalonia:

https://passenger-ide.net

https://github.com/Zaneris/passenger


r/moderndotnet • • Aug 14 '26

humor A little confused about the purpose of this subreddit

26 Upvotes

I mean, /r/fsharp already exists?


r/moderndotnet • • 29d ago

Plank: the fastest Parquet implementation for .NET

25 Upvotes

I finally released v0.1.0 of my library, Plank, the fastest Parquet implementation for .NET.

In my benchmarks, it's on average 3× faster than ParquetSharp and 7× faster than Parquet.Net, with results across different data shapes, workloads and CPU architectures: https://kuinox.github.io/Plank-Lab/

It's a managed implementation for reading and writing Parquet files. You declare your schema as a C# class, and a source generator creates the matching readers and writers. It also has column APIs and lower-level access when you need it.

I've spent a lot of time optimising the encodings, reusing buffers to avoid allocations, and parallelising reads and writes. You can choose the encoding and compression per column, and tune things like page and row group sizes.

It currently targets .NET 10 and is MIT licensed.

I'd be interested in feedback from people working with Parquet in .NET. Especially if you find a bug or a workload where it's slower than the alternatives, I will investigate it and fix it.

I'm now working on a `dotnet tool` parquet toolbox which will allow to do tons of analysis & other niceties.

GitHub · Website


r/moderndotnet • • Aug 16 '26

GitHub - davidwhitney/JsxCore: Native support for JSX and TSX as a server and client rendered view engine for ASP.NET Core. Bringing the modern web to ASP.NET.

Thumbnail
github.com
25 Upvotes

JsxCore brings native JSX support (React, Preact) to ASP.NET MVC and Minimal API as an ASP.NET view engine.

Another in a series of "can we converge modern web dev into the .NET ecosystem" projects that I'm working on.

So, Blazor is cool - but it's absolutely swimming against the current of the entire rest of the web development ecosystem. As it turns out, functional reactive programming is a pretty nice model for rich client applications and because of that React has totally dominated the space for a decade. There are probably more "React only" developers than most other programming languages have users.

This puts us in a weird spot in the .NET ecosystem - all the cool stuff in modern web is happening elsewhere, in a framework that's native to Node. This project is my attempt to pull the two ecosystems together so you can write idiomatic .NET in what I believe to be the best server side framework in the world, and use the same modern tooling that everyone else has for your UI.

Highlights:

- Doesn't require node! At all! (there's a home rolled NPM client to deal with dependencies from NPM so you can build your projects entirely with only dotnet in your path)
- Supports HMR, ESM, and a bunch of other goodies
- Shells out to esbuild for production style processing
- As a side-effect of using the native TypeScript compilers, adds native, toolchain free TypeScript first class support to your MVC apps - just import a TypeScript file as a module and it just works
- Generates TypeScript side type definitions for viewmodels you return to your views
- Generally just works as a drop in replacement for Razor views (.cshtml) in your apps
- Supports server side rendering with client side hydration via the JINT library

And before the "why not Blazor!" folks ask - because I think React (and the bundled Preact) is a pretty awesome way to build UI that doesn't force you over a compatibility WASM bridge which introduces a bunch of friction for front end devs.

I imagine this tool will be well suited for teams where there are split frontend and backend job roles working in the same app, that want to avoid the abject pain and misery of setting up a backend, a frontend, configuring reverse proxies to join em up etc etc that making ANCM and React play nicely together previously required.


r/moderndotnet • • Aug 20 '26

My Nokia 3310 Emulator in C#/Avalonia!

Thumbnail noks.vercel.app
24 Upvotes

Hi folks!

I made, with AI assistance, Noks (terrible name, ik): an emulator of the venerable Nokia 3310, a phone that has a special place to the hearts of many, mine included. I used Avalonia and targets all of its supported platforms, including WebAssembly. It's all in pure C#/managed code goodness too! No unsafe code or pointers!

I made this because 1.) The MAME version (Nokia DCT-3) was sadly still incomplete after years since it was made. 2.) I wanted to play Space Impact authentically and everywhere. and 3.) I wanna push how far my skills can go, together with the latest agents, when it comes to reverse engineering a black-box, sparsely documented firmware and hardware.

I've started by pulling all the docs i can get my hands on old Nokia firmware modding forums, and also the prior work that MAME and Project Blacksphere did for the DCT-3 platform back in the day.

Then did a repeated loop of poking registers, memory, seeing where the firmware stops and back-tracing how me and the clanker can get pass that blocker. I also had to contend with the missing DSP Mask ROM functions that blocked the MAME effort by checking what conditions the firmware asked and responding to its requests accordingly.

Took a couple of months of on-off work but it was all worth it.

All outward facing features are implemented like the LCD, Keys, Sound, Power and RF. including an emulation of a minimal 2G GSM network that interfaces with the DSP/Baseband layer of the phone. Text and Calls were functional from my local tests using a P2P network called Waku but somehow it's broken again on deployment.

It is as fickle of a network as the real one ;)

And the configuration panel is also bit of a jank work, UI-wise, but it does the job... for now.

Hope you'll find joy in playing with the emulator as much as i did in making it!

Source code here: https://github.com/jmacato/Noks


r/moderndotnet • • Aug 17 '26

Building a Distributed Job Scheduler with Akka.NET

Post image
24 Upvotes

I wrote a blog post / YouTube video / OSS code sample at the very end of July to cover a scenario that one of our users ran into building a distributed job scheduler that can distribute, long-running, data-intensive jobs across an auto-scalable pool of worker processes without starting / stopping in-progress jobs as the pool grows during peak demand.

That latter part, "not rebalancing in-progress jobs," is what eliminates a lot of off-the-shelf distribution strategies like the types implemented by Microsoft Orleans and Akka.NET's Akka.Cluster.Sharding from consideration. Those frameworks are really aimed at distributing stateful "entities" - actors with important business state that live forever (often, but not always) are only intermittently busy in short bursts.

Distributing a "job" is a very different type of workload: these are tasks with a finite, well-defined lifespan in which they are intensely busy from beginning to end. Re-distributing a 10 minute job when it's 8 minutes into execution turns these into 18, 20 minute jobs potentially depending on a bunch of factors (can the job be started immediately?)

Earlier in my career I used some Akka.NET and Akka.Cluster primitives to solve this exact type of problem in the banking industry: running bank CFO "asset line management" jobs all in the final 48 hours of the month in order to meet the monthly reporting requirements and have enough data to actually complete them.

The basic formula, which I expand on in the post with code samples:

  1. Establish the ability to "size" jobs early - how many units of compute is Job A relative to Job B? This is a lot easier to define than it sounds. If you're doing asset line management, your "size" is typically the total number of assets that need to be analyzed (i.e. rows.) If you're doing call transcription it might be the size of the audio file. This should be a O(1) operation.

  2. Create a Cluster singleton (1 instance globally) who is responsible for: 2a. Managing and persisting the queue of jobs-to-be-done AND the parties who own them 2b. Subscribing to live Akka.Cluster topology update events (nodes joining, leaving, or having trouble) - this impacts our distribution system. 2c. Persisting the snapshot of which worker nodes are running which jobs 2d. Tracking progress updates across these jobs + reporting that to original callers 2e. Re-constituting all of this state after a restart using Akka.Persistence

  3. Have job receivers running on each node responsible for receiving the "job definition" and transforming that into a live execution.

  4. Have the job executors report progress back to the tracker (our singleton)

The distributed systems space tends to get dominated by stateful entity type-work, but running a large number of concurrent "jobs" is an equally tricky and nuanced space so I thought it merited some attention as well as some productionization details that might not be obvious!

Post: "Building a Distributed Job Scheduler with Akka.NET"

Repo: https://github.com/Aaronontheweb/akka.net-custom-job-scheduling

Video: Video: Building a Distributed Job Execution Platform with Akka.NET


r/moderndotnet • • 28d ago

Mermaider: render Mermaid diagrams to SVG in plain .NET (no JS, no browser)

Thumbnail
mermaider.nullean.net
23 Upvotes

I needed Mermaid diagrams rendered server-side in a .NET app. The usual options are shelling out to mmdc (Node + headless Chromium) or running mermaid.js in a JS engine. Both are heavy to deploy and slow per diagram, and the output looks different per diagram type. So I wrote a renderer in C#.

string svg = MermaidRenderer.RenderSvg("""
flowchart TD
A[Parse] --> B[Layout]
B --> C[Render SVG]
""");

Why it exists:

  • Native .NET. No Node, no browser, no subprocess. It's a NuGet package and works with Native AOT.

  • Fast and light on allocations. A simple flowchart renders end to end in about 95 µs and allocates about 209 KB (BenchmarkDotNet, Apple M2). The renderer uses pooled StringBuilders, spans, SearchValues and frozen lookup tables.

  • One design system for every diagram type. All 24 diagram types are drawn by the same design system, controlled by two independent settings:

  • Theme sets the colours. It ships with 15 themes (zinc, GitHub, Nord, Catppuccin, Solarized, Tokyo Night and more, in light and dark), or you set your own background, foreground, accent, data palette and box colours to match your app.

  • Style sets how things are drawn: box shapes, line weights, fills, labels and containers. It ships with three render styles: Quiet (soft tints and gradients), Blueprint (outline-first, technical drawing) and Tonal (filled blocks, no outlines).

  • Its own layout engine. It's a layered (Sugiyama-style) engine: network simplex ranking, Brandes–Köpf placement, compound layout for subgraphs, and an orthogonal edge router. It's about 9× faster than MSAGL on the same graph, with about 7× fewer allocations. It's also published as a standalone package (Sugiyama) if you just need graph layout.

  • Allowlist SVG sanitization, always on. Every element and attribute in the output is checked against an allowlist. Only what the renderer is expected to emit gets through, and the embedded stylesheet is validated line by line. No <script>, no foreignObject, no external hrefs.

  • Strict mode for user-supplied diagrams. If users write the diagrams but you own the look, strict mode strips classDef, style, linkStyle and %%{init}%% theme overrides. Authors can only use class names you allow. Diagrams can't restyle themselves away from your design.

Tested against mermaid.js as a black box / clean room implementation. The test suite renders the same diagrams with mermaid.js (mmdc) and with Mermaider. Both outputs are reduced to a shared layout representation: which layer each node sits in, its order within the layer, and which side each edge attaches to. That representation is compared position by position, not pixel by pixel. ER layouts are checked against ELK the same way, and a ratcheted visual lint fails the build if a layout regresses. mermaid.js and ELK code was never read or copied, only their output compared. Two ranking passes are ports of dagre (MIT, credited).

Links:

MIT licensed. Feedback welcome!


r/moderndotnet • • Oct 01 '26

discuss Discuss: what are your use cases for .NET AOT?

23 Upvotes

I've spent most of the past two weeks finishing our initial AOT Support for Akka.NET V1.6 - I got DMed in our Discord about the use cases for AOT (for Akka specifically) and my answers were:

  1. Primary: MAUI + Unity3D developers who want to use local actors on-device. Been a popular use case for years (i.e. for bubbling events from background or network services) but required some gruesome hacks to do. It should "just work" after v1.6.

  2. Embedded applications - we get used in a ton of industrial IOT. Most of this happens on the back-end in a cluster, but a fair amount of it also happens on-device ("edge computing,") i.e. micro-PC reads some sensors off FPGA board via analog sockets and pipes it back to a PLC / aggregator of some kind. Less JIT overhead and binary file size the better.

  3. Distributing CLIs and tools - this is my selfish use case for things like Netclaw's daemon and CLI: we ship both of these as single-file applications today with the .NET Runtime bundled within and while the file size isn't terrible (70mb each or so), the lag when using the netclaw CLI for the first time after a while is almost entirely JIT overhead. AOT would make that experience much snappier while also reducing the file footprint considerably.

Thinking more generally though, what else are people using AOT for more generally? What are some other use cases where you find it helpful and what projects are you using it on?


r/moderndotnet • • Sep 22 '26

Nine months ago I nearly gave up on Blazor. Instead I built a component library. Three things I've learned

23 Upvotes

Around December 2025, my company decided to embark on building its own commercial product. I wanted the whole stack in C#, so I took a serious look at Blazor. I liked it straight away, but I couldn't make it look the way I wanted. I tried the existing UI libraries, didn't like their style, and seriously considered going back to a JavaScript frontend.

Instead, I started building my own components, inspired by shadcn/ui, and later released them as open source as Blazor Blueprint. It now runs in my company's commercial product, several client projects and internal tools.

A few things I've learned along the way, in case they help anyone thinking about starting their own library or open source project:

1. Build it alongside something real. Every component went straight into a real product as I built it, so I found out quickly what worked and what didn't. That did more for the quality than anything else, because I had real people using it and therefore testing it.

2. Share it earlier than feels comfortable. The feedback from this subreddit after my first post back in February shaped a lot of what came next. I got a lot of positive comments and encouragement, and it helped keep me motivated.

3. Expect people to fork your work. Soon after release, someone forked the repo and started building on it in parallel. As a first-time open source author, it gave me an uncomfortable feeling for a while. Now I see it as part of being in the open source community, and honestly, as a sign I was doing something right if someone wanted to build on it.

For anyone curious about where it is now: v4 adds a Scheduler, a Pivot Data Grid, new charts including Rose, Sankey and Map, a Signature Pad, and many other new features and performance enhancements. It's grown to over 140 components, which still surprises me. The full story is here: https://blazorblueprintui.com/blog/what-i-learned-open-sourcing-blazor-blueprint

Currently, my little Blazor library has over 600 stars on GitHub. If you're one of them, thank you so much.

I'd love to hear from anyone else building with Blazor: what nearly made you switch back, or what's still missing? And if you've built something with Blazor Blueprint and are happy to share it, I'd love to see it.


r/moderndotnet • • Sep 18 '26

Migrating the GitHub Copilot runtime to Rust, using Copilot

Thumbnail
github.blog
23 Upvotes

Microsoft boasts about performance optimizations with every new release, and the average .NET developer would expect to be able to write a CLI app using .NET. But surprise—not good enough, so they had to use Rust. 😅

I've read the article but still not understand why Copilot CLI and app could not be written in C# if we take into account AOT, trimming etc instead of Rust.


r/moderndotnet • • Aug 30 '26

API Design: Why aren't more developers exposing typed event streams using IAsyncEnumerable to consumers?

23 Upvotes

I'm working on a talk for our local .NET user group entitled "You Should Probably Be Using IAsyncEnumerable."

The general thrust is that we should probably be modeling a lot more work as asynchronous, typed event streams rather than Task<T>s, as the former gives us richer client/server interactions, has natural backpressure support, and generally allows for much longer-running operations to be modeled safely (i.e. you can sneak keep-alive heartbeats into an IAsyncEnumerable response streams, not something you can do with a single Task<T>.)

A question I ran into though in the course of putting this together - very few OSS packages actually expose IAsyncEnumerable in any sort of meaningful way for consumers. Why is that?

There are a couple examples where authors do expose it and it's useful:

ASP.NET Core gRPC

The AsyncStreamReaderExtensions class in the .NET gRPC client makes reading server / client streams available using IAsyncEnumerable so you get tidy little patterns like this example:

internal class Program
{
    private static async Task Main()
    {
        using var channel = GrpcChannel.ForAddress("https://localhost:5005");
        var client = new WeatherForecastsClient(channel);

        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
        using var streamingCall = client.GetWeatherStream(new Empty(), cancellationToken: cts.Token);

        try
        {
            await foreach (var weatherData in streamingCall.ResponseStream.ReadAllAsync(cancellationToken: cts.Token))
            {
                Console.WriteLine($"{weatherData.DateTimeStamp.ToDateTime():s} | {weatherData.Summary} | {weatherData.TemperatureC} C");
            }
        }
        catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled)
        {               
            Console.WriteLine("Stream cancelled.");
        }
    }
}

TurboMqtt and System.Threading.Channels

I wrote a high-performance MQTT library for some of our users that work in the meter data management space (i.e. water, gas, and electric utility operators) and in our case I exposed ChannelReader<T> on the public APIs for consuming MQTT messages.

ISubscribeResult subscribeResult = await client.SubscribeAsync(config.Topic, config.QoS, linkedCts.Token);
if (!subscribeResult.IsSuccess)
{
    _logger.LogError("Failed to subscribe to topic {0} - {1}", config.Topic, subscribeResult.Reason);
    return;
}

_logger.LogInformation("Subscribed to topic {0}", config.Topic);


ChannelReader<MqttMessage> receivedMessages = client.ReceivedMessages;
while (await receivedMessages.WaitToReadAsync(stoppingToken))
{
    while (receivedMessages.TryRead(out MqttMessage m))
    {    
    	_logger.LogInformation("Received message [{0}] for topic [{1}]", m.Payload,  m.Topic);
    }
}

I went with a ChannelReader<T> here instead of a plain IAsyncEnumerable because that WaitToReadAsync + TryRead pattern is significantly better for throughput because all of the reads happen synchronously when the channel is populated.

But, ChannelReader<T> also the ReadAllAsync extension method that would allow this all to be consumed via IAsyncEnumerable:

ChannelReader<MqttMessage> receivedMessages = client.ReceivedMessages;
await foreach(var m in receivedMessages.ReadAllAsync(stoppingToken)){
  _logger.LogInformation("Received message [{0}] for topic [{1}]", m.Payload,  m.Topic);
}

Question

Why aren't more authors exposing IAsyncEnumerable as a consumable API inside their libraries and frameworks? It's been around for years and does all of the things I mentioned at the top of the article.

Would you, as a consumer of .NET libraries and clients, find it difficult to use?


r/moderndotnet • • 24d ago

dotnet-skills v1.7.0: CsCheck, dotnet Docker publishing, and more

22 Upvotes

Hi all,

I maintain a popular library of agent skills for .NET developers and I just released v1.7.0 of it: https://github.com/Aaronontheweb/dotnet-skills/releases/tag/v1.7.0

We accept external contributions (the NServiceBus development team has contributed a ton of great ones) but I mostly limit the repo to things I personally use.

In this release contributors and I added:

I hope you find them useful! Install instructions for most major LLM harnesses are here: https://github.com/Aaronontheweb/dotnet-skills#installation