Last month we released version 1.2 of dotnet-script. This was already 36th release of the tool and I am proud to say all the dotnet-script releated packages on Nuget have passed 1 million downloads - thanks a lot!
The latest release (which already has a 1.2.1 patch too), contains several useful bug fixes, including a memory leak and one excellent new feature - assembly isolation.
The installation command is the same as in previous versions – you can get ahold of dotnet-script by running the dotnet tool installation:
dotnet tool install dotnet-script -g
For existing users, the update command is relevant:
dotnet tool update dotnet-script -g
If you are using some of the dotnet-script libraries in your projects, those are, obviously, also available on Nuget.
The latest release dropped support for .NET Core 2.1, as that version of .NET Core reached the end of life.
Assembly isolation 🔗
You can now execute your scripts with a -isolated-load-context flag. This will actually use a separate AssemblyLoadContext for your script, with respect to the dotnet-script tool itself. This means that certain “own” dependencies of dotnet-script no longer conflict with your script.
The best way to illustrate this is to show an example. Consider the following script:
#r "nuget:Newtonsoft.Json, 10.0.1" using Newtonsoft.Json; var version = typeof(JsonConvert).Assembly.GetName().Version; Console.WriteLine(version);
In the default version of dotnet-script, despite the fact that you are explicitly pulling in an older version of Newtonsoft.Json, the script would actually print:
This may seem rather unexpected, but the reason for this is that the version which ships as internal dependency of dotnet-script. In many cases this doesn’t matter, but in some, the conflicts between the dependencies of dotnet-script and your app may lead to runtime errors such as for example missing method exceptions.
When this script is invoked with -isolated-load-context flag, both versions of Newtonsoft.Json - the internal one of dotnet-script, and the one of your script, peacefully co-exist in the same process - in separate load contexts - and the script prints the expected:
You can confirm that you are running in your own assembly load context by calling AssemblyLoadContext.CurrentContextualReflectionContext from the System.Runtime.Loader namespaces. This returns null by default, but would return Dotnet.Script.Core.ScriptAssemblyLoadContext when the script is executed with the -isolated-load-context flag.
Why is it not enabled by default? 🔗
Not all .NET APIs are routed to AssemblyLoadContext.CurrentContextualReflectionContext. For example, Assembly.Load is, but Assembly.LoadFrom is not and ends up always loading stuff into the default assembly load context. If you have any dependencies in your script that internally use Assembly.LoadFrom, those assemblies would not be correctly loaded into the custom load context and the script would fail.
The feature would not be possible without the excellent work by Oleksiy Gapotchenko - whose knowledge of the assembly loading space is second to none! Thanks!