Using Newtonsoft.Json in a Visual Studio extension

Mads Kristensen

Mads

The ever popular Newtonsoft.Json NuGet package by James Newton-King is used throughout Visual Studio’s code base. Visual Studio 2015 (14.0) was the first version to ship with it. Later updates to Visual Studio also updated its Newtonsoft.Json version when an internal feature needed it. Today it is an integral part of Visual Studio and you can consider it a part of the SDK alongside other Visual Studio assemblies.

Extensions can therefore also use the very same Newtonsoft.Json shipped with Visual Studio. It can, however, be confusing to know what version to reference and whether to ship the Newtonsoft.Json.dll file itself with the extension or not. And what if the extension supports older version of Visual Studio that doesn’t come with Newtonsoft.Json?

I promise it’s not confusing once you know how, so let’s start at the beginning with versioning.

Versioning

Just like any other Visual Studio SDK assemblies, extensions must reference lowest version matching the lower bound of supported Visual Studio versions. For instance, if the extension supports Visual Studio 14.0, 15.0, and 16.0, then it must reference the 14.0 SDK assemblies. The same is true for referencing Newtonsoft.Json, but it is less obvious to know what version shipped when.

Here’s the breakdown:

  • Visual Studio 16.0 – Newtonsoft.Json 9.0.1
  • Visual Studio 15.3 – Newtonsoft.Json 9.0.1
  • Visual Studio 15.0 – Newtonsoft.Json 8.0.3
  • Visual Studio 14.0 – Newtonsoft.Json 6.0.x
  • Visual Studio 12.0 – none

So, if your extension’s lowest supported Visual Studio version is 14.0, then you must reference Newtonsoft.Json version 6.0.x. In fact, make sure the entire dependency tree of your references doesn’t exceed that version.

Learn more about Visual Studio versioning in the blog post Visual Studio extensions and version ranges demystified.

Binding redirects

When referencing a lower version of Newtonsoft.Json than ships in Visual Studio, a binding redirect is in place to automatically change the reference to the later version at runtime. Here’s what that looks like in the devenv.exe.config file of Visual Studio 15.0:

It makes sure that when an assembly references a version of Newtonsoft.Json that is older than 8.0.0.0, it automatically redirects to use the 8.0.0.0 version that ships in Visual Studio 15.0.

This is the same mechanism that makes it possible to use an SDK assembly such as Microsoft.VisualStudio.Language.Intellisense version 12.0 in Visual Studio 16.0. A binding redirect automatically changes the reference to the 16.0 version of that assembly.

Don’t ship it unless you need to

The rule of thumb is to not ship the Newtonsoft.Json.dll file in the .vsix container. Since Visual Studio always have a copy and does binding redirects, there is no reason to ship it.

However, there are two scenarios where you do want to ship the .dll with the extension.

  1. If your extension supports Visual Studio 12.0 or older
  2. If you absolutely need a newer version than shipped by Visual Studio

When supporting Visual Studio 12.0 or older, try to use Newtonsoft.Json version 6.0.x if possible. That ensures that when the extension runs in Visual Studio 14.0 and newer, then the .NET Framework won’t load the assembly from your extension, but instead use the one it ships with. That means fewer assemblies needed loading by the CLR.

If you ship your own version, then don’t expect to be able to exchange Newtonsoft.Json types with other assemblies in Visual Studio because they were compiled against a different version. Normally binding redirects unifies the versions, but not when shipping your own. Also specify a code base for it so Visual Studio can resolve it at runtime. You don’t always need to, but it’s considered best practice and avoids any issues. Simply add this line to your AssemblyInfo.cs file:

It’s very important that you never add your own binding redirect for Newtonsoft.Json.dll either. Doing so will force all assemblies in the Visual Studio process to redirect to the version you ship. This might lead to unpredictable issues that could end up breaking other extensions and internal components.

Follow the simple rules

So, the simple rules to apply when using Newtonsoft.Json are:

  1. Reference the lowest version of Newtonsoft.Json (but no lower than 6.0.x)
  2. Don’t ship Newtonsoft.Json.dll in the extension
    1. Except if you target Visual Studio 12.0 or older
    2. Except if you absolutely need a newer version than ships in Visual Studio
    3. If you do, specify a code base for it
  3. Don’t ever add binding redirects for Newtonsoft.Json.dll

I wrote this post based on feedback and questions about how to correctly reference Newtonsoft.Json from an extension. I hope it helped clarify it. If not, please let me know in the comments.

Mads Kristensen
Mads Kristensen

Senior Program Manager, Visual Studio Extensibility

Follow Mads   

5 Comments
Avatar
Alin Constantin 2019-03-21 00:06:25
Many thanks! Great timing, just one day later after publishing I needed this info :-). It was driving me crazy why all other referenced assemblies got packed and deployed by vsix for a project I was writing, just not Newtonsoft.Json 12.0. I was already going on the path of adding it explicitly as vsixmanifest asset... Downgrading the nuget package to 9.0.1 saved me some time!
Avatar
Jon Mikel Inza 2019-03-22 15:42:08
Thanks Mads. Useful and clear. This VS strong dependency is pretty understandable. However, is Microsoft working on easing the use of newer Newtonsoft.Json.dll versions (> 9.0.1) for the extensions (as if we were using any other reference/NuGet package)? Having to add the dll directly to the VSIX package does not sound ideal for many reasons.
Avatar
Jon Miller 2019-03-27 06:32:09
If I remember correctly, Microsoft is giong to be including a new JSON parser in .NET Core 3? One that is more efficient and does less memory alllocations. I'm wondering if VS will be moving to that? I assume not, considering it probably uses features that won't be available to the .NET Framework. Will VS be ported to .NET Core? I'm wondering if the new JSON parser will support schema validation. Newtonsoft charges for this. IMHO something this fundamental should come with the .NET platform free of charge, like it did with XML.
Francesco Colombo
Francesco Colombo 2019-03-29 04:46:41
Hi Mads and thank you for your blog post about VS extensions and Newtonsoft.Json.I'm looking for some help about this topic. I'm currently working on a VS2015 ext which includes SignalR.Core.Client. SignalR use a newer version of NW.Json, so I need to ship my ext with that newer version. Unfortunatelly I'm having no success on this. When I try to connect the SignalR client to a server I get an exception like this:Could not load file or assembly 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The system cannot find the file specified.File name: 'Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'Any idea on this?
Avatar
Matt Whitfield 2019-03-29 14:07:20
The problem with this is that it isn't always practical to reference a lower version - as many third party libraries will force you on to newer versions (even though they don't make use of newer functionality). There is also another dimension to this, which you haven't touched on - which is what framework version we are allowed to reference for different versions. Newtonsoft.Json has literally forever shipped breaking the rules on assembly strong naming - i.e. that two assemblies with the same strong name should be the same. Looking at the currently shipping 12.0.1 - the assemblies in the net35 and net45 folders share the same strong name, even though the public API isn't 100% the same. So if someone installs the net35 version in the GAC, then you can expect a MissingMethodException or similar if you rely on the net45 version... So some guidance around what we can expect in terms of .NET Framework version support would be good.