DEV Community

loading...

C# scripts using dotnet-script

Galdin Raphael
Software developer. When not writing code, I'm probably reading a book, playing the piano or studying music theory.
Originally published at gldraphael.com on ・3 min read

You know how the python folks can just write some code in a .py file and run it with python3 filename.py, without going through the "new project" and the "public static void main" ceremony that C# users have to? C# can write scripts too – something I learnt just like a year back.

Roslyn made C# scripts possible. There's a Jan 2016 MSDN blogpost by Mark Michaelis titled C# Scripting if you're interested.

The tool that I've been really fascinated by is dotnet-script, which is a cross-platform .NET Core global tool with full intellisense support on VS Code via omnisharp and covers most use-cases for your experimenting needs.

Prerequisites

  1. .NET Core SDK 2.1+
  2. VS Code
  3. Official C# Extension for VS Code

Installation

First make sure you have the latest version of .NET Core SDK installed from dot.net. The minimum requirement is .NET Core 2.1.

The easiest way to install dotnet-script is installing it as a global tool:

dotnet tool install --global dotnet-script

Enter fullscreen mode Exit fullscreen mode

You should now be able to run dotnet script --version and it should print the version of the dotnet-script tool.

Hello world

  1. Create a new directory to store all your scripts.
  2. Init a new script.
  3. Run.
mkdir console
cd console
dotnet script init hello
dotnet script hello.csx

Enter fullscreen mode Exit fullscreen mode
  • The init command creates a .csx (C# script) file along with an omnisharp.json file for intellisense and a VS Code launch.json file for debug support.
  • The csx script is run using dotnet script filename.

The generated hello.csx file has the following contents:

#!/usr/bin/env dotnet-script

Console.WriteLine("Hello world!");

Enter fullscreen mode Exit fullscreen mode

The first line is a shebang that *nix users must be familiar with. It means we can run it as ./hello.csx and it'll just work! (Also works on windows, but you'll need to associate .csx files with dotnet-script first using dotnet script register.)

Another quick example

A typical use-case for console applications is to experiment with new libraries, and dotnet-script is the perfect tool for the job. Let's say I'm learning about the stateless library. Here's how I'd go about experimenting:

  1. Create a new script using dotnet script init stateless.
  2. Open the folder in VS Code using code ..
  3. Import the nuget package using the roslyn #r directive.
  4. Go to their GitHub page and copy some sample code over.
  5. Add using statements if needed using Cmd+. (or Ctrl+.).
  6. Debug within VS code with F5.

Here's my stateless.csx file:

#!/usr/bin/env dotnet-script
#r "nuget: Stateless, 4.2.1"

// Copied from: https://github.com/dotnet-state-machine/stateless/blob/dev/example/OnOffExample/Program.cs
using Stateless;

const string on = "On";
const string off = "Off";
const char space = ' ';

// Instantiate a new state machine in the 'off' state
var onOffSwitch = new StateMachine<string, char>(off);

// Configure state machine with the Configure method, supplying the state to be configured as a parameter
onOffSwitch.Configure(off).Permit(space, on);
onOffSwitch.Configure(on).Permit(space, off);

Console.WriteLine("Press <space> to toggle the switch. Any other key will exit the program.");

while (true)
{
    Console.WriteLine("Switch is in state: " + onOffSwitch.State);
    var pressed = Console.ReadKey(true).KeyChar;

    // Check if user wants to exit
    if (pressed != space) break;

    // Use the Fire method with the trigger as payload to supply the state machine with an event.
    // The state machine will react according to its configuration.
    onOffSwitch.Fire(pressed);
}

Enter fullscreen mode Exit fullscreen mode

Notes for those new to developing using VS Code:

  • If intellisense doesn't work after 3, or no code-actions are available after 5, you might need to restart omnisharp by: Cmd+Shift+P --> Omnisharp: Restart Omnisharp. See filipw/dotnet-script#424 for more information.
  • While running the application you'll most likely see this error: "Cannot read keys when either application does not have a console or when console input has been redirected." because VS Code uses the Debug Console by default which doesn't support console input. You can change that by configuring it to use the integrated terminal instead, by adding a "console": "integratedTerminal" property to .vscode/launch.json. More information here.

That's it. If you ask me I think it's pretty slick.


What I love about dotnet-script is:

  1. All relevant code, including required nuget packages, can exist in a single file.
  2. Full and reliable intellisense.
  3. Debugger support.
  4. No public static void main or .csproj files.

Discussion (5)

Collapse
jessekphillips profile image
Jesse Phillips

I don't like the idea of this. It creates a new ecosystem with a special script interpreter, luckily it sounds like it comes with the tools.

In D you still have to use the standard language structure, but the language itself doesn't require the namespace, class, and function, instead it really is just the public void main you claim is the problem, but it is not.

Collapse
galdin profile image
Galdin Raphael Author

It's roslyn, the same thing that builds the usual C# code.

Never used D. But if you have every tried teaching C# to someone that's new to programming, you'll know why freedom from public static void main is a big deal. But I'm not claiming that it's a problem.

I've always had a solution with a gazillion C# console projects only to run sample code and check new libraries out. With dotnet-script I get to have single csx files instead and I like that. If you haven't tried it yet, do give it a shot!

Collapse
hsemix profile image
Hamid Semix

Wonderful tut. I have to admit, I didn't know this was possible.

Collapse
zeslova profile image
Simon Newby

I really love the possibilities here!

Collapse
ryanfourier profile image
ryanfourier

Thanks