I was recently working through some automation challenges and looked up c# scripting options. I wasn't really expecting to find any compelling solutions, but the world of .NET is evolving at a rapid rate in the last few years and thought I'd try my luck. I was pleasantly surprised when the dotnet tool dotnet-script came up in my search. I had not seen this tool before and it started me on a path of evaluation.
Why would you want to write scripts in csharp?
There are a number of available tools for scripting with c# that have been around for some time. I found one reference that indicated CS-script had it's start back in 2004.
The tools that have my interest at the moment are dotnet-script and CS-script. They both support cross platform and are current.
My recent foray into c# scripting lead me to dotnet-script. This tool seems like a good candidate for automation and as a scratch pad. The install is light and easy since you only need .Net 6 or later SDK installed as a prerequisite and you can install with dotnet tool in the cli.
In the past I've used CS-script and it is one of the most mature options that support hosting within your own application as well as CLI. It looks like the CS-script team has kept up with the newer developments with the dotnet ecosystem and this is a rich option for more complex scenarios. This is what I'd likely consider if I was going to embed scripting in to an application.
Both CS-Script and dotnet-script utilize the .csx
file extension for code files.
Some older options for c# scripting.
Why not just create a console app with top level statements instead?
It took me a bit to warm up to top level statements, but now that I've gotten used to them, I love them. It reduces the ceremony and makes .NET more accessible to engineers who have experience with interpreted languages. They also make creating quick console utilities fun and easy.
That said, there is still more ceremony with creating a project that contains several files and needs to be packaged to deploy. Where as a script file can be a standalone text file that is executed. No fancy IDE required to create a .csx file and you just need the .NET SDK installed to run the script.
Why is scripting sometimes a better option?
The down side of creating console apps for automation tasks, is that there is still a lot of ceremony with packaging and deploying them. If your not sure what I mean, try handing your DevOps team a console app to execute during your next release and let the fun begin.
In contrast, a bash script or .csx script file is relatively light weight to hand off. They have a limited number of prerequisites to install and you can easily stream the script files from source control or an S3 bucket. In addition, you are not handing off something that is opaque to run. They can open up the script file and reason through what you are doing if they feel the need.
With all that background, you are likely looking to get started with an example. Since my latest foray into c# scripting was with the dotnet-script tool, I'll show how to get started with this tool.
As a prerequisite you need to have .Net 6 or later SDK installed on your machine.
From a terminal window execute the following to install globally:
dotnet tool install -g dotnet-script
To create a script you can just create a .csx
file with notepad and add your code to it, but if you use dotnet-script to init your script, you will be set up to debug in VSCode, so I recommend that path.
create a fresh folder on your machine and make that folder the current path for your terminal window.
Then execute the following in the folder
dotnet script init
This will generate a omnisharp.json
file and a main.csx
file in the folder.
.
├── .vscode
│ └── launch.json
├── main.csx
└── omnisharp.json
You can now run this script by executing dotnet script main.csx
. You will see 'Hello World!' as the output.
I recommend opening the folder with VSCode to explore the code file at this point, but you could simply open the main.csx
file with notepad or other text editor of your choice.
There isn't much you can do in c# without referencing a NuGet package. It is quick and easy to reference a package when using dotnet-script. Prefix the line with #r
and add the name of the package and version like so.
#r "nuget: Newtonsoft.Json, 12.0.1"
This will use the NuGet sources already configured on your workstation. If you need other sources, check out the dotnet-script readme for instructions.
By now, hopefully you are ready for a more practical example that uses a NuGet package and calls an API. I've found that humor is a requirement for surviving in the software development industry, so let's create a script that tells us a joke using jokeapi.dev.
Create a file named joke.csx
in your folder next to the main.csx
file you created earlier. Then paste these contents into your joke.csx
file.
#r "nuget: Newtonsoft.Json, 12.0.1"
using System.Net.Http;
using Newtonsoft.Json;
var client = new HttpClient();
string apiURL = "https://v2.jokeapi.dev/joke/Programming?safe-mode";
var response = (await client.GetAsync(apiURL));
var json = (await response.Content.ReadAsStringAsync());
dynamic content = JsonConvert.DeserializeObject(json);
if(content.type == "twopart")
{
Console.WriteLine($"{content.setup}");
await Task.Delay(2500);
Console.WriteLine($"-> {content.delivery}");
}
else
{
Console.WriteLine($"{content.joke}");
}
You can now execute your joke script.
dotnet script joke.csx
Enjoy the Joke.
Debugging is also easy in VSCode, especially if you initialize your folder with dotnet-script. You must have the folder .vscode
at the root of your project folder and it needs a launch.json
file with configuration for .NET script.
After executing dotnet script init
in my folder I ended up with a launch.json
that looked like this.
Tip: I found that if the
.vscode
folder was not at the root level of the folder I had open in VSCode, debugging did not work.
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Script Debug",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"exec",
"C:/Users/me/.dotnet/tools/.store/dotnet-script/1.5.0/dotnet-script/1.5.0/tools/net8.0/any/dotnet-script.dll",
"${file}"
],
"cwd": "${workspaceRoot}",
"stopAtEntry": false
}
]
}
Now you can set break points in your joke.csx
file and hit F5 while the file is open to debug.
In short, I'm impressed with my experience with dotnet-script. I think it is a useful tool that I will use for automating tasks, CI/CD scripting and as a scratch pad for working through problems.
If you are a .NET Engineer and/or you are on a team that heavily uses .NET then you will find dotnet-script useful. In this scenario, you could learn a new language like Python to do these tasks, but then you have something new to maintain. If you are the only one on your team who knows the language you picked, guess who gets stuck maintaining it. Even if you get stuck as the maintainer of a dotnet-script solution, your future self will appreciate not dusting off a language you haven't used in months to make a small change.
If you are interested in getting into the world of .NET/C# or want to introduce folks to the dark side. dotnet-script is a good place to start.
If you are already skilled in Python and your team is a heavy user of that language, then I'd stick with Python. There are going to be an ocean of examples to pull from in the Python ecosystem and it was designed to do this type of task.