Skip to content

Instantly share code, notes, and snippets.

@DamianEdwards
Last active November 25, 2018 20:25
Show Gist options
  • Save DamianEdwards/f6c704230d71e0315fb4 to your computer and use it in GitHub Desktop.
Save DamianEdwards/f6c704230d71e0315fb4 to your computer and use it in GitHub Desktop.
Proposal for .NET Core CLI "new" command

.NET Core CLI: new

The new command is used to create new .NET Core projects. Projects are created using templates installed via NuGet packages.

Templates are laid out in their NuGet packages in a hierarchical fashion that enables the creation of simple trees of templates with categories that are then merged across the installed template packages to create an overall template tree. This tree allows the display of an interactive menu when creating new projects, while also allowing for direct project creation using a template node's full path, e.g. dotnet new -t aspnetcore/mvc/empty

As templates are in normal NuGet packages and installed into the standard NuGet packages folder, they can depend on other NuGet packages that are used in their templates, such that when they're installed, all the required packages to create new projects using the contained templates are installed too.

Using the Command Line

Displaying help:

~/code> dotnet new --help
    Usage:
        dotnet new
        dotnet new -t|--template <template/path> [-n|--name <ProjectName>] [[-v|--variable <Name> <Value>] [-v|--variable <Name> <Value>]]
        dotnet new <arguments>
    
    Arguments:
        -t|--template <template/path>                 The path of the template to use
        -n|--name <ProjectName>                       The name of the new project, created in current folder if not specified
        -v|--variable <Name> <Value>                  Variable to be passed to the template (can be specified more than once)
        
        -l|--list                                     Lists installed templates
        -i|--install <TemplatePackageId> [version]    Installs templates from a package with optional version
        -i|--install <TemplatePackagePath>            Installs templates from a package
        -u|--uninstall <TemplatePackageId>            Uninstalls a templates package
        -r|--restore                                  Restores installed template packages

Listing installed templates:

~/code> dotnet new --list

MS.DotNetCore.New.Templates 1.0.0
  - Console Application    [console]
  - Class Library          [classlib]

~/code> 

Installing new templates from a package:

~/code> dotnet new --install MS.DotNetCore.New.Templates.AspNetCore 1.0.0
Installing templates from MS.DotNetCore.New.Templates.AspNetCore

Installed 3 templates:
  - ASP.NET Core Empty Application          [aspnetcore/empty]
  - ASP.NET Core MVC Web Site               [aspnetcore/mvc/website]
  - ASP.NET Core MVC Web API Application    [aspnetcore/mvc/webapi]

~/code> dotnet new --list

MS.DotNetCore.New.Templates 1.0.0
  - Console Application    [console]
  - Class Library          [classlib]

MS.DotNetCore.New.Templates.AspNetCore 1.0.0
  - ASP.NET Core Empty Application          [aspnetcore/empty]
  - ASP.NET Core MVC Web Site               [aspnetcore/mvc/website]
  - ASP.NET Core MVC Web API Application    [aspnetcore/mvc/webapi]

~/code> 

Creating a new project with a specific template:

~/code> mkdir MyApp && cd MyApp
~/code/MyApp> dotnet new --template console

Created project "MyApp" in ~/code/MyApp

~/code/MyApp> cd ../
~/code> dotnet new -t console --name MyApp2

Created project "MyApp2" in ~/code/MyApp2

~/code> dotnet new -t aspnetcore/mvc/website --name MyWebApp

Created project "MyWebApp" in ~/code/MyWebApp

~/code> 

Creating a new project using the template menu:

~/code> dotnet new

  Templates
  -----------------------------------
  1. Console Application [console]
  2. Class Library       [classlib]
  3. ASP.NET Core        [aspnetcore]
  
Select a template [1]: 1
Enter a project name [Project1]: MyApp
Enter a target framework [netstandardapp1.5]: 
  
Created project "MyApp" in ~/code/MyApp

~/code/MyApp> cd../
~/code> dotnet new

  Templates
  -----------------------------------
  1. Console Application [console]
  2. Class Library       [classlib]
  3. ASP.NET Core        [aspnetcore]
  
Select a template [1]: 3

  ASP.NET Core Templates
  -----------------------------------
  1. ASP.NET Core Empty Application [aspnetcore/empty]
  2. ASP.NET Core MVC               [aspnetcore/mvc]

Select an ASP.NET Core template [1]: 2

  ASP.NET Core MVC Templates
  -----------------------------------
  1. ASP.NET Core MVC Empty               [aspnetcore/mvc/empty]
  2. ASP.NET Core MVC Web Site            [aspnetcore/mvc/website]
  3. ASP.NET Core MVC Web API Application [aspnetcore/mvc/webapi]

Select an ASP.NET Core MVC template [1]: 2
Enter a project name [Project1]: MyWebApp
Enter a target framework [netstandardapp1.5]: 
  
Created "MyWebApp" in ~/code/MyWebApp

~/code/MyWebApp> 

Authoring Templates

Templates are placed in NuGet packages in the content/templates folder. Optionally, in the root of the folder is a templates.json file that describes the templates contained and if present is used to enhance the project creation experience.

The layout allows for multi-level category nodes with template nodes as the leaves. In the case a category node contains just a single template node, that template will be automatically selected when the category is chosen.

Variables

Template files support basic variable substitution, with the only variables automatically supplied being $ProjectName$ and $RuntimeId$. Other variables can be added via the templates.json file.

Variables have an ID, question text, optional default value, and optionally conditions that must be true for the variable to be prompted for. In the case it isn't, the default value is used. The only condition supported is "rid", which checks for a match against the machine's runtime ID.

Example templates.json

Example templates.json for the default templates:

{
    "projectTemplates": {
        "console": {
            "title": "Console Application",
            "children": {
                "csharp": {
                    "title": "Console Application (C#)",
                    "variables": {
                        "framework": {
                            "question": "Please select a target framework",
                            "default": "netstandardapp1.5",
                            "conditions": {
                                "rid": ["win7"]
                            }
                        }
                    }
                }
            }
        },
        "classlib": {
            "title": "Class Library",
            "children": {
                "csharp": {
                    "title": "Class Library (C#)",
                    "variables": {
                        "framework": {
                            "question": "Please select a target framework",
                            "default": "netstandardapp1.5",
                            "conditions": {
                                "rid": ["win7"]   
                            }
                        }
                    }
                }
            }
        }
    }
}

Package Files Layout

The following demonstrates the layout of template NuGet packages. Note how templates from separate packages can share their structure such that they're templates can occupy the same parts of the resultant installed template "tree".

~/.nuget/
    packages/
        MS.DotNetCore.New.Templates/
            content/
                templates/
                    templates.json
                    console/
                        csharp/
                            title.txt
                            files/
                                Program.cs
                    classlib/
                        csharp/
                            files/
                                project.json
                                Program.cs
        MS.DotNetCore.New.Templates.VB/
            content/
                templates/
                    templates.json
                    console/
                        vb/
                            files/
                                project.json
                                Program.vb
                    classlib/
                        vb/
                            files/
                                projext.json
                                Program.vb
        MS.DotNetCore.New.Templates.AspNetCore/
            content/
                templates/
                    templates.json
                    aspnetcore/
                        empty/
                            csharp/
                                files/
                                    project.json
                                    Program.cs
                        mvc/
                            empty/
                                csharp/
                                    files/
                                        project.json
                                        Program.cs
                                        Startup.cs
                                        Controllers/
                                            HomeController.cs
                                        wwwroot/
                            website/
                                csharp/
                            webapi/
                                csharp/
    tools/
@blackdwarf
Copy link

Some comments on the above:

  • Overall, like the approach
  • The name should be an argument, e.g. dotnet new MyApp --template blah
  • The default templates (mvc, console app, class lib) should be pre-installed with the SDK. If we don't require internet for 80% of stuff for projects that you install the SDK for, then this falls into that bucket.
  • Do we need an install? Can we not just let people specify, search and error out if the template is not found.
    • I know, the above would require some gestures for discovery.
  • dotnet new should actually create the dir and the recommended layout for the project (like src and test folders and whatnot). This is the only sane thing to do.
  • Yo allows you to choose stuff. For console apps this is not needed, but do you guys want to do something similar for the mvc templates?
  • Like the nuget, but I'm scared, honestly, if this is getting too complex?

@DamianEdwards
Copy link
Author

  • The name is an argument --name|-n. If you mean it should be ordinal, that could be certainly be a thing, but I don't think we should have more than one ordinal arg, as it can get confusing having to know what order args are required in
  • The default .NET templates would be installed by the .NET Core SDK, the ASP.NET templates would be installed by the ASP.NET Core installer.
  • Scared of what? Obviously we could support more things over time, this seemed like a logical initial minimal set of features that sets a foundation and delivers the 1.0 experience we want
  • Again, if we need to be build anything at all (which we do) it seems logical it would be based on NuGet packages. That gets us our packaging, discovery, and distribution model for "free"
  • RE the src folder layout, I'm in two minds about that, but ultimately that's a question of the specific template
  • If we're going to support full framework then I'd rather not duplicate the templates but instead have them be able to prompt. That said, I don't think it's critical for v1 (i.e. not support any template questions at all)

@blackdwarf
Copy link

Replies to replies:

  • Yes, that's what I meant.
  • Good!
  • Scared of complexity in authoring. Could be that I'm overthinking it, but based on what I saw above it seems complex.
  • Agreed on Nuget being the packaging/versioning/delivery platform, don't get me wrong.
  • We should have a principle/recommendation/convention here, no?
  • Agreed, but we should think about use case for the interactive mode.
    • Though, with the above approach, the non-interactive is pretty easy to get also...

@DamianEdwards
Copy link
Author

The package authoring is pretty easy. Templates are just "content" from the NuGet perspective, which is one of the concepts NuGet supports. You layout your templates in the folder and optionally drop a templates.json file for more metadata. The folder layout is used to drive the template list/tree. That's basically it.

@blackdwarf
Copy link

Ah, ok. :) So I was overthinking it. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment