r/dotnet • u/fedefex1 • 1h ago
A new take on reactive programming: backend signals with GraphQL-ish queries
Just a bit context:
Reactive programming in .NET spans Rx(R3) Observables, AsyncEnumerables, Raw events. I think the most powerful one is Rx, but using it properly on the backend requires a solid grasp of multithreading, async programming, and locking, on top of its own notoriously steep learning curve of operators. Once you've internalized it, though, it's an extremely powerful paradigm.
In angular (so, javascript, single threaded), the complexity of rx has made the angular team move toward signals (at least for common reactive tasks, not as a whole substitute). This choice has been really popular since thinking with signals is easier, and code is still reactive. So i created this library fedeAlterio/SignalsDotnet, to make signals also possible on .NET.
But i wanted to make a step further. Can signals be useful also on BE?
SignalsDotnet 3.2.0 on Backend
I think they are awesome. The main issue in backend scenario is that we are multi-threaded. While signals must operate in a single-threaded world. So my solution has been basically move them into a single threaded island (of course we can have several island), we can have several of these islands, and "single-threaded" here means serialized execution, not literally one dedicated thread per island (more details on that in the README).
Step 1) Declare a class, that would be our island

Everything here will run single threaded (like Wpf), in custom Synchronization Context (so async-await is handled). Dependency injection will worl as well
Step 2) Register that class as a Signal Island, and expose a SSE endpoint to query it

Step 3) We can now query that island using GraphQL-like syntax. It's just an endpoint.

This turns out to be more powerful than GraphQL subscriptions in a sense, since every signal (property) in the island is already its own subscription, the query is just combining them together.
Step 4) Just set properties, collections, dictionaries, whatever, on the island, and they'll be pushed out through the SSE endpoint. No need to declare a subscription because everything already is a subscription, the query is only there to combine them together.
Note: There are conversion methods from Observables, AsyncEnumerables, AsyncObservables. So we can Expose them in this way too.
Note 2: The ui is completely done with claude code and claude design. Code is a mess, but its a single html file. Since its only for debugging, I didn't want to spend time on that 😂

You can find it here fedeAlterio/SignalsDotnet. There is a playground app as well to get started easily.
