.NET Development with JetBrains Rider: Inspections, Decompiler, Database Tools and Angular
Rider combines the ReSharper engine, DataGrip's database tools and WebStorm's Angular support in one IDE; but the tool isn't magic: the SQL EF Core generated for SQLite didn't run in the database console because of the ef_compare function. Settings layers and .editorconfig precedence, the decompiler and Source Link, Explain Plan, the Endpoints window, dotUltimate, what Rider 2026.2 added and .NET 10 file-based apps, with real output.
Version note: The code in this post was built and run with .NET 10 SDK (Software Development Kit) 10.0.402, Microsoft.EntityFrameworkCore.Sqlite 10.0.14 and SQLite 3.54. JetBrains Rider 2026.2 is not installed on this machine (macOS), so it was not run; Rider's features, menu names and shortcuts (default Windows keymap) come from JetBrains' Rider 2026.2 documentation and official blog. We show the work you would do in the database console by running the same SQL (Structured Query Language) on the sqlite3 command line.
Guess First
You want to see the SQL of a query that has slowed down in Bookstore. You get it from Entity Framework Core (EF Core) with ToQueryString() and paste it into the IDE's (Integrated Development Environment) database console to run it and look at its plan. The query looks for books priced above 40, and the database is SQLite. Do you think the SQL EF generated runs as is outside the application, in the database tool?
In this post we tour JetBrains Rider through the eyes of a .NET + Angular developer: the ReSharper engine and settings layers, the decompiler and Source Link, the built-in database tools, the WebStorm features for Angular, the dotUltimate tools and what 2026.2 brought.
The ReSharper Engine and Settings Layers
Rider has two parts: a front end built on the IntelliJ platform, and a backend process running the ReSharper engine that does the C# analysis. The inspections, quick-fixes and Solution-Wide Error Analysis we saw in the fourth post come from this backend; JavaScript, TypeScript and SQL support come from the parts of the IntelliJ platform that also power WebStorm and DataGrip.
Settings that come from ReSharper are layered. According to the docs, the icon on a settings page tells you which mechanism it uses: pages without an icon are IDE settings stored in the user profile, while layer-based settings are written to the "This computer", "Solution personal" and "Solution team-shared" layers. The two solution layers live in .DotSettings files in the solution folder; the team-shared one is committed to the repo, the personal one is not. These layers are compatible with ReSharper, so you share the same inspection settings with a teammate using ReSharper in Visual Studio. The most important rule is spelled out in the docs: code style and inspection settings defined in .editorconfig override every layer. Putting team rules into .editorconfig and ReSharper-specific preferences that have no .editorconfig equivalent into the team-shared layer avoids conflicts.
Decompiler, Source Link and Assembly Explorer
When you use Go to Declaration (Ctrl+B) on a method inside a NuGet package or the framework, Rider has to take you somewhere; where depends on the settings and on whether PDB (Program Database, the symbol file) information is available. Rider has four explicit targets: Assembly Explorer, Decompiled Sources, Metadata View and Sources from Symbol Files. The default behavior is chosen under Settings > Tools > External Symbols.
If the package's PDB contains Source Link information, Sources from Symbol Files downloads the original source file from the commit it was built from: with comments, real variable names and line numbers. Without Source Link, the built-in decompiler produces C# from IL (Intermediate Language); it is readable, but there are no comments or local variable names, and async methods and LINQ (Language Integrated Query) queries look close to what the compiler generated. Assembly Explorer lets you open and browse any assembly outside the solution. The same mechanism works during debugging: when you step into framework code, Rider stops in decompiled or Source Link sources. We saw how Source Link is produced in your own project, with real output, in the fifth post of the Debugging series.
When it helps: to read a library's behavior that its docs don't describe (for example, why an HttpClient handler swallows an exception) instead of guessing. When it doesn't: copying decompiled code into your own code is a separate licensing matter; use it for reading.
Inspecting EF Core's SQL with the Database Tools
Rider ships the Database Tools and SQL plugin, which provides all of DataGrip's features, bundled and enabled by default; it connects to SQL Server, PostgreSQL, MySQL, SQLite and others. The Database window is Ctrl+W, X in the default keymap. The query from Guess First:
IQueryable<string> query = db.Books
.Where(b => b.Price > 40m && b.Author.Name.StartsWith("Andrew"))
.OrderBy(b => b.Title)
.Select(b => b.Title);
// the SQL you would paste into the IDE's database console
Console.WriteLine(query.ToQueryString());
SELECT "b"."Title"
FROM "Books" AS "b"
INNER JOIN "Authors" AS "a" ON "b"."AuthorId" = "a"."Id"
WHERE ef_compare("b"."Price", '40.0') > 0 AND "a"."Name" LIKE 'Andrew%'
ORDER BY "b"."Title"
The Pragmatic Programmer
Inside the application the query ran. Pasting the same SQL into the database tool:
$ cat query.sql
SELECT "b"."Title"
FROM "Books" AS "b"
INNER JOIN "Authors" AS "a" ON "b"."AuthorId" = "a"."Id"
WHERE ef_compare("b"."Price", '40.0') > 0 AND "a"."Name" LIKE 'Andrew%'
ORDER BY "b"."Title";
$ sqlite3 bookstore.db < query.sql
Parse error near line 1: no such function: ef_compare
The answer to Guess First: no. ef_compare is a function EF Core registers on its own SQLite connection; because SQLite doesn't know the decimal type, EF stores the price as text and does the comparison with this function. The table's schema shows it:
$ sqlite3 bookstore.db '.schema Books'
CREATE TABLE "Books" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Books" PRIMARY KEY AUTOINCREMENT,
"Isbn" TEXT NOT NULL,
"Title" TEXT NOT NULL,
"Price" TEXT NOT NULL,
"AuthorId" INTEGER NOT NULL,
CONSTRAINT "FK_Books_Authors_AuthorId" FOREIGN KEY ("AuthorId") REFERENCES "Authors" ("Id") ON DELETE CASCADE
);
CREATE INDEX "IX_Books_AuthorId" ON "Books" ("AuthorId");
We removed the provider-specific function and looked at the plan of the rest of the query; in Rider, the Explain Plan action in the database console gives the same information as a table:
$ cat plan.sql
EXPLAIN QUERY PLAN
SELECT "b"."Title"
FROM "Books" AS "b"
INNER JOIN "Authors" AS "a" ON "b"."AuthorId" = "a"."Id"
WHERE "a"."Name" LIKE 'Andrew%'
ORDER BY "b"."Title";
$ sqlite3 bookstore.db < plan.sql
QUERY PLAN
|--SCAN b
|--SEARCH a USING INTEGER PRIMARY KEY (rowid=?)
`--USE TEMP B-TREE FOR ORDER BY
The Books table is scanned from start to finish (SCAN b) and a temporary B-tree is built for sorting. Since the price filter is done with a function over text, an index wouldn't help either. The fix for this finding isn't in the IDE but in the model: the EF Core series' posts on mapping decimal per provider and on index design are the place for that. The IDE's contribution is seeing the SQL, the schema and the plan in one window without leaving the application code.
HTTP Client and the Endpoints Window
Rider has a built-in HTTP (HyperText Transfer Protocol) Client that runs .http files; the run button next to the request line in the editor sends the request and shows the response in a separate panel. The Endpoints window (View > Tool Windows > Endpoints) lists the client and server APIs (Application Programming Interface) in the project for HTTP and WebSocket in one place and jumps to an endpoint's declaration with F4; you can also add external sources such as OpenAPI specifications. The syntax of .http files and how they compare with tools like Postman and Bruno are the subject of the upcoming API Tools series.
Angular: WebStorm Features Inside Rider
Rider ships WebStorm's JavaScript, TypeScript and Angular support in the box; unlike Visual Studio Code (VS Code), you don't install a separate Angular extension. Completion, navigation and rename in Angular templates, switching between a component and its template, ESLint and Prettier integration, npm run configurations created from package.json scripts, and the JavaScript debugger are all in the same IDE. Rider 2026.2 supports the TypeScript 7 compiler rewritten in Go; JetBrains writes that in its own test on a large codebase project load time dropped from about 12 seconds to 3 (a vendor measurement). With the compound configuration from the previous post you can debug the API and Angular with one click.
There is a trade-off: JetBrains' own Angular support runs instead of Angular's Language Service. When a new Angular feature appears (such as new template syntax), support depends on Rider's release schedule; the Angular team's VS Code extension is usually updated the same day as Angular itself.
dotUltimate: dotTrace, dotMemory, dotCover
A dotUltimate subscription includes ReSharper, dotTrace (performance profiler), dotMemory (memory profiler), dotCover (code coverage) and dotPeek (standalone decompiler) alongside Rider; in Rider the profilers and coverage start from inside the IDE and the results are linked to the code in the editor. Rider 2026.2 also added agent skills that let AI (Artificial Intelligence) agents read dotTrace snapshots and dotCover data. The method of profiling and the comparison of dotTrace with the Visual Studio Profiler are the subject of the upcoming Profiling and Diagnostics in .NET series; here it is enough to know where the tool lives.
What Rider 2026.2 Brought
The headlines of 2026.2, released on July 22, 2026, that matter to a .NET developer, from JetBrains' release announcement:
- Performance: on Windows the debugger starts about 2.8 seconds faster for .NET apps, branch switching in Roslyn-based solutions is generally 2 to 3 times faster, and backend processes use 7 to 8 percent less memory (vendor measurements).
- WPF (Windows Presentation Foundation) Hot Reload: in a WPF app running under the Rider debugger, XAML (Extensible Application Markup Language) changes are applied in place on save.
- A redesigned NuGet window: browsing, installed packages and updates now have separate paths.
- A C# file-based app template, intention previews, built-in Azure Functions support and an Azure DevOps pull request window.
- On the AI side: GitHub Copilot built into the agent picker, Microsoft's .NET, Aspire and Azure agent skills installable from the IDE, and quality-check hooks for Claude Code that stop the agent from finishing while there are compilation errors. Covered in detail in the ninth post.
File-based apps are a .NET 10 feature; Rider's template only makes creating them easier. A single .cs file without a project file is a perfect fit for small in-repo tools:
#!/usr/bin/env dotnet
#:property Nullable=enable
// a repo utility: list books whose stock is below the threshold
int threshold = args.Length > 0 ? int.Parse(args[0]) : 5;
(string Isbn, int Quantity)[] stock = [("978-0135957059", 3), ("978-0132350884", 12), ("978-0201616224", 0)];
foreach ((string isbn, int quantity) in stock.Where(s => s.Quantity < threshold))
{
Console.WriteLine($"{isbn}: {quantity}");
}
$ dotnet run low-stock.cs -- 5
978-0135957059: 3
978-0201616224: 0
$ dotnet run low-stock.cs -- 1
978-0201616224: 0
$ chmod +x low-stock.cs
$ ./low-stock.cs 4
978-0135957059: 3
978-0201616224: 0
$ dotnet project convert low-stock.cs
$ ls low-stock
low-stock.cs
low-stock.csproj
When the tool grows and needs to become a real project, dotnet project convert moves it into a folder next to a .csproj.
In Production
Memory settings for large solutions. Rider's front end runs on the JVM (Java Virtual Machine); the default JVM options live in the installation folder, and the docs tell you not to change that file, because it is overwritten on update and on macOS editing it breaks the application signature. The right way is to create a copy in the configuration folder with Help > Edit Custom VM (Virtual Machine) Options, or to use Help > Change Memory Settings. Remember that the backend process has its own memory consumption and that SWEA (Solution-Wide Error Analysis) grows both in large solutions.
Review the team-shared layer like code. The .DotSettings file is XML (Extensible Markup Language) and hard to read by hand; a change that sets an inspection to "Do not show" looks like an innocent one-line diff in a pull request.
The decompiler and Source Link need the network. In a closed enterprise network without access to the symbol server and the source server, Rider falls back to the decompiler; that is normal, but know that the code you see is not the original source.
Common Pitfalls
Mixing up the team-shared and personal layers. Saving a personal preference to the team-shared layer changes the whole team's inspections; saving a team decision to the personal layer keeps it valid only on your machine. Check the layer selection next to the Save button when you save.
Forgetting that .editorconfig and the layers conflict. The docs are clear: .editorconfig always wins. If a style setting you changed in Rider "doesn't work", look at .editorconfig first.
Running EF's SQL as is in the database tool. Real output: the SQLite provider's ef_compare function doesn't exist outside EF. For parameterized queries, ToQueryString() also emits the parameters as variable definitions; read the SQL before pasting it into the console.
Editing the default JVM options file. The change is lost on update and on macOS the signature breaks; use Edit Custom VM Options.
A Small Experiment
★☆☆ Take the ToQueryString() output of an EF Core query in your own project and run it in the database tool. Does a provider-specific function or parameter definition show up?
★★☆ Use Go to Declaration on a method of a NuGet package you use. Did the source come from Source Link or from the decompiler? How do you tell whether the package's PDB contains Source Link information?
★★★ Turn a recurring script in your repo (data seeding, a report) into a .NET 10 file-based app, use a NuGet package with #:package, and run it in CI (Continuous Integration) with dotnet run tool.cs. When it grows, convert it to a project with dotnet project convert.
We have met Rider. In the next post we move to the extension world of the three IDEs: extensions that actually help, Settings Sync, the recommended extension list in the repo, and the security consequences of the fact that extensions run with your permissions.