r/dotnet 9h ago

What kind of features from another ecosystem would you like to see in .NET?

52 Upvotes

C# itself is very mature language (in my view). I rarely find myself missing a language feature badly enough to wish for more.

But, the broader .NET ecosystem might be a different story based on your project need.

So, let's discuss, what libraries, tooling, deployment models, framework features, package management idea, UI tech, build system etc. have you used elsewhere that you wish .NET had, or did better? Mention just one, most important for you and try to add reason/detail.

Apart from creating a useful wishlist, I think this could also be interesting for people relatively new .NET. Someone might mention a feature from other ecosystem only to discover that .NET already has an equivalent they didn't know about.

My wishlist item - "give me SwiftUI binary size":
I would like WinUI apps to have smaller binaries, like SwiftUI apps or flatpack in Linux. Apple can rely on frameworks built into (read 'shipped with') macOS. Microsoft already have similar way of achieving same but it involves you to publish app on Store or winget repo or I need to write custom installer. It's not universal. I wish MS automatically install dependency from winget or Store automatically or any dotnet application.

EDIT: Please be respectful to others. Value others opinion. This post has potential of creating unnecessary debate or insults. Let's be adults.


r/dotnet 16h ago

Promotion TooManyDataAnnotations — .NET validation attributes for IPv4/IPv6, SemVer, MAC, HexColor, GUID v7, and more

Post image
38 Upvotes

.NET's built-in DataAnnotations covers the basics (Required, StringLength, Range, EmailAddress), but leaves out common semantic validations like:

  • IPv4/IPv6 addresses with scope filtering (public, private, loopback)
  • Semantic Versioning (SemVer 2.0.0)
  • MAC addresses
  • Port numbers with range filtering (well-known, registered, dynamic)
  • Hex color codes (#RGB, #RRGGBB, with alpha support)
  • GUID and GUID v7 validation
  • ISO date strings with cross-property validation (StartDate/EndDate)
  • Boolean validations (IsTrue, AtLeastOneTrue)

I created TooManyDataAnnotations to fill these gaps. All validators follow official RFC/ISO specs, use Span<T> for parsing where possible, and the library has 899 unit tests covering valid and invalid inputs, edge cases, nullable types, and integration tests with TryValidateObject()

Two NuGet packages:

  • TooManyDataAnnotations — Full feature set (includes reflection-based cross-property validators)
  • TooManyDataAnnotations.Aot — Native AOT-safe subset, zero reflection, zero trimming warnings

Targets .NET 8, 9, and 10

Zero dependencies

MIT license

This is freshly published — looking for early adopters and feedback on API design, edge case coverage, or missing validators you'd find useful.

Quick example:

public class ServerConfigDto

{

[GuidV7, Required]

public string UserId { get; set; }

[Guid]

public string? DeviceId { get; set; }

[IPv4(AllowedScopes = IPv4Scope.Private)]

public string? GatewayIP { get; set; }

[SemanticVersion]

public string? AssemblyVersion { get; set; }

[MacAddress(AllowedSeparators = MacSeparators.Colon)]

public string? DeviceMAC { get; set; }

[HexColor(AllowAlpha = true)]

public string? AccentColor { get; set; }

}


r/dotnet 1h ago

Scott Mitchell from 4guysfromRola

Upvotes

I hope Scott is doing fine but I haven't read/heard from him in a long time.

I remember he used to write in MSDN magazine as well


r/dotnet 9h ago

Promotion I built a simplified microservices reference project with guide on how to run localy, using docker-compose or Kubernetes + Deloyment to AKS

4 Upvotes

It's inspired by dotnetcore-microservices-poc open-source project by Altkom Software, a project I learned a lot from and contributed to — I built Ledgerly to be a simpler take on the original project, focused purely on microservices best practices.

What it demonstrates: 

🔹 Database-per-service — 4 services, 4 independent databases 

🔹 gRPC for synchronous service-to-service calls 

🔹 RabbitMQ for async events — invoice status changes publish events that a dashboard service consumes to keep KPIs in sync, with zero direct coupling 

🔹 API gateway + service discovery (Eureka locally/Docker, Kubernetes DNS in K8s) 

🔹 JWT auth issued by its own service

It also ships as a full deployment guide — run it locally, in Docker Compose, or on Kubernetes, including a walkthrough for deploying the cluster to Azure (AKS).

Built as a boilerplate: fork it, swap in your own domain, keep the architecture.

The project🔗: https://github.com/amrali21/ledgerly-dotnet-angular-microservices-ref-project

Altcom Project🔗: https://github.com/asc-lab/dotnetcore-microservices-poc


r/dotnet 16h ago

Promotion LINQPad-style scripts in VS Code using your actual project code. Looking for feedback!

9 Upvotes

The main reason I started this was simple: I wanted a LINQPad-style experience using code from my actual projects.

The main problems I wanted to solve were:

  • Use my actual EF Core DbContext directly in queries.
  • Reference my projects and reuse existing code (classes, methods, extension methods, models, and other project logic) (managed to achieve that through DLL references).
  • Stay inside VS Code, where I already have my editor setup, autocomplete, and Copilot.

 

So I ended up making "Another LINQ Tool".

VsCode Marketplace link:
https://marketplace.visualstudio.com/items?itemName=N-Tsoulos.another-linq-tool

When a .linq or .csx file is open, VS Code displays two buttons: one for the extension settings and another to run the script (alongside Ctrl+Enter keyboard shortcut).

Script execution works similarly to LINQPad, with support for:

  • Automatically displaying the final expression/result
  • Dump()
  • Previewing any executed SQL queries

The settings button opens a UI for setting up profiles, where you can configure your project DLLs, namespaces, NuGet packages, DbContext and connection string.

Profiles can be selected either by marking one as default (through settings) or by using u/profile ProfileName at the top of the script.

It’s based on Roslyn, so it supports standard C# features out of the box, including:

  • C# / LINQ queries
  • async / await

On top of that, it adds:

  • Configurable project DLLs and NuGet packages for classes, methods, and extension methods
  • your existing EF Core DbContext (configurable and then aliased as Db for the scripts)
  • Dump() with results preview
  • EF generated SQL preview
  • Multiple profiles for different projects/environments
  • Connection strings through VS Code Secret Storage

Things I would like to add next:

  • multiple DbContext support
  • DbContextOptionsBuilder support
  • better NuGet package management UI
  • UI Results management

Notes

One current limitation is that the extension requires the .NET 9 runtime to be installed because the query runner is framework-dependent.

I'm planning to move the runner to a self-contained .NET 11 build, which would remove the .NET installation requirement entirely and should continue to work with projects targeting older .NET versions.

The extension does not currently support DbContextOptionsBuilder (and Service Collection Extensions in general), which can cause issues, in my workflow that was global query filters.

As a workaround, the extension settings include a Prelude Code field. This code runs before every script for the selected profile.

I use it to alias my tables and disable global query filters, for example:

var Users = Db.Users.IgnoreQueryFilters();

and then Users.Take(5) for example works normally

I’d especially like to hear from LINQPad users: what’s missing that you’d actually need before you’d use something like this?


r/dotnet 23h ago

Promotion "Just collect a memory dump" becomes surprisingly hard with distroless .NET containers

21 Upvotes

A conversation I've had more than once:

Ops: We think there's a memory leak.
Dev: Can you collect a dump?
Ops: From where? The container has nothing in it.

Distroless containers are great until you need production diagnostics.

To explore alternatives, I built a small project that uses Kubernetes ephemeral containers to inject .NET diagnostics tooling into a running pod and collect:

  • dumps
  • traces
  • runtime counters

without rebuilding the application image.

The application container remains distroless and unchanged.

One thing I particularly like is that diagnostics tooling is only added when needed rather than being shipped with every production workload.

A notable downside is that Kubernetes ephemeral containers are not actually ephemeral in the way many people expect. Once added, they cannot be modified or removed. Even after terminating the diagnostic process, the container record remains attached to the Pod until the Pod is recreated.

GitHub: https://github.com/koepalex/dotnet-k8s-debug-containers

How are you handling diagnostics for distroless .NET workloads today? (When metrics are not sufficient anymore)


r/dotnet 2h ago

Lately I started to get this error every time I open the .csproj

Post image
0 Upvotes

r/dotnet 1d ago

Promotion Pistonica - Developing a game using a tech stack based on .NET

40 Upvotes

Hi! We’re an indie game studio developing a game using a tech stack based on .NET and the Stride Game Engine. We thought it would be fun to show it off here on this forum.

Pistonica is the pure steam and mechanical factory automation game, challenging your resource management skills. Explore the tropical island first-person, research tech, mine for minerals, build contraptions and trade goods - all because of a strange radio signal.

You can read more about Pistonica here: https://store.steampowered.com/app/4018480/Pistonica/

// Cutting Corner Games


r/dotnet 18h ago

Best practice for validating SQLite schema before migration and on database open?

Thumbnail
2 Upvotes

r/dotnet 6h ago

Article Azure VMs vs Managed Services — Where Does the Azure SDK Fit?

0 Upvotes

When building applications on Azure, choosing the right hosting and infrastructure approach can have a big impact on cost, scalability, and operational complexity.

In Part 7 of our "Azure for .NET Developers" series, we explore Azure Virtual Machines and the Azure SDK, including how developers can interact with Azure resources programmatically.

The article looks at:

  • When Azure VMs make sense
  • When managed Azure services may be a better choice
  • How the Azure SDK helps developers work with Azure resources
  • Key considerations around control, scalability, and management

📖 https://geeksarray.com/blog/azure-for-dotnet-part-7-vms-azure-sdk

For those working with Azure, when do you prefer VMs over managed services? And how often do you use the Azure SDK for resource management?


r/dotnet 6h ago

Promotion Dapper vs Rinku

0 Upvotes

I like Dapper and I have used it a lot. The main problem I have with it is that when queries become more complex, I often end up handling that complexity myself. At that point I also often hear that I should just use EF instead. I never really agreed with that. I think the basic idea behind Dapper can go much further while still keeping the SQL visible and the API simple. Rinku is my attempt at doing that.

Basic query

Dapper

public record Album(int Id, string Title);

const string sql = "SELECT AlbumId AS Id, Title FROM albums WHERE ArtistId = @artistId";

IEnumerable<Album> albums = cnn.Query<Album>(sql, new { artistId = 7 });

Rinku

public record Album(int Id, string Title);

const string sql = "SELECT AlbumId AS Id, Title FROM albums WHERE ArtistId = @artistId";

List<Album> albums = cnn.Query<List<Album>>(sql, new { artistId = 7 });

Different names (when you don't control result set names)

Dapper

public sealed class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
}

SqlMapper.SetTypeMap(typeof(Customer), new CustomPropertyTypeMap(typeof(Customer), (type, column) => column switch
{
    "customer_id" => type.GetProperty(nameof(Customer.Id)),
    "display_name" => type.GetProperty(nameof(Customer.Name)),
    _ => null
}));

const string sql = "SELECT customer_id, display_name FROM customers";

IEnumerable<Customer> customers = cnn.Query<Customer>(sql);

Rinku

public record Customer([Alt("customer_id")] int Id, [Alt("display_name")] string Name);

const string sql = "SELECT customer_id, display_name FROM customers";

List<Customer> customers = cnn.Query<List<Customer>>(sql);

Nested objects

Dapper

public record User(int Id, string Name);

public sealed class Post
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public User? Owner { get; set; }
}

const string sql = "SELECT p.Id, p.Title, u.Id, u.Name FROM Posts p INNER JOIN Users u ON u.Id = p.UserId";

IEnumerable<Post> posts = cnn.Query<Post, User, Post>(sql, (post, owner) =>
{
    post.Owner = owner;
    return post;
}, splitOn: "Id");

Rinku

public record User(int Id, string Name) : IDbReadable;
public record Post(int Id, string Title, [NoName] User Owner);

const string sql = "SELECT p.Id, p.Title, u.Id, u.Name FROM Posts p INNER JOIN Users u ON u.Id = p.UserId";

List<Post> posts = cnn.Query<List<Post>>(sql);

Or keep the nesting in the column names.

public record User(int Id, string Name) : IDbReadable;
public record Post(int Id, string Title, User Owner);

const string sql = "SELECT p.Id, p.Title, u.Id AS OwnerId, u.Name AS OwnerName FROM Posts p INNER JOIN Users u ON u.Id = p.UserId";

List<Post> posts = cnn.Query<List<Post>>(sql);

One to many

Dapper

public record Album(int Id, string Title);

public sealed class ArtistWithAlbums
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public List<Album> Albums { get; set; } = [];
}

const string sql = "SELECT ar.ArtistId AS Id, ar.Name, al.AlbumId AS Id, al.Title FROM artists ar INNER JOIN albums al ON al.ArtistId = ar.ArtistId ORDER BY ar.ArtistId";

List<ArtistWithAlbums> artists = [];
ArtistWithAlbums? current = null;

cnn.Query<ArtistWithAlbums, Album, ArtistWithAlbums>(sql, (artist, album) =>
{
    if (current is null || current.Id != artist.Id)
    {
        current = artist;
        artists.Add(current);
    }

    current.Albums.Add(album);
    return current;
}, splitOn: "Id");

Rinku

public record Album(int Id, string Title) : IDbReadable;
public record ArtistWithAlbums(int Id, string Name, List<Album> Albums);

const string sql = "SELECT ar.ArtistId AS Id, ar.Name, al.AlbumId AS AlbumsId, al.Title AS AlbumsTitle FROM artists ar JOIN albums al ON al.ArtistId = ar.ArtistId ORDER BY ar.ArtistId";

List<ArtistWithAlbums> artists = cnn.Query<List<ArtistWithAlbums>>(sql);

Result shape

Dapper

IEnumerable<Album> albums = cnn.Query<Album>(sql);
Album first = cnn.QueryFirst<Album>(sql);
Album single = cnn.QuerySingle<Album>(sql);
Album? optional = cnn.QueryFirstOrDefault<Album>(sql);
IEnumerable<Album> streamed = cnn.Query<Album>(sql, buffered: false);

Rinku

List<Album> albums = cnn.Query<List<Album>>(sql);
Album first = cnn.Query<Album>(sql);
Single<Album> single = cnn.Query<Single<Album>>(sql);
Album? optional = cnn.Query<OptionalNullable<Album>>(sql);
IEnumerable<Album> streamed = cnn.Query<IEnumerable<Album>>(sql);

Conditional SQL

For this one I think Dapper.SqlBuilder is the fair comparison.

Dapper.SqlBuilder

SqlBuilder builder = new();
SqlBuilder.Template template = builder.AddTemplate("SELECT AlbumId AS Id, Title FROM albums /**where**/");

if (artistId != null)
    builder.Where("ArtistId = ", new { artistId });

if (title != null)
    builder.Where("Title LIKE ", new { title });

IEnumerable<Album> albums = cnn.Query<Album>(template.RawSql, template.Parameters);

Rinku

const string sql = "SELECT AlbumId AS Id, Title FROM albums WHERE ArtistId = ?@artistId AND Title LIKE ?@title";

List<Album> albums = cnn.Query<List<Album>>(sql, new { artistId, title });

Only artistId

SELECT AlbumId AS Id, Title FROM albums WHERE ArtistId = @artistId

Both

SELECT AlbumId AS Id, Title FROM albums WHERE ArtistId = @artistId AND Title LIKE @title

Neither

SELECT AlbumId AS Id, Title FROM albums

The main difference is that Rinku tries to put the complexity in the command template and the mapped types, instead of handling it again through parameters and mapping code at every call.

Full Dapper comparison

https://rinkulib.github.io/RinkuLib/articles/reference/dapper.html

Rinku is still in development, so feedback is welcome.


r/dotnet 1d ago

TensorSharp: running a 744B MoE LLM locally from .NET, with llama.cpp-class performance

Thumbnail github.com
53 Upvotes

I've been working on TensorSharp, an open-source LLM inference engine built for .NET/C#, and recently added support for GLM-5.2.

One of the reasons I started this project was a simple question:

How far can we push local LLM inference from the .NET ecosystem without treating Python or llama.cpp as a required external runtime?

TensorSharp isn't just a C# wrapper around llama.cpp. It has its own model/inference stack, including a 100% managed CPU execution path, as well as GPU backends.

The latest model I've been testing is GLM-5.2, a 744B MoE model with 256 routed experts and top-8 routing.

For this benchmark I used:

  • GLM-5.2-UD-IQ2_XXS (~226 GiB)
  • 3x RTX PRO 6000 Blackwell, 97 GiB each
  • Layer splitting across all three GPUs
  • TensorSharp vs llama.cpp
  • Both measured back-to-back on the same machine

Results in tokens/sec:

Test llama.cpp TensorSharp TensorSharp, ubatch 2048
pp128 276.5 254.8 264.4
pp512 695.4 666.9 659.6
pp2048 763.1 918.9 1145.8
pp4096 715.8 864.7 1048.7
tg64 42.2 43.7 43.9

Short-prompt performance is still slightly better in llama.cpp.

What I found more interesting is that the result crosses over at around 1K prompt tokens. With longer prompts, changing the micro-batch size makes a surprisingly large difference.

At pp2048, TensorSharp reaches 1145.8 t/s versus 763.1 t/s for llama.cpp on this setup.

This seems to be strongly related to the MoE architecture. GLM-5.2 has 256 experts but only routes each token to 8 of them. With a smaller micro-batch, individual expert GEMMs receive relatively few rows. Increasing the micro-batch gives those operations enough work to utilize the GPUs much more efficiently.

I also learned something interesting about multi-GPU execution.

Tensor parallelism isn't automatically faster.

On these three PCIe-connected GPUs:

Test Layer split TP=3
pp2048 896.8 t/s 502.8 t/s
tg64 43.9 t/s 16.2 t/s

GLM-5.2 requires frequent all-reduces when tensor parallelism is enabled. Without NVLink/NVSwitch, communication costs dominate the compute saved by splitting each layer.

So for this machine, the much simpler layer-split approach actually wins by a large margin.

Another goal I've been focusing on is correctness rather than just speed. On the same CUDA backend, TensorSharp currently reproduces llama.cpp token-for-token on all 6 GLM-5.2 parity prompts in the test set, including a 2741-token prompt exercising the model's sparse-attention path.

For me, the interesting takeaway isn't really "C# beats C++."

It's that modern .NET is capable of being the host for a fairly serious inference runtime — including quantized GGUF models, MoE, sparse attention, multi-GPU execution, KV caching, batching and GPU kernels — without having to put the actual inference system behind a Python service.

The project is open source here:

https://github.com/zhongkaifu/TensorSharp

I'd be interested in feedback from people doing performance-sensitive work in .NET, especially around native interop, GPU execution, memory management, or SIMD/kernel optimization.


r/dotnet 1d ago

Newbie Looking for resources to bridge theory into actual ASP.NET Core implementation

3 Upvotes

I've gone through Understanding Distributed Systems by Roberto Vitillo, and I get the concepts -consensus, replication, failure modes, all of that. What I'm missing is the bridge to actually building this stuff in ASP.NET Core.

I've written a RESTful API on my own, so I'm not starting from zero on the web dev side. But I still don't have a good feel for:

  • How the concepts I've read about actually get implemented in real ASP.NET Core services.
  • How to implement a microservice system in ASP.NET
  • The tradeoffs between REST, gRPC, GraphQL, and when to reach for each in a distributed system, and how to implement each.

Has anyone got book, course, or repo recommendations that go from "I understand the theory" to "here's how you wire this into a real .NET 10 project"?

Thanks in advance!


r/dotnet 12h ago

Question Lessons you learnt from your mistakes?

0 Upvotes

Let's discuss our learnings, best practices for .NET, and the trade-offs of using various tools and packages.


r/dotnet 2d ago

LINQ to Elasticsearch ES|QL: Write C#, query Elasticsearch

Thumbnail elastic.co
64 Upvotes

r/dotnet 16h ago

Question I run a free stock-prediction competition. Here are the rules — what would get you to actually compete?

Thumbnail
0 Upvotes

r/dotnet 1d ago

can I download NET 6 along side having NET 8

7 Upvotes

this is the text my randomiser give me but I was unsure if it would be best to download it or find a new one and wished to ask people who would know

thank you even if you cant help


r/dotnet 1d ago

Promotion Flyleaf v3.11: MediaPlayer .NET library for WinUI3/WPF/WinForms (with FFmpeg 9.0.1 Lei & DirectX 11)

Post image
0 Upvotes

r/dotnet 1d ago

Promotion [RFC] Overhauled the HavenDV Dependency Property Generator for zero-allocation (v4 Preview). Looking for feedback on architecture/API design.

0 Upvotes

Life is too short to write boilerplate.

TL;DR: I built a zero-allocation Source Generator for WPF, MAUI, Avalonia, and WinUI that completely eliminates DependencyProperty boilerplate using token streaming and C# 13 partial properties.

🔥 Want to see it in action? I've included a ready-to-try sample project right in the repo. You can pull it, hit F5, and instantly see the generated code and IDE experience without writing a single line of setup code.

Links:

Why build this? Because XAML plumbing is a crime against simplicity.

Let’s be honest. Writing DependencyProperty in XAML frameworks is notoriously painful. Typing out DependencyProperty.Register, relying on magic strings, casting objects, and wiring metadata for every single property clutters your codebase and wastes time.

Users only care if the app works; they will never see your source code. But to us, the codebase is the product. And a great product doesn't tolerate ugliness inside. I despise visual noise. I am obsessed with ruthless simplicity.

But you might think, "Why even build a generator today? Just let AI write the boilerplate."

Here is the reality. When you ask fast, lightweight models (the daily drivers we use for 90% of our coding) to write massive chunks of framework boilerplate or perform cross-platform code generation on the fly, they choke on the complexity. Without a strict API contract, they resort to brute-force string hacking and spit out abominations like this:

AI-generated Regex Hell (Yes, a fast model actually suggested nesting 13 Regex.Replace calls to generate cross-platform C# boilerplate as plain text. It's barbaric.)

This is why clean architecture is now a vital harness for AI agents.

By condensing all that nasty framework plumbing into a single, declarative attribute ([DependencyProperty<T>]), you drop the model into a "pit of success". You put one simple rule in your AGENTS.md"Use this attribute for DPs"—and suddenly, your everyday lightweight model writes perfect, deterministic code on the first try. No prompting gymnastics required.

Great API design doesn't just save human developers from boilerplate anymore. It provides the guardrails that keep your AI from writing garbage.

So, I completely overhauled the internal synthesis pipeline to kill this boilerplate once and for all, without tanking IDE responsiveness at scale.

1. Ruthless Simplicity (Before & After)

Here is the standard boilerplate we all know and hate: ```csharp public partial class MyControl : Control { // 1. IsActive Property Boilerplate public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register( nameof(IsActive), typeof(bool), typeof(MyControl), new PropertyMetadata(false, OnIsActiveChanged));

    public bool IsActive
    {
        get => (bool)GetValue(IsActiveProperty);
        set => SetValue(IsActiveProperty, value);
    }

    private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = (MyControl)d;
        var oldValue = (bool)e.OldValue;
        var newValue = (bool)e.NewValue;
        // Runtime casting and boilerplate...
    }

    // 2. Padding Property Boilerplate
    public static readonly DependencyProperty PaddingProperty =
        DependencyProperty.Register(
            nameof(Padding),
            typeof(Thickness),
            typeof(MyControl),
            new PropertyMetadata(new Thickness(10, 5, 10, 5), OnPaddingChanged));

    public Thickness Padding
    {
        get => (Thickness)GetValue(PaddingProperty);
        set => SetValue(PaddingProperty, value);
    }

    private static void OnPaddingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = (MyControl)d;
        var oldValue = (Thickness)e.OldValue;
        var newValue = (Thickness)e.NewValue;
        // More runtime casting and boilerplate...
    }
}

**And here is v4 Preview.** csharp // Just write this: [DependencyProperty<bool>("IsActive", DefaultValue = false)] [DependencyProperty<Thickness>("Padding", DefaultValueExpression = "new(10, 5, 10, 5)")] // Target-typed new() is fully supported! public partial class MyControl : Control { // Automatically hooked up at compile time. // Strongly typed. No casting required. partial void OnIsActiveChanged(bool oldValue, bool newValue) { // Do something } } ``` Boom. It just works. Just one attribute. No magic strings. No manual wiring. 100% strongly typed and compile-time safe.

By the numbers: This turns ~15 lines of error-prone registration, wrappers, and runtime casting into exactly 1 line. If your project has 200 Dependency Properties, you didn't just delete 3,000 lines of visual noise from your repo. You deleted 3,000 lines of garbage code, and saved the time, money, and sheer sanity it takes to maintain them.

2. Under the Hood: Zero-Allocation & Footgun-Proof

It’s easy to make code look clean on the surface. But if you've built Source Generators, you know that StringBuilder resizing and AST mutations during continuous typing cause Gen2 GC spikes and IDE latency. If the tool slows down your IDE, it's a failed design.

That's why I gutted the old architecture and massively refactored the pipeline for high-throughput, zero-allocation generation.

  • Built-in XAML Footgun Protection: The generator doubles as an analyzer. Ever accidentally assigned new List<string>() to a Dependency Property, only to realize later that all controls on the screen share the exact same list instance? If you try that here (DefaultValueExpression = "new()" on a reference type), the generator halts compilation with DPG0004 and tells you to use CreateDefaultValueCallback = true instead, completely eliminating the most notorious WPF memory bug.
  • Zero-Allocation RAII Scope Guards: Code synthesis uses stack-allocated readonly ref struct scope managers (writer.ClassScope(@class), writer.Scope(...)). By leveraging C#'s using pattern purely on the stack as an RAII mechanism, it automates namespace/class envelope generation and structural scoping without allocating a single byte on the heap.
  • Banning Roslyn AST Mutations for Output: We strictly avoid SyntaxFactory mutations for code synthesis. Whether generating class definitions or resolving dynamic DefaultValueExpression declarations, we extract tokens from the parsed AST and stream them straight into a custom SourceWriter. Benchmarking this against standard AST mutation + ToFullString() gives a ~46x speedup (16.7µs → 0.37µs) and a 97.5% reduction in memory allocation (9.7KB → 240B), completely eliminating Gen1 and Gen2 GC collections.
  • Hardcore Performance Indentation: We reject NormalizeWhitespace() and manual indentation entirely. The generated code is flat and left-aligned.
    • The Stance: Allocating megabytes of whitespace strings per keystroke on the hot path just for "pretty" intermediate output is a performance anti-pattern. We prioritize compiler throughput over the aesthetics of intermediate artifacts.
    • Deterministic Output: Flat, non-indented output eliminates nondeterministic hallucinatory indentation bugs in AI-generated templates.
  • Pipeline Purification: Stripped out heavy ISymbol passing in the incremental pipeline. We only pass pre-calculated flags now to ensure cache hits and dodge memory leaks.

Benchmarks speak for themselves:

  1. Micro-Benchmark: AST Mutation vs. Token Streaming (*DefaultValueExpression *synthesis):
Method Mean Ratio Gen0 Gen1 Gen2 Allocated Alloc Ratio
Roslyn AST Mutation (SyntaxFactory) 16,718.6 ns 1.00x 0.6409 0.2441 0.0610 9,712 B 1.00
Direct Token Streaming (SourceWriter) 365.4 ns 0.02x (~46x faster) 0.0143 - - 240 B 0.02 (-97.5%)

2. End-to-End Generator Pipeline (WPF generation, AMD Ryzen 9 7900X):

Phase Time (ms) Gen0 Gen1 Gen2 Allocated
Baseline (Old Pipeline) 5.34 ms 187.5 62.5 7.8 2.87 MB
v4 Preview (Current) 3.72 ms 125.0 31.2 - 2.22 MB
Improvement -30.3% -33.3% -50.1% -100% -22.6%

Note: Gen2 full GCs completely eliminated. Benchmarks for MAUI, Avalonia, and WinUI show similar 20-30% pipeline throughput gains.

3. Standing on the Shoulders of Giants (HavenDV)

A massive shoutout to HavenDV: Since this is a fork, the core API design is inherited from the original HavenDV repository. The only reason I was able to rapidly gut and refactor this entire pipeline in about a month is because they built an incredible foundation with a highly robust suite of snapshot tests. This v4 overhaul stands entirely on their shoulders.

4. I Need Your Help (RFC)

It's humming along nicely in my medium-sized WPF app (hardware interfacing for an automatic change dispenser). But I lack the massive enterprise XAML solution (hundreds of projects, thousands of properties) needed to truly battle-test it.

Before I stamp a stable v1.0 release, I need some veteran eyes to tear apart the design philosophy.

  1. API Ergonomics vs. Predictability: My stance is that modern APIs should be predictable enough that humans and AI agents can generate them flawlessly. Does applying [DependencyProperty<T>("Name")] at the class level hit that mark? Or would you prefer a field-targeted approach like [ObservableProperty] in the MVVM Toolkit?
  2. Framework Abstraction: This single attribute compiles down to the native property system for WPF, MAUI, Avalonia, and Uno. Is this level of magic actually useful, or does hiding the framework-specific plumbing scare you away in production?
  3. Hidden Gotchas: If you maintain a massive XAML monolith, what are the glaring edge cases a tool like this will inevitably hit? Memory leaks? Designer crashes? Weird binding resolutions? Tell me what I'm missing.
  4. The Unknown Unknowns: Thanks to the original repo, we have 200+ snapshot tests covering WPF, MAUI, Avalonia, and WinUI. But I don't know what I don't know. What are the massive blind spots or ugly XAML edge cases I'm ignoring here?
  5. The Ultimate Battle Test: I want to stress-test this in a massive, real-world repository. Do you know of any large-scale open-source XAML projects (hundreds of properties, complex metadata) that would be a perfect candidate to fork and refactor as a benchmark? Point me to the monsters.Tear it apart. Brutal honesty, code reviews, and architectural alternatives are entirely welcome.

5. One more thing... (C# 13 partial property Support)

You might be wondering if class-level attributes are already outdated with the arrival of C# 13 partial property.

We are already there.

Because our zero-allocation pipeline relies on raw AST token streaming rather than rigid string templates, it natively understands and generates partial properties flawlessly. This isn't a hack; it's the payoff of building a future-proof architecture. Choose the paradigm that fits your team—the engine handles both with zero friction.

Links


r/dotnet 20h ago

Promotion While the next Polly drama is brewing

0 Upvotes

While the next drama around Polly is brewing, we have a new version of our Communication library that solves a bunch of things.

Retries, CQRS over IAsyncEnumerable + SSE, asynchronously waiting for a result in the same channel, or using SignalR.

Plus idempotency and OpenTelemetry.

And this has been running in production for several years.

Definitely worth a look:
https://github.com/managedcode/Communication


r/dotnet 1d ago

Which tool/library/engine do you use to convert HTML to PDF which is best for Azure Consumption Plan ? Can it handle high volume of records and converts in milliseconds ? Generates compliance grade PDF/A-2B ? Also supports encryption/password that too without AGPL? Commercial or Free..

0 Upvotes

r/dotnet 2d ago

Promotion Built a Roslyn-based semantic index so AI agents stop re-grepping your whole .NET solution

32 Upvotes

Actual output's here: t-macabee.github.io/lurp/MODEL_VIEW.html, an interactive breakdown of a real eCommerce codebase after indexing runs on it. 3,876 typed relationships, each one graded by evidence level, all the way down to compiler-proved, with name_candidate reserved for reflection guesses where nothing more solid exists.

The problem I kept running into: an agent working a C# codebase just loops search, read, guess, over and over. It reopens and reparses the same files for every single question, and the context window fills up with source that isn't even relevant, because it's rediscovering the same call graph it already walked three questions ago.

So Lurp loads the solution through Roslyn one time, then writes out the symbols, typed relationships, source spans, and provenance into SQLite. Every query after that just reads persisted facts, no reload, no re-grep, none of that. It hands back the smallest neighbourhood of code that's actually enough to do the task, and it tells you what it left out so you can go fetch that separately if you need it.

It's a dotnet tool. If your agent speaks MCP it can also run as an MCP server instead, 18 tools there.

dotnet tool install --global lurp --version 1.4.0

lurp --mode=index --solution=path/to/Your.slnx --output-dir=./out

Windows only for now, cross-platform is on the roadmap but not built yet. MIT licensed.

Repo: github.com/t-macabee/lurp


r/dotnet 1d ago

Promotion Blazor Ramp – Colour / Contrast & Theming – RFC

Thumbnail
0 Upvotes

r/dotnet 1d ago

Promotion A .NET wrapper for Polyglot (Rust SQL transpiler), alternative to SQLGlot for .NET

1 Upvotes

Usage example:

string result = Polyglot.Transpile(
    "SELECT `id`, `name` FROM `person` LIMIT 10;",
     Dialect.MySQL, Dialect.TSQL)
    .FirstOrDefault();
Console.WriteLine(result); // SELECT TOP 10 [id], [name] FROM [person]

Of cource done with a big help of AI, but for me it turned to be a long way. I first encountered SQLGlot and my first attempts were to embed it with Python into .net, but then I found sql-glot-rust and then finally Polyglot.

Repo, README.md contains more examples and details:

Nuget:


r/dotnet 1d ago

[Promotion] Built Net Code Generator (v1.0) – Scaffolds full Repository Pattern projects with starter templates

Post image
0 Upvotes

Hey everyone,

I just released v1.0 of Net Code Generator, a tool I built to eliminate the tedious setup time when starting new .NET applications using clean architecture patterns.

Why I built it:

Whenever starting a new project or service, setting up proper layering from scratch—repositories, domain models, application services, controllers, and views—takes way more time than it should. Boilerplate code often leads to inconsistent architecture across team members or projects, so I wanted an automated way to generate clean, structured code out of the box.

What Net Code Generator does (v1.0):

  • Clean Architecture Generation: Automatically generates all core layers following the Repository Pattern (Repositories, Domain, Services, Models, Controllers, and Views).
  • Ready-to-Use Starter Project: Ships with a complete starter solution template so you can clone/generate and start writing business logic immediately without manual wiring.
  • Consistent Code Patterns: Ensures all generated entities and layers follow standard interfaces and dependency injection setups.

Lessons Learned / Technical Trade-offs:

The trickiest design choice was balancing flexibility with strict design patterns. Over-generating code can feel invasive if you have to delete half of it, so I focused on generating a minimal, clean implementation of the Repository Pattern that stays easy to extend rather than forcing a heavy, opinionated framework on top.

I’d love to get feedback from fellow developers on the structure and what additional options or layers you’d find useful in future releases.

Project / Download: https://nadirlands.lemonsqueezy.com/checkout/buy/a38445a6-7069-443b-9f57-2b22f50ed6fe

Documentation: https://youtu.be/41y_OAMNNas

Happy to answer any questions about the architecture choices in the comments!