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

· 1031 words · 5 minutes to read

Last week, together with [Bernhard][1] we released version [0.16 of dotnet-script][2], 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.

~$ dotnet script
> var x = 1;
> x+x
2

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:

~$ dotnet script
> var x = new List<string>();
> x.Add("foo");
> x
List<string>(1) { "foo" }
> x.Add("bar");
> x
List<string>(2) { "foo", "bar" }
>

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.

~$ dotnet script
> #r "nuget: Automapper, 6.1.1"
> using AutoMapper;
> typeof(MapperConfiguration)
[AutoMapper.MapperConfiguration]
> #load "nuget: simple-targets-csx, 6.0.0";
> using static SimpleTargets;
> typeof(TargetDictionary)
[Submission#0+SimpleTargets+TargetDictionary]
```

### 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.

    ~$ dotnet script
    > class Foo {
    * public string Bar {get; set;}
    * }
    > var foo = new Foo();

### 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: ```csharp var msg = "Hello World"; Console.WriteLine(msg); ``` When you run this with the _-i_ flag, _Hello World_ is printed, REPL starts and _msg_ variable is available in the REPL context. ~$ dotnet script foo.csx -i Hello World > 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: ~$ dotnet script > #load "foo.csx" Hello World > ### _#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][3] . ``` └── contentFiles └── csx └── netstandard2.0 └── main.csx ``` 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 _#load_directive. The following example loads the [simple-targets][4] package that contains script files to be included in our script. ```csharp #! "netcoreapp2.0" #load "nuget:simple-targets-csx, 6.0.0" using static SimpleTargets; var targets = new TargetDictionary(); targets.Add("default", () => Console.WriteLine("Hello, world!")); Run(Args, targets); ``` > 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][5]. ### 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_.

About


Hi! I'm Filip W., a software 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