C# IL Viewer for Visual Studio Code using Roslyn side project

Posted on Monday, 30th January 2017

For the past couple of weeks I’ve been working on an IL (Intermediate Language) Viewer for Visual Studio Code. As someone that develops on a Mac, I spend a lot of time doing C# in VS Code or JetBrains’ Rider editor - however neither of them have the ability to view the IL generated (I know JetBrains are working on this for Rider) so I set out to fix this problem as a side project.

As someone that’s never written a Visual Studio Code extension before it was a bit of an abmitious first extension, but enjoyable none the less.

Today I released the first version of the IL Viewer (0.0.1) to the Visual Studio Code Marketplace so it’s available to download and try via the link below:

Download IL Viewer for Visual Studio Code

Download C# IL Viewer for Visual Studio Code or install it directly within Visual Studio Code by launching Quick Open (CMD+P for Mac or CTRL+P for Windows) and pasting in the follow command and press enter.

ext install vscodeilviewer

The source code is all up on GitHub so feel free to take a look, but be warned - it’s a little messy right now as it was hacked together to get it working.

VS Code IL Viewer

For those interested in how it works, continue reading.

How does it work?

Visual Studio Code and HTTP Service

At its heart, Visual Studio Code is a glorified text editor. C# support is added via the hard work of the OmniSharp developers, which itself is backed by Roslyn. This means that in order to add any IL inspection capabilities I needed to either hook into OmniSharp or build my own external service that gets bundled within the extension. In the end I decided to go with the later.

When Visual Studio Code loads and detects the language is C# and the existence of a project.json file, it starts an external HTTP serivce (using Web API) which is bundled within the extension.

Moving forward I intend to switch this out for a console application communicating over stdin and stdout. This should speed up the overall responsiveness of the extension whilst reducing the resources required, but more importantly reduce the start up time of the IL viewer.

Inspecting the Intermediate Language

Initially I planned on making the Visual Studio Code IL Viewer extract the desired file’s IL directly from its project’s built DLL, however after a little experimentation this proved not to ideal as it required the solution to be built in order to view the IL, and built again for any inspections after changes, no matter how minor. It would also be blocking the user from doing any work whilst the project was building.

In the end I settled on an approach that builds just the .cs file you wish to inspect into an in memory assembly then extracts the IL and displays it to the user.

Including external dependencies

One problem with compiling just the source code in memory is that it doesn’t include any external dependencies. As you’d expect, as soon as Roslyn encounters a reference for an external binary you get a compilation error. Luckily Roslyn has the ability to automatically include external dependencies via Roslyn’s workspace API.

public static Compilation LoadWorkspace(string filePath)
{
    var projectWorkspace = new ProjectJsonWorkspace(filePath);

    var project = projectWorkspace.CurrentSolution.Projects.FirstOrDefault();
    var compilation = project.GetCompilationAsync().Result;

    return compilation;
}

After that the rest was relativly straight forward, I grab the syntax tree from the compilation unit of the project the load in any additional dependencies before using Mono’s Cecil library to extract the IL (as Cecil supports .NET Standard it does not require the Mono runtime).

Once I have the IL I return the contents as a HTTP response then display it to the user in Visual Studio Code’s split pane window.

Below is a simplified diagram of how it’s all tied together:

IL Viewer

As I mentioned above, the source code is all available on GitHub so feel free to take a look. Contributions are also very welcome!