Hitchhiker’s Guide to the C# scripting

We know C# as a programming language, but it’s been a couple of years since we can write scripts with our beloved language, CSharp! Let’s start the journey.

Ali Bahraminezhad
ITNEXT

--

Background

C# scripting was introduced into .NET community together with the Roslyn CTP back in October 2011. The primary idea behind C# scripting was to allow for code to be dynamically evaluated at runtime. While there have been other technologies allowing that in the past (Reflection.Emit, CodeDOM etc.), Roslyn took this concept to new heights by introducing scripting — using not the regular strict C#, but a relaxed version of C# language semantics.

Reference:
https://blogs.msdn.microsoft.com/cdndevs/2015/12/01/adding-c-scripting-to-your-development-arsenal-part-1/

Did you use C# for writing your scripts? Some people might disagree with the idea of writing scripts in C# since there are other script-oriented tools like bash, power-shell and sometimes Python.

However,

Imagine, you have libraries or codes that are working fine in your backend, and you need to write some scripts to automate plenty of jobs. For this reason, you don’t have to learn PowerShell or any other scripting lang!

  • ✔ Works with all good libraries (Newtonsoft.JSON, Security and all assemblies)
  • ✔ You don’t need to learn a new language
  • ✔ Cross-platform (Mac, Linux, Windows, Raspberry Pi …)

Getting started with C# scripting

Scripting in CSharp ain’t a big deal; it’s the same C# you use every day in your robust applications.

Structure of C# script file

  1. C# scripting files are just plain-text files with the extension of .csx
  2. With #r "path of a DLL assembly" preprocessor-directives you can reference every DLL to the script
  3. Every C# code works inside the file, from implementing a class to using a namespace

Here is an example of simple CRX file:

Just a glimpse of the code, as you can see you can do everything!

But it’s csx file. How are you going to execute it? To write the script you need to have a specific tool. There are a couple of them such as:

  • Roslyn Mono CSI (if you install Visual Studio or Mono SDK you will have it on your OS)
  • dotnet-scripts global dotnet tool
  • cs-scripts

I’m going to explain all of the tools I mentioned above then, in the end, we are going to compare them.

Running script with Mono/Roslyn CSI

I have installed Mono SDK on my OS, so I can access csi.exe directly via the command line! You can check if it’s on the path or not with where or whereis command.

C:\>where csi
C:\Program Files\Mono\bin\csi
C:\Program Files\Mono\bin\csi.bat

The first argument of CSI command is the csx file.

> csi sample-job1.csxHello World!
Hello World, This file is created at 19/12/2019 11:40:37

Since it runs the file in interpreter mode, it takes one second. Now let’s reference some assembly to CSX file.

I downloaded Assembly dll of Newtonsoft.Json and put it next to my CSX file.

> csi sample-job2.csx{"Id":"5611f423-9819-4f02-887e-4d39e9a9b0b8","Name":"FooBar","Enabled":true}

I used JsonConvert.SerializeObject method to serialize a dummy object.

💡 If you just open csi app it will execute a repl in terminal and you can execute C# codes line by line.

C:\>csi
Microsoft (R) Visual C# Interactive Compiler version 3.3.1-beta4-19462-11 ()
Copyright (C) Microsoft Corporation. All rights reserved.
Type "#help" for more information.
> var message= "Hello World";
> Console.WriteLine(message);
Hello World
>

How about referencing NuGet packages?

Unfortunately, CSI doesn’t support NuGet. So you have to download and put the DLL assembly next to your script manually. But as I’ve already mentioned, there are other tools that they support NuGet as well.

📒 Make sure you installed dotnet runtime/sdk on your platform.

▶ Dotnet-Script global tool

One of the best things about dotnet core CLI is its global tools. You can read about them here. In a nutshell, they are just a special NuGet package that contains a console application. A Global Tool can be installed on your machine on a default location that is included in the PATH environment variable or on a custom location.

This tool can be installed like this:

> dotnet tool install -g dotnet-scriptYou can invoke the tool using the following command: dotnet-script
Tool 'dotnet-script' (version '0.50.1') was successfully installed.

dotnet-script tool has built-in NuGet support! So you can easily use this directive to reference any NuGet package your like.

#r “nuget: PackageId, version”// for e.g:
// #r “nuget: Newtonsoft.Json, 12.0.3”

Make sure you set the version because dotnet-script will cache the package for the next executions and this will make the script running more faster!

The first launch is a bit slow because it’s going to download the NuGet package with its dependencies!

> dotnet script sample-job3.csx{"Id":"5f14b3be-d634-414d-95e2-b015fda6d383","Name":"FooBar","Enabled":true}

The result is still the same, right?

One of the big advantages of dotnet-script is scaffolding which helps you create a folder for your script with launch settings for your beloved VSCode!

> dotnet-script initCreating VS Code launch configuration file
...'\path\.vscode\launch.json' [Created]
Creating OmniSharp configuration file
...'\path\omnisharp.json' [Created]
Creating default script file 'main.csx'
Creating 'main.csx'
...'\path\main.csx' [Created]

With this configuration, you can run and debug your code inside VSCode!

▶ Script-CS- makes it easy to write and execute C# with a simple text editor.

Compare to dotnet-script and CSI, Script-CS is a bit different. The only way to install it is via Chocolaty which is a windows package installer.

# install it with chocolatycinst scriptcs

After installation, you have access to scripts command in CMD. By typing scripts in the cmd the scriptcs-repl will run, which let you enter C# codes line by line:

C:\>scriptcs
Moving directory '.cache' to '.scriptcs_cache'...
scriptcs (ctrl-c to exit or :help for help)
> var message = "Hello World";
> Console.WriteLine(message);
Hello World
>

For installing NuGet packages, you can use -install argument. This should execute inside your script folder.

C:\>scriptcs -install Newtonsoft.JsonInstalling packages...
Installed: Newtonsoft.Json
Package installation succeeded.
Saving packages in scriptcs_packages.config...
Creating scriptcs_packages.config...
Added Newtonsoft.Json (v9.0.1, .NET 4.5) to scriptcs_packages.config
Successfully updated scriptcs_packages.config.

Writing code in ScriptCs is not really different from the others, here is an example:

And execute it like:

C:\>scriptcs sample-job2.csx{"Id":"e3a9d76e-d558-46d1-8d1a-b831c8013e16","Name":"FooBar","Enabled":true}

Referencing assemblies and the rest is the same as others with #r directive.

Debugging

It’s too bad the article does not mention how to debug such a script in an actual IDE when it’s needed…
https://www.reddit.com/r/csharp/comments/ectt1v/hitchhikers_guide_to_the_c_scripting/fbe2l1g?utm_source=share&utm_medium=web2x

You cannot debug your scripts with CSI but Script-CS and Dotnet-Script offer the debugging, although Script-CS debugging is tricky requires Visual Studio and an extension that’s not 100% percent compatible with the latest Visual Studios. In this section, I only cover dotnet-script debugging.

  1. Initialize a new script with dotnet-script scaffolder
> mkdir foo-bar> cd foo-bar> dotnet-script init foobar
Creating VS Code launch configuration file
...'\foo-bar\.vscode\launch.json' [Created]
Creating OmniSharp configuration file
...'\foo-bar\omnisharp.json' [Created]
Creating 'foobar'
...'\foo-bar\foobar.csx' [Created]

Install VSCode if you haven’t installed it already, then open the folder of the script like this:

code .

If this is the first time you are going to open any .cs or .csx file the VSCode is going to install C# Extension and Omnisharp it takes less than a minute. Now you can easily set breakpoints and Press F5 to run and debug your script!

Example of debugging in VSCode

Which one to use?

.-----------------.------.-------.----------------.--------.
| Name | Repl | Nuget | Cross-Platform | Debug |
:-----------------+------+-------+----------------+--------:
| Mono/Roslyn CSI | Yes | No | Yes | No |
:-----------------+------+-------+----------------+--------:
| Script-CS | Yes | Yes | No | Yes(1) |
:-----------------+------+-------+----------------+--------:
| Dotnet-Script | Yes | Yes | Yes | Yes |
'-----------------'------'-------'----------------'--------'
1. Script-CS supports debugging but it requies complete Visual Studio and it's not easy to do

In my humble opinion, dotnet-script is the best option, it has many other features such as compiling to exe but again it’s just my humble opinion, it’s always up to you and your needs and you need to see which tool solves your problems better.

References

These are a couple of references I used to get the background of C# scripting.

  1. Introducing the Microsoft “Roslyn” CTP
  2. Adding C# scripting to your development arsenal

If you liked my article please take a lot on my other articles about C#

--

--

Writer for

I’m a geek, a software engineer who likes to build amazing stuff 😉Here on Medium I write about different things but mostly focused on programming and .NET!