Robin Rottier
Robin Rottier's Blog


Robin Rottier's Blog


.NET 5 - C#9 - Underwhelmed by top level code and a custom project template to create it

Robin Rottier's photo
Robin Rottier
·Jan 19, 2021·

7 min read

A new feature of C#9 is 'top level code' ... that is code you can just write without having to decorate with a namespace, a Program class and a static void Main function, all just to make your one line call to Console.WriteLine("Hello World!").

This means that instead of this from the default Console template...

using System;

namespace helloworld
    class Program
        static void Main(string[] args)
            Console.WriteLine("Hello World!");

you could just have

using System;
Console.WriteLine("Hello World!");

or even just a single line if you get rid of the using, replaced by fully specified call to System.Console instead.

BUT whats the point? No-one (or very few people I'm sure) ever type in all that boiler plate code ... you would just create a default project and start from there.

SO, yes top level code is a bit neater and terser and a bit more of a quick prototyping approach but until the tools send you there very easily I'm not sure how it gets used.

Custom templates

BUT if you really like that terser starting point then you could save your own template and use it to directly create the simple project and top level program code.

Using .NET CLI, just edit the files as above or add a bit more you want in this template. Build it and check its what you want.

Then in the project folder create a folder called .template.config, then create a file in there called template.json, edit it so...

  "$schema": "",
  "author": "John Smith",
  "classifications": [ "Common", "Console" ],
  "identity": "somecompany.somename.consoletlc",
  "name": "Console Application With Top Level Code",
  "shortName": "consoletlc",
    "tags": {
        "language": "C#"
  "preferNameDirectory": "true",
  "sourceName": "helloworld"

The key parts to that as follows: $schema schema id...its fixed so just use it like that author your name classifications is a list of descriptions applicable to this template - could also be "web" for example identity a unique name for this template...not sure exactly the rules for this so make something up that looks like a namespace with your company and /or name in it name a descriptive name for the template shortName a short name that can be used in a dotnet new command ... so something useful, easy to type and remember is good tags is a list of specific tags for this template, again used when searching, and language is specifying the language used. preferNameDirectory and 'sourceName' enable simple substitution to replace any text in the source with the new project name and to call the new project the new project file the same as the project directory.

Your directory structure will be like this: ...\helloworld\ helloworld.csproj Program.cs .template.config\ template.json

In project root directory, run this dotnet command to 'install' the template...

dotnet new -i .

. being the location of the .template.config folder or use the full path if you are not in the directory itself.

The output of the command should be like a listing of all the templates and you should see the new consoletlc listed.

Next, cd to a new location away from that template and you can use that short name in a new command...

cd ..
md helloworld2
cd helloworld2
dotnet new consoletlc

Dir the directory to confirm helloworld2.csproj, and type Program.cs to check it's as expected with the namespace changed to helloworld2.

If the point of this is to enable quickest startup for a new project with top level code then maybe even give it a short shortName so long as you can remember it and use it quickly (dotnet new tlc maybe?)

In Visual Studio, you can duplicate the same process, having created the stub as above that you want to template, select project and 'export template' menu option. HOWEVER note that Visua Studio and dotnet cli do not seem to naturally share the same list of user templates and there is a setting under Environment-Preview Features to enable it.

Once a template has been installed it can be uninstalled using the equivalent -u flag - except note that it has to have a full path to the directory containing .template.config.

And also if the templates get really messed up you can do dotnet new --debug:reinit to reset back to the installed state.


That's it! You now how a (locally saved) template that can be used to create a quick project with top level code file.

Template creation and use of course nothing specifically to do with top level code as such ... much more complex and useful templates could be created as starting points for projects in your workflow.

BUT to me, its the top level code that needs a template to create it and get used. Perhaps Microsoft is thinking that a .cs file will eventually be build-able and run-able directly as is -- without even a project file or the explicit separate build step i.e. just like a scripting language.


Some Microsoft resources around templates:

Share this