r/dotnet • • 20h ago

Article I benchmarked a native .NET LLM inference engine against llama.cpp, vLLM, SGLang, NInfer, and velox on an RTX 5090 — here are the results

40 Upvotes

TL;DR

I benchmarked TensorSharp, an open-source native .NET inference engine, against five other inference engines running Qwen3.8 27B on a single NVIDIA RTX 5090 (32GB).

The benchmark covers real-world workloads: coding, long-context processing, multi-turn conversations, JSON generation, function calling, agentic workflows, vision, and concurrent requests.

Key findings:

  • TTFT: TensorSharp achieved the fastest screenshot-processing TTFT at 125 ms, ahead of vLLM (127 ms), SGLang (153 ms), and llama.cpp (309 ms).
  • Prefill: TensorSharp processed approximately 8,000–9,300 tokens/sec, compared with 8,900–12,400 for NInfer/SGLang and 6,300–7,600 for llama.cpp.
  • Decode: TensorSharp reached 80 tokens/sec without speculative decoding and 234 tokens/sec with DFlash2, a 2.9× improvement.
  • Coding: TensorSharp generated code at 339 tokens/sec, compared with 321 for llama.cpp, 383 for vLLM, and 415 for NInfer.
  • Parallel requests: TensorSharp achieved 445 aggregate tokens/sec with 4 concurrent requests, ranking second behind NInfer (488).
  • Agentic workflows: TensorSharp completed a four-turn agentic workflow in 0.748 seconds, the fastest of all six engines.
  • Overall winner: NInfer led most raw throughput measurements. TensorSharp was particularly competitive in agentic workflows, screenshot TTFT, and concurrent inference.

For a native .NET inference engine, these results are encouraging. They show that .NET can be a viable foundation for high-performance local AI inference, not just an API client for Python-based inference servers.

Project: https://github.com/zhongkaifu/TensorSharp

1. Benchmark setup

All six engines ran sequentially on the same machine.

Component Configuration
GPU NVIDIA RTX 5090, 32GB
CPU AMD EPYC 9354
System memory 93GB limit
OS Ubuntu 24.04
Model Qwen3.8 27B
Context 40,960 tokens per sequence
Concurrency Up to 4 requests
Speculative decoding DFlash2, up to 7 drafts per step
Inference mode Greedy, thinking disabled
Repetitions 3 per scenario

Engines tested:

  • TensorSharp — native .NET, direct CUDA backend
  • llama.cpp — C/C++ inference engine
  • vLLM — Python/PyTorch inference framework
  • SGLang — Python/PyTorch serving framework
  • velox-inferer — Rust inference engine
  • NInfer — native inference engine

An important qualification: the engines used different quantized checkpoints and drafter formats. TensorSharp and llama.cpp used the same NVFP4 GGUF weights, while vLLM/SGLang and NInfer/velox used their respective model formats.

Therefore, these are end-to-end engine + checkpoint comparisons, not isolated comparisons of programming languages or inference kernels.

2. Time to First Token (TTFT)

TTFT matters for interactive applications because it determines how quickly users see the first response.

Without speculative decoding

Lower is better. All values are in seconds.

Task TensorSharp llama.cpp vLLM SGLang velox NInfer
Short prompt (~50 tokens) 0.050 0.027 0.061 0.042 0.088 0.051
4K prompt 0.430 0.524 0.368 0.320 0.533 0.322
16K prompt 1.64 2.05 1.45 1.34 1.80 1.24
32K prompt 3.96 5.01 3.73 3.58 4.21 3.02
Multi-turn, later turns 0.052 0.038 0.145 0.058 0.081 0.046
Screenshot (1344×768) 0.125 0.309 0.127 0.153 0.250 0.162

Observations:

TensorSharp’s screenshot TTFT was approximately 2.47× faster than llama.cpp and 2× faster than velox.

For short text prompts, llama.cpp was fastest, while TensorSharp responded in 50 ms.

For long-context workloads, NInfer led. TensorSharp processed a 32K prompt in 3.96 seconds, compared with 5.01 seconds for llama.cpp.

3. Prefill performance: processing long prompts

Prefill throughput becomes particularly important for RAG, document analysis, codebase understanding, and long-context agents.

The benchmark measured the following prefill throughput ranges:

Engine Prefill throughput
TensorSharp 8,000–9,300 tok/s
NInfer / SGLang 8,900–12,400 tok/s
llama.cpp 6,300–7,600 tok/s

These are reported ranges, not identical per-engine averages.

A more concrete comparison is the 32K-prompt TTFT:

Engine 32K TTFT
NInfer 3.02 s
SGLang 3.58 s
vLLM 3.73 s
TensorSharp 3.96 s
velox 4.21 s
llama.cpp 5.01 s

TensorSharp was approximately 21% faster than llama.cpp in 32K-prompt TTFT, although it remained behind NInfer, SGLang, and vLLM.

For .NET developers building document-processing pipelines or retrieval-augmented agents, this is an important result: a native .NET engine can process substantial contexts at competitive speeds.

4. Decode performance: plain vs. DFlash2

Decode throughput determines how quickly the model generates its response after prefill.

Single-request decode throughput

Engine Plain decode DFlash2 decode Speedup
TensorSharp 80 234 2.9×
llama.cpp 84 213 2.5×
vLLM 69 248 3.6×
SGLang 79 235 3.0×
velox 69 235 3.4×
NInfer 77 281 3.6×

All throughput values are tokens/sec.

Without speculative decoding, TensorSharp ranked second, just behind llama.cpp.

With DFlash2, TensorSharp reached 234 tok/s, effectively tied with SGLang and velox at 235 tok/s, but behind vLLM and NInfer.

The 234 tok/s result is the mean across code, prose, and passage-copy workloads.

Interestingly, all engines reporting DFlash2 acceptance achieved approximately 4.4–4.6 emitted tokens per verification step.

That suggests the remaining performance differences are primarily in draft-and-verify execution costs rather than drafter acceptance.

5. Performance by generation task

A single decode number doesn’t tell the whole story.

Different workloads have different generation characteristics. We separately measured coding, prose generation, and passage copying with DFlash2 enabled.

Higher is better, tokens/sec.

Engine Code generation Prose generation Passage copying
TensorSharp 339 174 190
llama.cpp 321 160 158
vLLM 383 189 171
SGLang 368 184 152
velox 346 184 175
NInfer 415 209 217

Coding assistants

TensorSharp generated code at 339 tok/s:

  • 5.6% faster than llama.cpp
  • 11.5% slower than vLLM
  • 18.3% slower than NInfer

This makes TensorSharp a competitive option for local code generation, while leaving meaningful room to optimize speculative verification.

Prose generation

TensorSharp achieved 174 tok/s, compared with 160 for llama.cpp and 209 for NInfer.

Passage copying

TensorSharp reached 190 tok/s, ranking second behind NInfer.

These results show why it is useful to benchmark different output patterns rather than relying on a single synthetic generation test.

6. Parallel request performance

Single-request speed is important, but inference servers also need to handle multiple simultaneous users or agent tasks.

Without speculative decoding

Aggregate output throughput, tokens/sec:

Engine 1 request 2 requests 4 requests
TensorSharp 80 137 215
llama.cpp 84 154 251
vLLM 69 116 226
SGLang 79 140 148
velox 69 67 67
NInfer 77 144 257

TensorSharp scaled from 80 tok/s for one request to 215 aggregate tok/s for four requests, a 2.69× throughput increase.

With DFlash2

Engine 4-request aggregate throughput
TensorSharp 445 tok/s
llama.cpp 259 tok/s
vLLM 304 tok/s
SGLang 251 tok/s
velox 303 tok/s
NInfer 488 tok/s

TensorSharp ranked second, achieving:

  • 72% higher throughput than llama.cpp
  • 46% higher throughput than vLLM
  • 47% higher throughput than velox
  • Approximately 91% of NInfer’s throughput

This is particularly relevant for .NET applications serving multiple simultaneous chat sessions, coding agents, or background AI tasks.

One caveat: SGLang could only run two active DFlash2 lanes within the 32GB GPU memory limit, so its four-request result includes queued requests.

7. Agentic workflows and function calling

This is one of the most interesting parts of the benchmark for .NET developers.

Rather than only measuring token generation, we tested complete agent-style tasks involving tool calls, structured output, and multiple conversation turns.

All results below use DFlash2.

Lower is better. End-to-end latency in seconds.

Task TensorSharp llama.cpp vLLM SGLang velox NInfer
JSON object 0.281 0.314 0.391 0.304 0.369 0.274
JSON schema 0.309 0.473 0.445 0.360 Failed 0.258
Single function call 0.199 0.218 0.354 0.171 0.383 0.180
3 parallel function calls 0.427 0.484 0.539 0.457 0.680 0.378
Agentic loop (4 turns) 0.748 0.817 1.45 0.791 1.42 0.817

Agentic workflow: TensorSharp finished first

The agentic benchmark simulated a small workflow involving file listing, file reading, and calculator operations.

The engine had to complete the tool interactions and return the correct final result.

TensorSharp finished in 748 ms, compared with:

  • 817 ms for llama.cpp
  • 1,450 ms for vLLM
  • 791 ms for SGLang
  • 1,420 ms for velox
  • 817 ms for NInfer

This is approximately 1.94× faster than vLLM and 1.90× faster than velox in this particular workflow.

For developers building .NET-based AI agents, this is arguably more meaningful than raw tokens/sec.

An agent’s responsiveness depends on the entire tool-execution loop, not just model decoding.

Structured output correctness

The benchmark also validated output correctness.

Most checks passed, with two notable exceptions:

  • velox ignored the strict JSON-schema response format in all three repetitions.
  • NInfer with DFlash2 produced an empty JSON key in one of three JSON-object replies.

One additional detail: NInfer’s JSON responses were shorter than those of the other engines, which explains part of its end-to-end latency advantage.

This is why benchmarking structured outputs should include correctness checks, not just latency.

8. Why this matters for .NET

TensorSharp is an open-source project exploring whether we can build a complete local AI inference engine and agent runtime around the .NET ecosystem.

The goal isn’t to wrap a Python inference server behind an HTTP client.

It’s to make .NET a first-class environment for model inference, with native execution backends and agent integration.

The benchmark used TensorSharp’s direct-CUDA backend, so these numbers should not be interpreted as pure managed-C# kernel performance. GPU execution and native kernels remain critical.

But the results demonstrate something useful:

A .NET-based inference stack can compete with established inference frameworks on real workloads, including speculative decoding, concurrent serving, and agentic tool execution.

There is still substantial optimization work to do.

In particular, TensorSharp’s DFlash2 draft-and-verify execution is slower than NInfer’s despite similar draft acceptance rates.

That is an actionable optimization target rather than a fundamental limitation of .NET.

9. Limitations and reproducibility

A few things worth emphasizing:

  • All measurements were performed on a single RTX 5090.
  • Different engines used different quantized checkpoints and drafter formats.
  • The benchmark used greedy decoding with thinking disabled.
  • Each scenario had three measured repetitions.
  • Differences below approximately 5% should be treated as ties.
  • The benchmark did not evaluate more than four concurrent requests, model load time, video, or broader answer quality.
  • These are operational performance comparisons, not proof that one programming language is inherently faster than another.

The benchmark uses streamed OpenAI-compatible requests and validates the responses.

The TensorSharp repository includes scripts for running the comparison and generating the performance reports:

  • eng/qwen38-engine-servers.sh
  • eng/qwen38-engine-bench.py
  • eng/qwen38-engine-report.py

GitHub: https://github.com/zhongkaifu/TensorSharp

10. Discussion

I’m the author of TensorSharp, and I’d be interested in feedback from the .NET community.

In particular:

  • Would you consider running local LLM inference directly inside a .NET application instead of depending on a separate Python-based inference service?
  • For your workloads, which matters most: TTFT, prefill throughput, decode speed, concurrent throughput, or end-to-end agent latency?
  • What would make a native .NET inference engine genuinely useful in production?

I’m also interested in suggestions for improving DFlash2 verification performance and scaling beyond four concurrent requests.

The project is open source, and contributions, benchmark reproductions, and technical feedback are very welcome.

https://github.com/zhongkaifu/TensorSharp


r/dotnet • • 1d ago

Question How do you manage your transient nuget dependencies?

48 Upvotes

For example I have the nuget "Microsoft.Data.SqlClient" Version="7.1.1" and it depends on "System.Security.Cryptography.Pkcs" Version="9.0.18" which has some kind of vulnerability. So I manually added "System.Security.Cryptography.Pkcs" Version="10.0.13" to the project.

my hope is that "Microsoft.Data.SqlClient" will upgrade their version and then reference a new/safe version of "System.Security.Cryptography.Pkcs" all on its own and go maybe even beyond Version="10.0.13" which would be the perfect time to remove my direct dependency again and rely on the transitive one. IF I still remember that I did that in the first place.

How do you deal with such issues?


r/dotnet • • 5h ago

Article .NET 8 and 9 go out of support on Nov 10. These are the .NET 10 breaking changes that don't fail the build

Post image
1 Upvotes

With .NET 8 and .NET 9 both ending support on November 10, a lot of teams are doing the LTS-to-LTS jump right now. I went through the official breaking-change lists and wrote up the ones most likely to hit a typical Web API.

The build-time ones are annoying but obvious. These are the ones that aren't:

  • Exception diagnostics are suppressed when IExceptionHandler.TryHandleAsync returns true. No ExceptionHandlerMiddleware log line, no error.type tag on http.server.request.duration. If an alert counts those logs, it goes quiet while the 500s continue. Log inside your handler, or set ExceptionHandlerOptions.SuppressDiagnosticsCallback = _ => false.
  • Cookie auth no longer redirects known API endpoints ([ApiController], JSON minimal APIs, TypedResults, SignalR). You get 401/403 with the Location header still set. [AllowCookieRedirect] or .AllowCookieRedirect() opts an endpoint back in.
  • EF Core 10 sends collections as multiple parameters (IN (@ids1, @ids2, ...) instead of OPENJSON), and parameter names changed (@status instead of @__status_0). New SQL text means every cached plan recompiles once after deploy. UseParameterizedCollectionMode or EF.Parameter() brings back the old shape for the app or for one query.
  • Default container images are Ubuntu now, and .NET 10 ships no Debian images. aspnet:10.0-bookworm-slim simply doesn't exist.
  • **dotnet restore audits transitive packages**, so NU1903 can show up for packages you never referenced. With TreatWarningsAsErrors, that fails the build.

The loud ones, for completeness: KnownNetworks → KnownIPNetworks (ASPDEPR005), Swashbuckle 10 on Microsoft.OpenApi 2.x, ExecuteUpdateAsync taking a plain lambda, and NU1510.

Two tips from the comments when I shared this elsewhere: if you'd rather keep the old exception telemetry, SuppressDiagnosticsCallback restores it everywhere; and make your pipeline read the SDK from global.json (UseDotNet@2 with useGlobalJson: true in Azure DevOps, global-json-file in GitHub Actions) so CI can't drift from local builds.

I wrote it up as a case study with before/after code and a checklist. Full disclosure: it's my blog, and the scenario is a composite built from Microsoft's documented changes, not a single real incident.

https://www.softinbit.com/dotnet-field-guide/upgrading-dotnet-8-to-10

What else bit you on the way to 10?


r/dotnet • • 3h ago

Promotion I built HttpResponseTransformer to make it easier to rewrite HTTP responses

0 Upvotes

I recently published some updates to HttpResponseTransformer, which is a NuGet package I originally published over a year ago. I’ve been meaning to share it ever since, and with the update, this seems like a good time.

The library overall lets you define targeted transform rules for outgoing HTTP responses, like manipulating raw bytes, text, and HTML. For example: csharp services.AddResponseTransformer(builder => builder .TransformDocument(document => document .When(ctx => ctx.Request.Path == "/") .InjectScript(script => script .FromUrl("/js/custom.js") .At("//head")))); The new version adds support for image transforms and caching.

The original impetus was to support a set of Jellyfin plugins called Jellyfin PowerToys. Although Jellyfin is extendable, the support for extending the UI is pretty poor. There are some community hacks, but I wanted a simple, reliable way to do it. I've found more uses for it since then; for instance, I used it to build the UI extension framework in Magpie.

I’m really happy with how the API turned out in particular. Hopefully someone else will find it useful too, let me know what you think.


r/dotnet • • 19h ago

Blazor Welcomes Open-Source Contributions from Infragistics

Thumbnail devblogs.microsoft.com
5 Upvotes

r/dotnet • • 20h ago

.NET/C# native port of libjxl

Thumbnail github.com
3 Upvotes

r/dotnet • • 1d ago

CVE-2026-111497: a Brotli decoder bug forced an out-of-band .NET release (10.0.14) on Oct 25

58 Upvotes

Microsoft released .NET 10.0.14 on 25 October as an out-of-band security update, and the stated reason is CVE-2026-111497, an out-of-bounds write (CWE-787) in the Brotli decoder bundled with .NET. CVSS 8.1, publicly disclosed, exploitation marked more likely.

Affected and fixed: - .NET 8 before 8.0.33 → 8.0.33 - .NET 9 before 9.0.22 → 9.0.22 - .NET 10 before 10.0.14 → 10.0.14 (SDK 10.0.114 or 10.0.403) - .NET Framework is not affected

The same release completes the October 13 fixes for CVE-2026-70197 (SocketAsyncEventArgs) and CVE-2026-102870 (Blazor WebAssembly debugger), which had shipped incomplete, and adds CVE-2026-114148 for Linux source-build tarballs.

Exposure needs a call path that decompresses attacker-controlled Brotli: request decompression with br enabled, HttpClient AutomaticDecompression including Brotli, or BrotliStream/BrotliDecoder on untrusted input. None of that is on by default, and response compression alone does not hit it. Until you update, dropping Brotli from those paths is a workable stopgap.

Framework-dependent apps need the host runtime updated and restarted. Self-contained apps need a rebuild and republish, and the Blazor WebAssembly Server/DevServer packages have to be bumped separately because the shared runtime update does not cover them.

Advisory: https://github.com/dotnet/announcements/issues/494 Release notes: https://github.com/dotnet/core/blob/main/release-notes/10.0/10.0.14/10.0.14.md


r/dotnet • • 1d ago

Question What Frontend framework would you pick to create a Web & Mobile App?

10 Upvotes

For only web I would easily go with blazor of course. And MAUI also seems like a nice option but I don't think it would feel as good on mobile as something like React Native.

Are there any other options, or what is your go to framework?


r/dotnet • • 1d ago

Article What changed in ASP.NET Core authentication, authorization and Data Protection in .NET 11 RC2 (from reading the source)

Thumbnail nestenius.se
44 Upvotes

r/dotnet • • 1d ago

Brotli CVE-2026-111497 now patched in .NET, VS and PowerShell. How are you finding where Brotli decoding actually happens in your apps?

54 Upvotes

Microsoft shipped fixes on 25 Oct for the Brotli decoder out-of-bounds write (CVE-2026-111497). The fixed versions are .NET 8.0.33, 9.0.22 and 10.0.14, .NET 11 RC3, Visual Studio 2019, 2022 and 2026, and PowerShell 7.4 to 7.6. Microsoft rates it 8.1 and "Exploitation More Likely". No in-the-wild exploitation has been reported yet, and the public PoC only works against a weakened build.

Per the advisories, the exposure is anywhere attacker-controlled Brotli data reaches the decoder: compressed request bodies, responses fetched from untrusted servers and compressed files. Updating the machine-wide runtime is the easy part. Self-contained deployments and container images that bundle their own runtime need rebuilding.

Has anyone found a reliable way to inventory which services actually decompress Brotli input, or are you just rebuilding everything?


r/dotnet • • 2d ago

.NET October 2026 Out-of-Band Security Updates

Thumbnail devblogs.microsoft.com
92 Upvotes

r/dotnet • • 2d ago

Article TickerQ's license change ships as a minor bump (10.4 → 10.5), so check your Dependabot/Renovate rules

50 Upvotes

Saw the license thread yesterday. One thing i havent seen mentioned is that the licensed packages don't come as a new major. On the .NET 10 line it goes from 10.4.0, wich is MIT OR Apache-2.0 on NuGet, to 10.5.0 under the new TickerQ Software License Agreement. Same on the other lines with 9.5.0 and 8.5.0.

So if your Dependabot or Renovate config only holds back majors, the next PR it opens could be the license change. And going by their licensing page, a missing or invalid license file blocks job execution, so as far as i can tell the jobs just stop rather than log a warning.

The free Community tier covers companies under USD 5 million in revenue, so alot of people will be fine there, but you still need to get the license file and wire it in with UseLicense(...). Haven't tried that flow myself.

If you want to stay on the MIT releases for now, pin it. With central package management:

<PackageVersion Include="TickerQ" Version="[10.4.0]" />

In dependabot.yml:

ignore:
  - dependency-name: "TickerQ*"
    versions: [">= 10.5.0"]

And for Renovate, a packageRule with "matchPackageNames": ["/^TickerQ/"] and "allowedVersions": "<10.5.0".

Use the right number for you're line (9.5.0 or 8.5.0 if you're on those), and do the same for every TickerQ package you reference, not just the main one.


r/dotnet • • 1d ago

How I isolated admin rights in a .NET 10 WPF app: an elevated helper limited to a closed list of operations

6 Upvotes

I maintain DrDXT, an open-source (GPL-3.0) Windows game optimizer. It has to touch system

settings, and I didn't want the UI to run elevated. So:

- the WPF UI runs as the user;

- a separate elevated helper only accepts a fixed set of bounded operations, and anything

outside the list is refused;

- each write journals the original value first, so a crash, a rollback or an uninstall

restores it.

CI runs almost 9,900 tests, plus CodeQL, on GitHub Actions.

I'm curious how others handle this. Do you use a separate service, a scheduled task, or

something else? And if anyone wants to dig in, there are good first issues:

https://github.com/ablanchard-dev/drdxt/issues

Repo: https://github.com/ablanchard-dev/drdxt


r/dotnet • • 2d ago

Promotion Kenshi Unofficial Port from C++ to .NET - Massive Performance Gain + QOL

Thumbnail youtube.com
28 Upvotes

r/dotnet • • 2d ago

Promotion I built Satori Insight, an open-source .NET heap and GC profiler with live region map

Thumbnail gallery
14 Upvotes

r/dotnet • • 2d ago

Wake up, new license rugpull just dropped — TickerQ 5.x

Thumbnail tickerq.net
125 Upvotes

r/dotnet • • 1d ago

What AI Workflow do you use?

Thumbnail
0 Upvotes

r/dotnet • • 1d ago

Question Anyone debugging a legacy VB.NET app without Visual Studio?

0 Upvotes

I maintain an older ASP.NET WebForms/Web API application written in VB.NET, targeting .NET Framework 4.8.
It runs as a 32-bit application under IIS Express.

These days I do most of my editing outside Visual Studio with help from a coding agent, so I’m wondering how much I still need VS for.

I’ve successfully built the solution from the command line using the MSBuild installed with VS 2022 Professional.
I also have a script to start IIS Express separately. That covers building and running it without opening the IDE, but I’m still using tools from the VS installation.

The part I’m unsure about is debugging.
Has anyone here used dnSpyEx for day-to-day debugging of a VB.NET web application? Can you step through the original .vb files with matching PDBs, or do you mostly work with decompiled code?
How well do breakpoints and variable inspection work?

I’m also unclear about standalone Build Tools licensing for a commercial application like this.
Does using those still require a Visual Studio license? An official reference would be helpful.

Would be interested to hear from anyone maintaining a similar application.
Is this a workable setup, or do you find yourself going back to Visual Studio whenever a server-side bug gets complicated?


r/dotnet • • 1d ago

Managed Object Internals 1

Post image
0 Upvotes

r/dotnet • • 2d ago

Promotion PdfPecker v1.20: dependency-free HTML to PDF for .NET, no Chrome, MIT

27 Upvotes

I've gotten tired of slow PDF converters, and packages that change to paid licensing, like PDFsharp just changed to AGPL from v6.5.0. So I’ve built PdfPecker over the past 2 weeks with Claude as a coding assistant, and I’ve tested and reviewed everything myself.

I've tested it to get very close to Chrome, and it's now closer than Firefox. PdfPecker matched Chrome 97% on 103 pages, compared to Firefox's 95%. It's crazy how many differences there can be when rendering HTML to PDF, I haven’t seen any two that render it the same when the pages become complex.

Main bullets:

  • Zero dependencies
  • No Chrome
  • Modern CSS
  • No JavaScript, it's built for templates you control
  • It can render from HTML to PDF in under 1ms for a typical invoice
  • Uses very little memory
  • MIT license

You can find the package on https://www.nuget.org/packages/PdfPecker

PdfPecker.Fluent has also been created to make a QuestPDF style C# API.

Getting started:

using PdfPecker;

byte[] pdf = HtmlToPdf.Convert("<h1>Hello</h1><p>World</p>");
File.WriteAllBytes("hello.pdf", pdf);

Feedback welcome, especially HTML that breaks PDF rendering.


r/dotnet • • 1d ago

More cache. Less RAM. No cache server

Thumbnail nuget.org
0 Upvotes

I wanted a bigger cache, not another Redis instance. So I built a filesystem-backed cache for .NET.

I ran into an interesting problem while working on a .NET application hosted on a VM.

The VM had plenty of disk space, but RAM was a much more precious resource. I wanted to cache a lot of data to avoid repeatedly doing expensive work, but keeping all of that data in memory wasn't particularly appealing.

The obvious options each had trade-offs.

IMemoryCache was straightforward, but I didn't want my cache capacity tied so closely to my application's memory budget.

Redis was an option, but deploying and maintaining a separate caching service felt like unnecessary infrastructure for an application that just needed a larger local cache.

I wondered: why not use the disk we already have?

So I started building a filesystem-backed implementation of .NET's IDistributedCache.

The idea is simple: keep the metadata needed to find entries in memory, but store the actual payloads on disk. Put a hard limit on storage, handle expiration and eviction automatically, and optionally preserve the cache across application restarts.

No separate server. No need to keep every cached payload in managed memory. Just a cache that can grow beyond the application's RAM budget.

I've also integrated it with .NET's HybridCache, so it can serve as a secondary cache without changing the application-level caching API.

I've been benchmarking it against other caching approaches. Redis is impressively fast, and I'm not going to pretend I've beaten it on raw latency. That's not really the point.

The interesting trade-off is capacity versus memory consumption and infrastructure complexity.

I ended up publishing it as Eryri.FileDistributedCache: https://www.nuget.org/packages/Eryri.FileDistributedCache

I'm curious how other .NET developers approach this problem.

If you had a single-instance application with plenty of disk space but a limited RAM budget, would you consider a filesystem-backed cache, or would you reach for something else?


r/dotnet • • 2d ago

Promotion MarkView.Avalonia 12.4: a native Markdown viewer for Avalonia 12 (MIT)

15 Upvotes

A few months ago, I posted about my library.

Quick description: It's a Markdown viewer control for Avalonia UI 12, built on Markdig. It renders to native Avalonia controls, with no WebView, so it behaves the same on Windows, macOS, Linux and in the browser (WebAssembly).

12.4 came out this week, with a lot of new features:

  • Streaming. viewer.BeginStreaming() returns a session you can Append text to from any thread (e.g. tokens from an AI chat) . Only the blocks still being written re-render, so scroll position, selection and focus survive every update. A half-written **bold or link renders as it will once complete, and <think> blocks fold into "Thought for 12 seconds" when they end.
  • Mermaid diagrams and LaTeX math in pure .NET (Mermaider and CSharpMath), including the \(…\) delimiters models like to emit.
  • Theme presets: GitHub, Chat (takes your message bubble's colours) and Docs. Light/dark switches live.
  • Code blocks with a copy button, and optional line numbers, wrapping and max height. TextMate highlighting is a separate package.
  • Find, folding (alerts, <details>, headings), a context menu with copy as Markdown, HTML or a table, and saving a diagram as SVG or PNG.
  • Accessibility: screen reader roles, Tab through links, WCAG AA colours and a high-contrast mode. Right-to-left text too.

Streaming is mostly intended for AI integration. With Microsoft.Extensions.AI it's a few lines:

using var session = viewer.BeginStreaming();
await foreach (var update in chatClient.GetStreamingResponseAsync(prompt))
session.Append(update.Text);

There was a lot of focus on improving the performance to make it viable in the browser (WebAssembly). It's not yet enough and the upcoming 12.4.1 version will make it even better.

Try it in your browser: https://kryptos-fr.github.io/MarkView.Avalonia/demo/

Docs: https://kryptos-fr.github.io/MarkView.Avalonia/

Repo: https://github.com/Kryptos-FR/MarkView.Avalonia

Package: https://www.nuget.org/packages/MarkView.Avalonia

If you use another Markdown control in an Avalonia or WPF app today, I'd like to know what would make you switch, or what's missing.


Full disclosure: I used Claude AI to work out the roadmap, discuss the architecture and implementation candidates. I then delegated the coding to Claude sub-agents while I did all the review and manual testing. I kept it transparent on the repo where all such commits include a "Co-authored-by: Claude" mention.

On that note, I found that Claude was very efficient when all projects have a high test coverage (currently 95%), as well as mutation testing using Stryker (also 95%). That causes some delays in CI where Stryker can take up to 3 hours but in my opinion it is worth the trouble.


r/dotnet • • 1d ago

Question Has anyone combined their backend development expertise in .NET with data engineering skills (such as Python, Databricks, PySpark, Apache spark, and data warehouse)?

0 Upvotes

r/dotnet • • 1d ago

should we use 'statelessworker' grain for reporting aggregate data?

0 Upvotes

we have a silo cluster serving our trading platform.
we have user role grains that hold user state like positions, current ProfitLoss, etc..

we need to expose for our backoffice webpage, endpoints to serve general queries like "get all positions from today"
"get all orders belong to instrument x" etc...

is there any reason to use 'StatelessWorker' for that? in our case it the statelessworker will just query the db. is it better then just using a standard .net service/singleton that would query the db?

thanks for your help


r/dotnet • • 1d ago

I'm the creator of TickerQ. Let's talk about the licensing change and what's actually changed.

0 Upvotes

Hey everyone! I'm the creator of TickerQ.

I've been reading the recent discussions about the licensing change, and I wanted to share some context and explain what's been happening behind the scenes.

First, I understand the frustration around moving away from open source. TickerQ started as a personal project, but as it grew, maintaining it properly became a much bigger responsibility.

We decided to move to commercial licensing to make development sustainable and invest more in engineering, testing, and long-term support.

Previous open-source versions remain under their original licenses, and the new release includes a free Community license for eligible users.

About the versioning confusion

Some people asked why such a big release came as a minor update.

We've always aligned TickerQ's major package versions with .NET:

  • 10.5.x → .NET 10
  • 9.5.x → .NET 9
  • 8.5.x → .NET 8

So the 5.x represents the TickerQ release generation, while the first number identifies the .NET version.

That said, I understand why introducing a licensing change in a minor update raised concerns, especially with automated dependency updates. We should have communicated this better.

What we've actually been working on

TickerQ 5.x isn't just another update. We've completely redesigned, rebuilt, and re-architected it, focusing heavily on production reliability.

A few highlights:

  • 98+ issues resolved, including stability and concurrency problems.
  • Enterprise-level testing and benchmarks to improve reliability and performance.
  • AI-powered with auto Investigate failures, recomend jobs, alert setup and much more.
  • Debug running jobs in real time, and troubleshoot issues directly from the dashboard with AI assistance.
  • Workflow orchestration with sequential and parallel execution, conditions, retries, and recovery.
  • Completely new dashboard with AI-assisted diagnostics and real-time monitoring.
  • Expanded database support including SQL Server, PostgreSQL, MySQL, MariaDB, SQLite, Oracle, CockroachDB, YugabyteDB, MongoDB, and Redis.
  • Better distributed execution and worker coordination.
  • Business calendar policies, advanced scheduling, and OpenTelemetry.
  • Slack, Microsoft Teams, and webhook integrations.

Another important change is that TickerQ is no longer a one-person project. We now have a professional engineering team working on it, with a much stronger focus on testing, maintenance, and support.

I know some people have had issues with previous versions, and I won't pretend everything was perfect. That's exactly why we invested so much effort into rebuilding it.

We're not trying to turn a small hobby library into a paid product overnight. We're trying to build something reliable that developers and companies can actually depend on long-term.

I appreciate everyone who has supported TickerQ, reported bugs, contributed, or even criticized the decisions we've made.

I know we won't convince everyone, but I wanted to explain our side rather than stay silent.

Happy to answer questions and hear your thoughts.

Changelog: https://tickerq.net/docs/5.x/changelog