- Use the
dotnet new,build,runandtestcommands - Read an SDK-style
.csprojfile and set up project references in a solution - Add a NuGet package and explain where it is stored
In the C# course every program was a single app.cs file, started with dotnet run app.cs thanks to a .NET 10 feature. A real application, however, consists of several projects: a library with the business logic, a console or web app that uses it, and tests. To create them, connect them, build them and add external packages there is the .NET CLI — the dotnet command. It works the same on Windows, macOS and Linux.
The main .NET CLI commands
| Command | What it does |
|---|---|
dotnet new list | lists the available templates |
dotnet new console -n Hello | creates a console project named Hello |
dotnet build | compiles the project (into the bin/ and obj/ folders) |
dotnet run | builds and runs right away |
dotnet test | runs the test projects |
dotnet add package X | adds a NuGet package |
dotnet publish -c Release | builds a ready-to-ship version for a server or users |
dotnet --info | shows the installed SDKs and runtimes |
dotnet new console -n Hello
cd Hello
dotnet runThe template "Console App" was created successfully. ... Restore succeeded. Hello, World!
The heart of a project is the **.csproj file — XML in MSBuild format. A modern SDK-style** file contains only what matters: TargetFramework (net10.0), ImplicitUsings (adds frequently needed using directives automatically) and Nullable (warnings about null mistakes). All .cs files in the folder are included automatically. In old .NET Framework projects every file had to be listed separately:
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Student.cs" />
<Compile Include="GradeCalculator.cs" />
<!-- every new file had to be listed here -->
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project><Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Gradebook.Core\Gradebook.Core.csproj" />
<PackageReference Include="Humanizer" Version="2.14.1" />
</ItemGroup>
</Project>Solutions: several projects together
A solution is a file that groups related projects; in .NET 10 it is created by default in the new, compact .slnx format (the old .sln still works). A typical structure: Gradebook.Core — a library that depends on nothing, Gradebook.App — a console program that calls it, Gradebook.Tests — xUnit tests. A project reference (ProjectReference) lets one project see another project's classes.
- 1Create the solution and the projects
dotnet new sln -n Gradebook, then three projects from theclasslib,consoleandxunittemplates. - 2Add the projects to the solution
dotnet sln add ...— now the IDE anddotnet buildsee all three projects together. - 3Set up the references
dotnet add Gradebook.App reference Gradebook.Coreand the same command for the tests. A reference goes one way: Core does not see App. - 4Build, run, test
In the solution folder
dotnet buildbuilds everything,dotnet run --project Gradebook.Appstarts the console app anddotnet testruns the tests.
dotnet new sln -n Gradebook
dotnet new classlib -n Gradebook.Core
dotnet new console -n Gradebook.App
dotnet new xunit -n Gradebook.Tests
dotnet sln add Gradebook.Core Gradebook.App Gradebook.Tests
dotnet add Gradebook.App reference Gradebook.Core
dotnet add Gradebook.Tests reference Gradebook.CoreGradebook.slnx and three project foldersnamespace Gradebook.Core;
public static class GradeCalculator
{
public static double Average(IEnumerable<int> scores)
{
var list = scores.ToList();
if (list.Count == 0) throw new ArgumentException("No scores");
return list.Average();
}
public static string Letter(int score) => score switch
{
< 0 or > 100 => throw new ArgumentOutOfRangeException(nameof(score)),
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
>= 50 => "D",
_ => "F"
};
}Gradebook.Core/GradeCalculator.cs — a class in the library (it must be public for another project to see it)using System.Globalization;
using Gradebook.Core;
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
int[] scores = [92, 78, 85];
double average = GradeCalculator.Average(scores);
Console.WriteLine($"Average: {average:F1}");
Console.WriteLine($"Letter: {GradeCalculator.Letter((int)average)}");Average: 85.0 Letter: B
Gradebook.App/Program.cs, run with dotnet run --project Gradebook.AppNuGet packages
NuGet is the .NET package manager, and nuget.org is the repository of hundreds of thousands of ready-made libraries (like Maven Central in Java). dotnet add package Humanizer writes the latest version into the .csproj as a PackageReference; in .NET 10 the new-style dotnet package add Humanizer does the same. dotnet build or dotnet restore downloads the packages and keeps them in a shared cache in your user folder (~/.nuget/packages), and dotnet list package --outdated shows outdated packages.
using Humanizer;
Console.WriteLine("score".ToQuantity(1));
Console.WriteLine("score".ToQuantity(3));
Console.WriteLine("student".ToQuantity(12));1 score 3 scores 12 students
To share a finished program, use dotnet publish: since .NET 8 it builds by default in the Release configuration, which optimises the code (dotnet build uses Debug mode, meant for debugging). Add -r win-x64 --self-contained and the result is a stand-alone folder that runs even on a computer without .NET installed. So that everyone on the team works with the same SDK version, a global.json file is placed at the root of the repository — dotnet new globaljson creates it.
Key points
dotnet new,build,run,test,publish— one CLI for a project's whole life.- An SDK-style
.csproj:TargetFramework,ImplicitUsings,Nullable;.csfiles are included automatically. - A solution (
.slnx) groups projects, andProjectReferenceconnects them in one direction. - NuGet:
dotnet add package→PackageReference; packages are kept in the~/.nuget/packagescache. - With several projects write
dotnet run --project ...;bin/andobj/do not go into Git.
Check yourself
10 questions. Every correct answer earns XP.