Visual Studio
03 / 04

NuGet & Project Management

NuGet & Project Management

NuGet is the .NET package manager. Modern SDK-style .csproj files are lean and composable. Understanding solution structure, project references, and global tooling like Directory.Build.props is essential for maintainable multi-project .NET solutions.

NuGet Package Manager

# NuGet Package Manager UI
# Right-click project → Manage NuGet Packages
# Or: Tools → NuGet Package Manager → Manage NuGet Packages for Solution

# Tabs:
# Browse:   search nuget.org and private feeds
# Installed: packages currently in the project
# Updates:  packages with newer versions available

# NuGet Package Manager Console (PowerShell-based)
# Tools → NuGet Package Manager → Package Manager Console

# Install a package
Install-Package Newtonsoft.Json
Install-Package Microsoft.EntityFrameworkCore -Version 8.0.0
Install-Package Serilog.AspNetCore -ProjectName MyProject.Api

# Update packages
Update-Package                        # Update all packages in solution
Update-Package Newtonsoft.Json        # Update specific package
Update-Package -Safe                  # Update to highest compatible minor/patch (safe)

# Uninstall
Uninstall-Package Newtonsoft.Json

# Restore packages (usually automatic; force restore)
dotnet restore
# Or in PMC:
Update-Package -Reinstall

# List outdated packages (CLI)
dotnet list package --outdated
dotnet list package --outdated --include-transitive   # Including indirect deps

# Add package via CLI (faster than PMC for simple adds)
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 8.0.4
dotnet add MyProject.Core package MediatR

# Private NuGet feeds (CI, Azure Artifacts, GitHub Packages)
# Add to nuget.config at solution root:
# <packageSources>
#   <add key="AzureArtifacts" value="https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json" />
# </packageSources>

SDK-Style .csproj Format

<!-- Modern SDK-style .csproj (Visual Studio 2017+, all .NET Core/.NET 5+) -->
<!-- Much shorter than legacy .csproj — automatically includes all .cs files -->

<!-- MyProject.Api/MyProject.Api.csproj -->
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <RootNamespace>MyProject.Api</RootNamespace>
    <AssemblyVersion>1.0.0.0</AssemblyVersion>
    <Version>$(AssemblyVersion)</Version>
  </PropertyGroup>

  <ItemGroup>
    <!-- NuGet package references -->
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
    <PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>

  <ItemGroup>
    <!-- Project reference (linked project, not NuGet) -->
    <ProjectReference Include="..MyProject.CoreMyProject.Core.csproj" />
    <ProjectReference Include="..MyProject.InfrastructureMyProject.Infrastructure.csproj" />
  </ItemGroup>
</Project>

<!-- Class library project -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <!-- Multi-target: <TargetFrameworks>net8.0;netstandard2.1</TargetFrameworks> -->
    <Nullable>enable</Nullable>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <PackageId>MyCompany.MyProject.Core</PackageId>
    <Description>Core domain logic for MyProject</Description>
  </PropertyGroup>
</Project>

Directory.Build.props & global.json

<!-- Directory.Build.props — placed at solution root, applies to ALL projects -->
<!-- MSBuild auto-discovers it by traversing up from each project directory -->
<Project>
  <PropertyGroup>
    <!-- Common properties for all projects in solution -->
    <LangVersion>latest</LangVersion>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <Authors>MyCompany</Authors>
    <Copyright>Copyright © 2024 MyCompany</Copyright>
  </PropertyGroup>
  <ItemGroup>
    <!-- Add common analyzer to all projects -->
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
    </PackageReference>
  </ItemGroup>
</Project>

<!-- Directory.Packages.props — Central Package Management (CPM) -->
<!-- When ManagePackageVersionsCentrally=true, define versions here ONCE -->
<Project>
  <ItemGroup>
    <PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
    <PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
    <PackageVersion Include="Serilog.AspNetCore" Version="8.0.1" />
  </ItemGroup>
</Project>
<!-- Then in .csproj files, omit Version attribute: -->
<!-- <PackageReference Include="Microsoft.EntityFrameworkCore" /> -->

// global.json — pin the .NET SDK version at solution root
{
  "sdk": {
    "version": "8.0.101",
    "rollForward": "latestPatch"   // latestPatch | minor | major | disable
  }
}

// rollForward values:
// disable:      use exact version, fail if not installed
// latestPatch:  use latest patch of specified minor (recommended)
// minor:        use latest minor >= specified
// major:        use any newer SDK

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free