Skip to content

Expert · Testing, tooling and Unity · topic 38 of 43 · 25 min

NuGet packages, solutions and project structure

Explanation

NuGet is .NET's package manager: dotnet add package downloads a library from nuget.org and records it as a PackageReference in your .csproj. A solution file groups several projects, such as an API, a class library and a test project, and project references connect them. Choosing packages carefully and keeping them updated is part of keeping an app secure.

What is a package?

A package is ready-made code that someone else wrote and shared, bundled as a .nupkg file. NuGet is the tool and nuget.org is the public gallery with hundreds of thousands of packages: database providers, logging, PDF generation, Excel export, payment SDKs. Using a well-maintained package saves weeks of work.

bash
dotnet add package Serilog.AspNetCore
dotnet list package
dotnet list package --outdated
dotnet list package --vulnerable
dotnet remove package Serilog.AspNetCore
add downloads the package and edits the .csproj. --outdated shows newer versions; --vulnerable shows packages with known security advisories.
xml
<ItemGroup>
  <PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
  <ProjectReference Include="..\Shop.Core\Shop.Core.csproj" />
</ItemGroup>
PackageReference pins a package and version; ProjectReference points to another project in your solution. dotnet restore (run automatically by build) downloads what is listed. Version numbers here are examples.

Choosing a package safely

  • Check downloads, recent updates and the owner on nuget.org. A package last updated years ago may not work with your .NET version.
  • Check the licence. Some popular libraries changed to commercial licences for business use in recent years, so read the licence before adding one to a company project.
  • Watch for look-alike names (typosquatting) such as Newtonsoft.Jsonn. Copy the exact name from nuget.org.
  • Prefer what .NET already includes: System.Text.Json, ILogger and HttpClient cover many needs without extra packages.
  • Run dotnet list package --vulnerable regularly and update.

Solutions and multiple projects

Real applications are split into several projects. A solution groups them so that dotnet build, dotnet test and your IDE treat them as one unit. Newer SDKs may create the newer, simpler .slnx solution format instead of the classic .sln; both work with the dotnet commands and Visual Studio.

bash
dotnet new sln -n Shop
dotnet new webapi    -o src/Shop.Api
dotnet new classlib  -o src/Shop.Core
dotnet new xunit     -o tests/Shop.Tests

dotnet sln add src/Shop.Api src/Shop.Core tests/Shop.Tests
dotnet add src/Shop.Api reference src/Shop.Core
dotnet add tests/Shop.Tests reference src/Shop.Core

dotnet build
dotnet test
A common layout: an API project, a core class library with the business rules, and a test project.
output
Shop/
  Shop.sln (or Shop.slnx)
  src/
    Shop.Api/          endpoints, Program.cs, configuration
    Shop.Core/         entities, business rules, interfaces (no web, no database code)
    Shop.Infrastructure/  EF Core DbContext, email/SMS implementations (optional, as it grows)
  tests/
    Shop.Tests/
Keeping business rules in a library with no web or database references makes them easy to test and reuse.
Think of it like this: A solution is like a school building and projects are the classrooms. Each classroom has its own subject and teacher, but they share a building, a timetable and a principal. Project references are the corridors: Shop.Api can walk into Shop.Core, but Shop.Core should not need anything from Shop.Api.

Useful tools in the SDK

CommandUse
dotnet formatFix code style and formatting to match your .editorconfig
dotnet build -c ReleaseOptimised build
dotnet publish -c Release -o outProduce files ready to deploy
dotnet tool install --global <tool>Install a CLI tool such as dotnet-ef
dotnet new gitignoreA .gitignore that skips bin, obj and IDE files

Common mistakes and fixes

  • Circular project references (A references B, B references A): not allowed. Move the shared code into a third library.
  • Different versions of the same package in different projects: confusing build warnings. Keep versions aligned (Central Package Management with a Directory.Packages.props file can help in larger solutions).
  • Adding a heavy package for one tiny function: write the ten lines yourself.
  • Never updating packages: you miss security fixes. Update regularly and run your tests after.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

NuGet packages, solutions and project structure · 1/7

NuGet and solutions

In this lesson you will use NuGet packages and organise a real multi-project solution.

Prefer a video by a teacher? Find free videos on “dotnet CLI solution class library project reference NuGet packages tutorial” on YouTube ↗

In real life: Structuring a college fee portal

A small team builds a fee payment portal for a group of colleges. They keep fee rules (late fines, scholarships, instalments) in a Core library that has no web or database code. The API project and a nightly reminder job both reference Core, and the test project checks every fee rule without starting a server.

bash
dotnet new sln -n FeePortal
dotnet new classlib -o src/FeePortal.Core
dotnet new webapi -o src/FeePortal.Api
dotnet new console -o src/FeePortal.ReminderJob
dotnet new xunit -o tests/FeePortal.Tests
dotnet sln add src/FeePortal.Core src/FeePortal.Api src/FeePortal.ReminderJob tests/FeePortal.Tests
dotnet add src/FeePortal.Api reference src/FeePortal.Core
dotnet add src/FeePortal.ReminderJob reference src/FeePortal.Core
dotnet add tests/FeePortal.Tests reference src/FeePortal.Core
One set of fee rules, used by two apps and checked by one test project.

Practice (0/4 done)

Task 1 · Question

Which command adds the package Humanizer to the current project?

Task 2 · Question

Project A references B and B references A. What happens?

Task 3 · Question

Which command lists packages with known security vulnerabilities?

Task 4 · Practice

Create a solution named Library with three projects: src/Library.Core (classlib) containing a Book record and a LateFee.Calculate(int daysLate) method (Rs 2 per day, max Rs 100), src/Library.App (console) that prints a fee, and tests/Library.Tests (xunit) with tests for 0, 10 and 80 days. Wire up all references and make dotnet build and dotnet test succeed from the solution folder.

Quick quiz

Question 1

1.Where is a package dependency recorded?

Question 2

2.What does a solution file do?

Question 3

3.Why keep business rules in a separate class library?

Question 4

4.Which is a sign a package may be risky?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Where is a package dependency recorded?

Answer: As a PackageReference in the .csproj

The .csproj lists PackageReference items.

What does a solution file do?

Answer: Groups several projects so they build and test together

It is a container for projects.

Why keep business rules in a separate class library?

Answer: Rules can be tested and reused without the web or database layers

Separation makes testing and reuse easy.

Which is a sign a package may be risky?

Answer: A name one letter different from a famous package, few downloads and an unknown owner

Look-alike names are a known supply-chain attack.

Which file tells .NET the project's target version?Related

Answer: The .csproj file

The <TargetFramework> element in the .csproj, for example net10.0.

From Installing .NET and using the dotnet CLI

Which command downloads the packages listed in pubspec.yaml?Related

Answer: flutter pub get

pub get resolves and downloads dependencies.

From Packages and pub

package.json has "dayjs": "^1.11.13". Which version can npm install?Related

Answer: 1.12.0

^ allows newer versions with the same major number: 1.12.0 yes, 2.0.0 no, and older ones like 1.10.0 no.

From Modules, npm and Vite

Since which version does a new ASP.NET Core app start from Program.cs without Startup.cs?Related

Answer: .NET 6

The minimal hosting model arrived in .NET 6.

From ASP.NET Core: your first Web API

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Testing, tooling and Unity” before its exam: Game development with Unity and C#.
  2. Module 9 exam: Testing, tooling and Unity · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Interviews, portfolio and careers. 43 topics left in the course before the final exam.

← Previous: Test doubles: fakes, stubs and mocks