Using Roslyn refactorings with OmniSharp and Visual Studio Code

ยท 624 words ยท 3 minutes to read

One of the features that we added to a recent OmniSharp release (which, as a reminder, backs the C# language services in various editors), and that quietly shipped in C# for Visual Studio Code 1.10.0 last week, was the ability to use external Roslyn refactorings.

Before, OmniSharp shipped with some built-in Roslyn refactorings (i.e. move type to file) but this new feature allows a user to import custom refactorings - either self- or 3rd-party built.

It’s still an experimental feature, so it needs to be switched on manually, but hopefully it can provide you some much neeeded productivity boost.

Let’s have a look at how that’s done.

The concept of a global refactoring ๐Ÿ”—

Refactorings in Roslyn - contrary to analyzers/code fixes - are not installed into the project in the form of an analyzer reference, but rather they are globally available in the IDE.

In Visual Studio, that means installing a refactoring (or a package containing multiple refactroings) as a VSIX. There are several popular ones - for example Roslynator or Code Cracker. They both contain tens of refactroings that boost C# development productivity a lot and typically do the job you might have gotten used to with Resharper.

For example:

  • initialize fields/properties from constructor parameters
  • change if into switch and vice versa
  • change for into foreach/LINQ and vice versa
  • collapse an object into object initializer syntax
  • converting members to expression-bodied ones
  • and many moreโ€ฆ

The equivalent of globally installing such an extension in OmniSharp world is to use OmniSharp configuration and set up a RoslynExtensionsOptions location path.

There are a number of ways to do that, but the easiest is to use omnisharp.json file. In order to address all of your projects, update the global configuration file at %USERPROFILE%/.omnisharp/omnisharp.json. This works on all platforms - Windows, OS X and Linux.

{
    "RoslynExtensionsOptions": {
        "LocationPaths": [
            "C:/refactorings/roslynator",
            "C:/refactorings/my-refactorings"
        ]
    }
}

In addition to that, you can also configure a local omnisharp.json file, at the root of your solution’s folder - such configuration would only apply to that project then.

You can read in detail about how to have granular control over OmniSharp’s settings in the project wiki - cause there are a few other ways.

Usage ๐Ÿ”—

OmniSharp will pick up the DLLs from the folders configured via RoslynExtensionsOptions.LocationPaths configuration array and find the refactorings in them. Then, the discovered refactorings will be enabled for use in the editor. The process of getting OmniSharp to correctly recognize the refactorings is two-fold:

  1. when you download a VSIX with refactorings, you will have to actually extract it (VSIX is just a ZIP file), as OmniSharp will only scan for DLL files at the moment
  2. You should remove any Visual Studio specific DLLs from that folder. For example Roslynator contains Roslynator.VisualStudio.Core.dll and Roslynator.VisualStudio.dll inside the VSIX - they are VS specific and must be deleted, otherwise they will interfere with the MEF services inside OmniSharp.

And this is it. You should be able to benefit from the refactorings as you launch Visual Studio Code.

Hopefully, this can improve your productivity with Visual Studio Code quite a bit.

Future ๐Ÿ”—

At the moment, the technique described in this article allows you to load externally configured refactorings built with Roslyn. There are two other types of code aware libraries - diagnostic analayzers and code fixes. Diagnostic analyzers are not supported (yet). Actually, code fixes are also loaded by OmniSharp at the moment, but because they can only be presented in response to a diagnostic, they are not surfaced in the editor in any way right now.

Both diagnostic analayzers and code fixes can be loaded in Visual Studio globally (via VSIX) and in a project scope (as analyzer references). Both of those scenarios are on the future roadmap for OmniSharp.

About


Hi! I'm Filip W., a cloud architect from Zรผrich ๐Ÿ‡จ๐Ÿ‡ญ. I like Toronto Maple Leafs ๐Ÿ‡จ๐Ÿ‡ฆ, Rancid and quantum computing. Oh, and I love the Lowlands ๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP