A demo from 2022 that sends LINQ queries from a client to a server over HTTP. You write a normal-looking fluent query on the client (Where, OrderBy, Skip, Take), the expression trees get serialized to bytes, posted to a generic API controller, rebuilt into an IQueryable<T> on the server, and run against EF Core + SQLite. Two different clients — a Blazor WebAssembly app and a plain console app — talk to the same backend with the same query code. It was written to play with the idea, not to ship.
The core trick is moving a LINQ query across the wire instead of building a custom endpoint per query shape.
- A fluent builder,
Linq<T>(BlazorCausality/Linq.cs), collects calls like.Where(...),.OrderBy(...),.ThenBy(...),.Skip(n),.Take(n),.Distinct(), and.Include(...)into an orderedList<Query>. - Each predicate is a real
Expression<Func<T, bool>>(orFunc<T, object>), serialized with Serialize.Linq over aBinarySerializer. The list is then JSON-serialized and POSTed to<entity>/get. - On the server,
GenericController<T, C>(BlazorCausalityServer/GenericController.cs) deserializes the query list back into expression trees, replays them onto the entity'sIQueryablein order viaConcatAndBuildQuery, and returns the result. It logs the SQL EF Core produced withqueryable.ToQueryString()so you can see what actually hit the database. - The same
MessageBroker : Linq<Message>type runs from both the Blazor client and the console app, so the query-building code is shared, not duplicated per host.
Honest about scope: GetById, Insert, Update, and Delete exist on the client repository and controller, the query side only supports the operators listed above, and there's a large block of commented-out experiments (Join, SelectMany, Select, string-based OrderBy) left in Linq.cs showing where the author was poking. Error handling mostly swallows exceptions and returns null or an empty list — fine for a playground, not for production.
- .NET 6 (
net6.0) across all six projects - Blazor WebAssembly (hosted model) for the web client
- ASP.NET Core for the server host
- Entity Framework Core 6 with the SQLite provider
- Serialize.Linq 2.0.0 for expression-tree serialization
- Newtonsoft.Json 13 for the query envelope
- Serilog for server-side logging of the generated SQL
Note: the EF Core and ASP.NET Core WebAssembly packages are pinned to .NET 6 rc.1 preview versions (e.g. 6.0.0-rc.1.21452.10), which is what dates this repo. Restoring may need those preview packages available.
| Project | What it is |
|---|---|
BlazorCausality |
The library. Linq<T> builder, ClientRepository<T>, ServerRepository<T, TDataContext>, the Query/LinqType envelope, expression serialization extensions, EntityBase. |
BlazorCausalityServer |
Server-side query rebuilding: GenericController<T, C> and QueryExpression<T>. |
Shared (blazor.Shared) |
The shared Message entity (Id, UpdatedDate from EntityBase, plus Subject and Body). |
Client (blazor.Client) |
Blazor WebAssembly app that lists messages. |
Server (blazor.Server) |
ASP.NET Core host: serves the Blazor app, wires ApplicationDbContext to SQLite, registers the Message controller. |
blazor.Console |
Console app that runs the same Where(...).OrderBy(...).ToListAsync() against the running server and prints the rows. |
The SQLite file (Server/sqlite.db) and the EF migration for the Message table are committed, so the data is there on clone.
You need the .NET 6 SDK.
In Visual Studio (the path the original README describes):
- Open
BlazorCausality.sln. - Set multiple startup projects:
blazor.Serverfirst, thenblazor.Console. - Confirm the server runs on
https://localhost:7199. If it picks a different port, update the base address inblazor.Console/Program.cs(line 10) to match. - Run without debugging. The Blazor app and the console app both come up against the same backend and the same local SQLite database.
From the CLI:
# build everything
dotnet build BlazorCausality.sln
# terminal 1 — start the server (serves the Blazor client too)
dotnet run --project Server/blazor.Server.csproj
# terminal 2 — once the server is on https://localhost:7199, run the console client
dotnet run --project blazor.Console/blazor.Console.csprojThe console app prints each Message it gets back; the Blazor client lists them at /. If the server lands on a port other than 7199, change the BaseAddress in blazor.Console/Program.cs before running the console app.
A 2022 proof-of-concept, last touched April 2022. The library carries a 0.1.4-beta version and the preview-SDK pins were never updated. It works for the message query path it demos; the commented-out Join/SelectMany work was never finished. Treat it as an experiment in serializing LINQ across the wire, not a maintained library.
Johan Olofsson, Noisy Cricket AB (noisycricket.se) johan.olofsson@noisycricket.se
The open-iconic font/icons bundled under Client/wwwroot/css/open-iconic/ ship under their own font and icon licenses (see the FONT-LICENSE and ICON-LICENSE files there).