C# REPL for .NET Core 2.0 and #load support from Nuget – dotnet-script 0.16 is out!

Last week, together with Bernhard we released version 0.16 of dotnet-script, the .NET Core 2.0 C# script runner. I’d like to summarize the new features in this short blog post – as there are two highlights of this release – which we are very excited about!

The project now offers a C# REPL (interactive mode) which can be access when launching dotnet-script without any arguments. All the features of scripting are supported in the interactive mode, including support for adding Nuget references via #r “nuget: {package}”.

The second large feature is support for #load “nuget: {package}”, which works similar to its #r counterpart, except not for assemblies but for referencing CSX files from Nuget.

REPL overview

The REPL mode (“interactive mode”) is started by executing dotnet-script without any arguments.

The interactive mode allows you to supply individual C# code blocks and have them executed as soon as you press Enter. The REPL is configured with the same default set of assembly references and using statements as regular CSX script execution.

Once dotnet-script starts you will see a prompt for input. You can start typing C# code there.

If you submit an unterminated expression into the REPL (no ; at the end), it will be evaluated and the result will be serialized using a formatter and printed in the output. This is a bit more interesting than just calling ToString() on the object, because it attempts to capture the actual structure of the object. For example:

Inline Nuget packages in REPL

REPL also supports inline Nuget packages – meaning the Nuget packages can be installed into the REPL from within the REPL. This is done via our #r and #load from Nuget support and uses identical syntax.

REPL Multiline mode

Using Roslyn syntax parsing, we also support multiline REPL mode. This means that if you have an uncompleted code block and press Enter, we will automatically enter the multiline mode. The mode is indicated by the * character. This is particularly useful for declaring classes and other more complex constructs.

REPL commands

Aside from the regular C# script code, you can invoke the following commands (directives) from within the REPL:

Command Description
#load Load a script into the REPL (same as #load usage in CSX)
#r Load an assembly into the REPL (same as #r usage in CSX)
#reset Reset the REPL back to initial state (without restarting it)
#cls Clear the console screen without resetting the REPL state
#exit Exits the REPL

Seeding REPL with a script

You can execute a CSX script and, at the end of it, drop yourself into the context of the REPL. This way, the REPL becomes “seeded” with your code – all the classes, methods or variables are available in the REPL context. This is achieved by running a script with an -i flag.

For example, given the following CSX script:

When you run this with the -i flag, Hello World is printed, REPL starts and msg variable is available in the REPL context.

You can also seed the REPL from inside the REPL – at any point – by invoking a #load directive pointed at a specific file. For example:

#load with Nuget support (“Script packages”)

On the heels of our #r from Nuget for referencing Nuget packages, we are now introducing #load with Nuget support. It allows you to reference a Nuget package containing not assemblies, bur other CSX files and consume them directly against your script.

Script packages are a way of organizing reusable scripts into NuGet packages that can be consumed by other scripts. This means that we now can leverage scripting infrastructure without the need for any kind of bootstrapping.

Creating a script package

A script package is just a regular NuGet package that contains script files inside the content or contentFiles folder.

The following example shows how the scripts are laid out inside the NuGet package according to the standard convention .

This example contains just the main.csx file in the root folder, but packages may have multiple script files either in the root folder or in subfolders below the root folder.

When loading a script package we will look for an entry point script to be loaded. This entry point script is identified by one of the following.

  • A script called main.csx in the root folder
  • A single script file in the root folder

If the entry point script cannot be determined, we will simply load all the scripts files in the package.

The advantage with using an entry point script is that we can control loading other scripts from the package.

Consuming a script package

To consume a script package all we need to do specify the NuGet package in the #loaddirective.

The following example loads the simple-targets package that contains script files to be included in our script.

Note: Debugging also works for script packages so that we can easily step into the scripts that are brought in from Nuget. Intellisense support for this feature requires the new (upcoming) version 1.28.0 of OmniSharp.

NuGet.config support

Inline package references now respect a local NuGet.config file. You can now create a NuGet.config file in the same folder as your CSX script and the inline packages will be installed using the sources from the NuGet.config.

Share the post!