New Features - General
- LINQPad's tab control, toolbar, and menu renderer have been rewritten for better performance, appearance and dark-theme rendering.
Icons have been updated for greater consistency with Visual Studio, and are drawn with theme-optimized scalable graphics.
Dark theming has also been improved in a number of other areas, including commonly used dialogs, data grids and autocompletion tooltips.
- LINQPad's toolbar includes a new dropdown to set the transaction isolation level for queries that use LINQ-to-SQL or EF Core connections.
This can function with or without a transaction, and works by automatically issuing a SET TRANSACTION ISOLATION LEVEL command immediately
after LINQ-to-SQL or EF Core opens a connection.
(Working without a transaction in the read-committed or snapshot isolation levels is useful for querying a database without blocking updates.)
You can also set a per-connection default by right-clicking the combo, and set/override the isolation level programmatically via
the
Util.TransactionIsolationLevel
property.
- LINQPad has a new toolbar button to automatically generate a description when dumping.
You can also access this behavior programmatically by calling DumpTell instead of Dump.
To make this feature enabled by default for new queries, right-click the button and choose the option on the context menu.
When active, you can still override the description by calling
Dump("heading")
- or Dump("")
for no heading.
- You can now render Avalonia controls directly inside LINQPad, just by dumping them.
For samples, press Ctrl+F1 and type Avalonia.
- LINQPad now restores both modified and unmodified queries after closing and shelving.
There's also now an Always Shelve button directly on the Exit dialog.
- There's a new item on the File menu to restart LINQPad (shortcut Ctrl+Alt+Shift+Delete). This will restore all queries that were open.
- You can now press Ctrl+Plus to navigate forward in the editor. Ctrl+Shift+Minus also works, if used after a Navigate Back.
- LINQPad's interactive authentication engine now uses a custom UI host for better reliability and compatibility with the latest authentication schemes.
It can also now propagate tokens across multiple process boundaries, so a query that you execute via
Util.Run
will not re-authenticate unnecessarily.
- LINQPad now includes a self-diagnostic tool for monitoring latency and blockages on the UI thread. Should you experience an issue, go to Help | Start Internal Profiling -
this will generate a report that you can send to tech support. There's also a new Process Monitor to monitor the memory and CPU usage of each query,
as well as the host process.
-
Util.HtmlHead.AddScript
now supports a type attribute. There's also now a Util.HtmlHead.AddRawHtml
method for additional flexibility.
- The EF Core driver supports DateOnly/TimeOnly type mappings with EF Core 8+. You can switch this feature on or off via a checkbox in the connection dialog.
- LINQPad's EF Core connection dialog lets you specify compatibility level for SQL Server connections, to mitigate the
breaking change in EF Core 8.
- When you try to save a read-only file, LINQPad now presents a dialog with options to save to a different file, or overwrite anyway (after a second confirmation).
You can also now make a query read-only or writable via context menu options on the query tab.
- LINQPad 8 always loads queries into noncollectible Assembly Load Contexts, to maximize compatibility with third-party libraries.
- Autocompletion's member info tooltips now show exception tags.
New Features - Excel Interop
LINQPad has a new Excel export engine that generates native .xlsx content instead of relying on HTML or CSV.
This ensures reliable handling of DateTimes and extended Unicode characters, the preservation of
leading zeros in string data (such as phone numbers), and allows for the generation of multi-sheet workbooks.
It also works in environments that block Excel's HTML import feature for security reasons.
You can access the Excel export engine interactively in any of the following ways:
-
(new) by clicking the ellipses on a table in the Results view
- via the Export menu option on the Results toolbar
- by right-clicking a Data Grid
You can also export data programmatically by calling the .ToSpreadsheet
extension method, followed by Open
or Save
:
customers.ToSpreadsheet().Open();
salesQuery.ToSpreadsheet().Save ("salesQuery.xlsx");
The Save
method does not require Excel to be installed on the machine.
You can include multiple sheets in a single workbook by calling the fluent .AddSheet
method:
customersQuery
.ToSpreadsheet ("Customers")
.AddSheet (ordersQuery, "Orders")
.AddSheet (profitsQuery, "Profit and Loss")
.Save (@"c:\temp\export.xlsx")
.Open();
Spreadsheets can also be populated manually:
var sheet = new Worksheet // Worksheet is in the LINQPad.Spreadsheet namespace.
{
[1, 1] = "Revenue",
[1, 2] = "Expenses",
[1, 4] = "Profit",
[2, 1] = 150230,
[2, 2] = 25010,
[2, 4] = new Cell { Formula = "B1-B2" }
};
sheet.Open();
// or sheet.Save ("filepath");
This is much faster than using COM interop to populate a spreadsheet, because no round-tripping takes place.
For more samples, press Ctrl+F1 and type Excel.
Architectural Changes
- LINQPad 8's query and daemon process launcher has been redesigned to use the startup executable, with a redirection
taking place within a custom CLR host. This makes LINQPad friendly to environments that block executables that reside
outside the Program Files folder, as well as reducing the chance of triggering antivirus software into blocking or
slowing their startup. This also means that to whitelist the LINQPad process, you now need to specify only the startup executable.
- LINQPad no longer uses the soon-to-be-removed .NET binary serialization engine in any capacity; instead, it now uses a custom-written
replacement that recognizes the same attributes. This means that
Util.Cache
still works to cache data between
executions when types get recompiled between executions, as long as you apply the [Serializable] attribute when requested.
- LINQPad's host and command-line runner now targets .NET 6+. LINQPad.Runtime, however, still targets .NET Core 3.1, so that you can interactively
run code under .NET Core 3.1 and .NET 5 (which some restrictions, described in the following section). Dependencies of LINQPad.Runtime that
require .NET 6+ have been moved to a separate internal library that resolves automatically via an internal dependency injection mechanism.
- LINQPad has a new assembly resolution mechanism for the host and command-line runner that has greater authority when versioning
discrepancies occur between the the host and framework libraries (and their transitive dependencies). This has allowed for a
refresh of LINQPad's internal libraries, while still supporting a range of .NET versions.
Deployment
LINQPad 8 requires at least one of the following runtimes:
- .NET 8 (Desktop)
- .NET 7 (Desktop)
- .NET 6 (Desktop)
If none of these have been installed, LINQPad will bootstrap the installation of .NET 8. If multiple runtimes have been installed, you can choose which to use on a per-query basis via a dropdown in the toolbar. (You can also set a global default in Edit | Preferences.)
LINQPad 8 also lets you run queries under .NET 5 and .NET Core 3.1, with the following limitations:
- .NET 8/7/6 must also be installed.
- X64 disassembly and C# 1.0 decompilation is unavailable.
- Util.Run and LPRun.exe do not work under .NET 5 or .NET Core 3.1.
Should you need these features, you can run LINQPad 7 side-by-side.
The xcopy-deployable version of LINQPad 8 ships with the following launchers:
LINQPad8-x64.exe // for X64
LINQPad8-x86.exe // for X86 - choose this if you need to reference native 32-bit DLLs
LINQPad8-arm64.exe // for ARM64 machines such as Surface Pro X
It is recommended that you rename/copy the launcher that corresponds to your native platform to LINQPad8.exe.
LINQPad's launchers are custom CLR hosts. This allows them to bind the host to the optimum .NET version, and bootstrap the installation of .NET if no suitable version has been installed.
The command-line launchers are as follows:
LPRun8-x64.exe // X64
LPRun8-x86.exe // X86
LPRun8-arm64.exe // ARM64
It is recommended that you rename/copy the launcher that corresponds to your native platform to LPRun8.exe (the installer does this for you automatically).
Custom CLR hosts and include logic on the unmanaged side to determine which .NET version to spin up.
Instead of looking for a .runtimeconfig.json file, the command-line launchers locate and examine the .linq query that you want to run.
If you chose a specific .NET version in the toolbar when you wrote the query, this will have been saved to the .linq file, and this choice
will be honored. Otherwise the launcher parses the user-preferences file for your default framework choice.
You can also specify/override the .NET version with LPRun8's -fx
switch:
LPRun8 -fx=8.0 (query-to-run) // Run query under .NET 8.0
LPRun8 -fx=7.0 (query-to-run) // Run query under .NET 7.0
LPRun8 -fx=6.0 (query-to-run) // Run query under .NET 6.0
EF Core 8.0
LINQPad 8 supports Entity Framework Core 8.0 (as well as older versions). LINQPad's EF Core driver understands the compatibility matrix between
versions/subversions of .NET and EF Core, and if necessary, will switch your query to the closest compatible .NET version (with a warning).
Licensing
To enable the Premium features of LINQPad 8, you will need to upgrade your license to Version 8 (unless you purchased recently.)
A LINQPad 8 license works for all older versions of LINQPad, too.
Running LINQPad versions side-by-side
For .NET Framework support, you can continue to run LINQPad 5 side-by-side with LINQPad 8.
Here are some tips to help you with sharing queries between LINQPad 5 and LINQPad 8:
- Any .NET Framework assembly references are ignored in LINQPad 8.
- Other assembly references may cause difficulties unless they are to .NET Standard libraries. NuGet package references are the best option.
- For conditional compilation, the NETCORE symbol is defined in LINQPad 8 but not LINQPad 5.
-
My Extensions is separate for LINQPad 5 and 8, so each can have different implementations and dependencies.
As long as you provide textually similar methods in both, queries will work with both.