How LINQPad Works

LINQPad is a client/server application with a twist. Whereas with most client/server applications, there are many clients and one server, with LINQPad there is one client and many servers!

The user interface is the client, as you might expect. For each query, LINQPad creates a separate server, which a class that runs in its own application domain and executes the query in isolation. This isolation prevents queries from interfering with each other (or the UI) and allows LINQPad to safely cancel a query (by aborting its thread) without polluting other application domains.

LINQPad Architecture

LINQPad compiles your queries using .NET's CSharpCodeProvider (or VBCodeProvider). Because C# and VB are statically typed, any database objects that you reference need the backing of a typed DataContext. For performance, LINQPad builds typed DataContexts on the fly using Reflection.Emit rather than generating and compiling source code. It uses LINQ to SQL rather than Entity Framework because LINQ to SQL is lighter and faster in building the metamodel when instantiated.

Reflection.Emit must instantiate types in memory whose assemblies cannot be unloaded. For this reason, LINQPad's emission engine itself runs in a separate application domain, which is regularly refreshed to avoid an ever-increasing memory footprint.

Because so much work goes on the background (querying database schemas, emitting typed DataContexts, compiling and then executing queries), every potentially time-intensive feature of LINQPad must operate asynchronously to maintain a responsive user interface. The interaction between the many threads that perform this work and the main thread driving the UI (with endpoints such as updating the repository tree view and autocompletion service) was one of the hardest things to get right!

LINQPad's Dump command feeds the output into an XHTML stream which it displays using an embedded web browser (you can see this by right-clicking a query result and choosing 'View Source'. The transformation into XHTML is done entirely using LINQ to XML, as one big LINQ query! The deferred expansion of results works via JavaScript, which means the XHTML is fully prepopulated after a query finishes executing. The lambda window populates using a custom expression tree visitor (simply calling ToString on an expression tree is no good because it puts the entire output on one line).

LINQPad uses a number of third-party components within the UI. The query editor uses Actipro's SyntaxEditor control (a very polished product); the "IntelliSense" features rely on a combination of libraries from Actipro Software and ICSharpCode (from the SharpDevelop project). Here's how it all fits together:

LINQPad UI

Features such as syntax highlighting, red squiggly underlines and autocompletion require that you lexically and semantically parse the source code. Lexical parsing means reading the raw text stream and breaking it up into a stream of tokens; a semantic parser then reads those tokens and figures out what they mean in context, emitting a code DOM (called an Abstract Syntax Tree). The final step is to resolve the nodes in the AST into .NET types and members.

Much of the heavy lifting is done by NRefactory and SharpDevelop.Dom, written by Daniel Grunwald, Andrea Paatz, and Mike Krüger (as part of the SharpDevelop project). These are fantastic libraries: writing a fully-featured lexical and semantic language parser in itself is no easy task; writing a well-structured type resolution DOM that can correctly handle the nuances of C# 3.0 type inference is a major achievement.

Because LINQPad ships as a single click-and-run executable, all the libraries are included as embedded resources. (Look at the last example on this page to see how). A bonus of this approach is that you can compress the libraries at the same time, reducing the executable size.

LINQPad automatically patches itself by downloading updates into its Application Data folder. It then checks that the new assembly has the same strong name, and if so, forwards to that executable, which then writes itself back to the original file. This may fail (depending on the permissions of the folder to which LINQPad was downloaded) so LINQPad always checks whether there's a later signed version of itself in its Application Data folder when started.

Over 1 million downloads

LINQPad

LINQPad

Delicious Bookmark this on Delicious

Follow LINQPad on Facebook

More

LINQPad Forum

LINQPad + Mindscape LightSpeed

LINQPad + DevForce

LINQPad + DevArt

AWS with LINQPad

Method Chaining and Debugging

LINQBugging WinForms/WPF

Terry's LINQPad Extensions

Videos

Writing queries with LINQPad
   - Hi-res QuickTime

LINQPad + EF

V2 and Beyond

Dimecasts LINQPad Intro

LINQPad + OData


LINQPad was written by Joseph Albahari
© 2007-2014. Site hosted in Windows Azure