The dotnet CLI and Solutions

Creating projects, adding packages from NuGet, formatting code, and grouping several projects into one solution.

Syntaxdotnet package add <PACKAGE_NAME> [-v|--version <VERSION>]

dotnet is one command with many subcommands, and they all arrive with the SDK. There is nothing extra to install.

Creating and referencing

dotnet new <template> creates a project from a template; dotnet new list prints the templates, among them console, classlib, webapi and xunit. dotnet package add <name> adds a package: a library someone else published. It writes a PackageReference line into the .csproj and then restores. Packages come from NuGet, the public .NET package gallery at nuget.org. .NET 10 documents the noun-first order, dotnet package add; the older dotnet add package still works and is what you will see in most existing scripts.

Where restored packages live

Restore downloads each package once into a shared folder, not into your project: ~/.nuget/packages on macOS and Linux, %userprofile%\.nuget\packages on Windows. dotnet nuget locals all --list prints the paths.

Solutions

A solution is a list of projects that belong together, so one command can build or test all of them. dotnet new sln -n Shop creates it and dotnet sln Shop.slnx add Api/Api.csproj adds a project.

Formatting

dotnet format rewrites your code to match the rules in an .editorconfig file. dotnet format --verify-no-changes edits nothing and exits with a failure code if any file would have changed, which is the form a build server should run.

Example

Example · csharp
// Program.cs of the Api project, created and wired up with:
//   dotnet new sln -n Shop
//   dotnet new console -o Api
//   dotnet sln Shop.slnx add Api/Api.csproj
//   dotnet format Api/Api.csproj
//
// From the solution folder, this project is started with:
//   dotnet run --project Api
Console.WriteLine("Api started.");
Console.WriteLine("Shop.slnx lists the projects that build together.");

// Output:
// Api started.
// Shop.slnx lists the projects that build together.

When to use it

  • Adding a database driver to a service and recording the version in source control.
  • Grouping an API project, a shared library and a test project so one command builds all three.
  • Failing a continuous integration build when code is not formatted, without changing the files.
  • Finding where a restored package's files actually sit on disk.

More examples

A solution with two projects

This is the layout almost every real service grows into: an application project, one or more libraries, and a test project. A project reference is what lets Api use types written in Shop.Core.

Example · bash
dotnet new sln -n Shop            # creates Shop.slnx on .NET 10 and later
dotnet new console -o Api         # the service
dotnet new classlib -o Shop.Core  # shared code, no entry point

dotnet sln Shop.slnx add Api/Api.csproj Shop.Core/Shop.Core.csproj

cd Api
dotnet add reference ../Shop.Core/Shop.Core.csproj
cd ..

dotnet build Shop.slnx            # builds every project in the solution
dotnet sln Shop.slnx list         # prints what is in it

Adding a package and finding where it went

Use this whenever you need a library you did not write, such as a database driver. The listing matters during a disk-space or corrupted-cache investigation, because the packages are in that one shared folder and not inside your repository.

Example · bash
dotnet package add Npgsql
# Writes a <PackageReference Include="Npgsql" ... /> line into the .csproj
# and then restores the package.

# Pin an exact version when you need to:
#   dotnet package add <name> --version <version>

dotnet package list                       # what this project references
dotnet nuget locals global-packages --list
# info : global-packages: /Users/you/.nuget/packages/

Formatting, and checking formatting in CI

Run dotnet format before you commit, and --verify-no-changes in the pipeline. The second form is what keeps formatting arguments out of code review without a build step that quietly edits the repository.

Example · bash
dotnet new editorconfig            # an .editorconfig with the .NET defaults
dotnet format                      # rewrite files to match it

# For a build server: changes nothing, fails if anything is unformatted.
dotnet format --verify-no-changes

Discussion

  • Be the first to comment on this lesson.