microsoft/managing-legacy-dotnet-packages
> Manages NuGet packages in old-style .NET Framework projects (.NET Framework 4.x). Handles both packages.config (classic NuGet) and PackageReference in non-SDK-style csproj files. Use when updating, adding, or removing NuGet packages in projects that use packages.config, have old-style csproj format (ToolsVersion attribute), or target .NET Framework without SDK-style project format. Also triggers for "nuget update", "packages.config", "update package in old project", or "HintPath" tasks.
npx skills add https://github.com/microsoft/upgrade-agent-plugins --skill managing-legacy-dotnet-packages
Manage NuGet packages in old-style .NET Framework projects where packages use packages.config (classic NuGet format) or PackageReference in non-SDK-style csproj files.
This skill is different from managing-package-references which handles SDK-style projects with PackageReference and Central Package Management (CPM). Legacy .NET Framework projects have different package management mechanics.
Before modifying packages, determine which format the project uses:
| Indicator | Format | Management Approach |
|-----------|--------|-------------------|
| packages.config file in project directory | Classic NuGet | Edit packages.config XML + update HintPath in csproj |
| <PackageReference> in csproj WITHOUT Sdk attribute on <Project> | PackageReference in old-style | Edit version in csproj XML directly |
| <Reference> with <HintPath> containing packages\ path | Classic NuGet (assembly reference) | Update HintPath when package version changes |
| No packages.config AND no PackageReference | No NuGet packages | Nothing to manage |
packages.config in the project directory.<PackageReference> elements.<Project Sdk="..."> (SDK-style) or <Project ToolsVersion="..."> (old-style).packages.config is an XML file listing all NuGet packages and their versions:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net472" />
</packages>
The csproj file references the package assemblies via <Reference> with <HintPath>:
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
To update a package (e.g., Newtonsoft.Json from 13.0.1 to 13.0.3):
packages.config: Change the version attribute. <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net481" />
Also update targetFramework to net481 if upgrading the project TFM.
<HintPath> in csproj: The HintPath contains the version number in the path. <!-- Before -->
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<!-- After -->
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
⚠️ Important: The lib\{tfm}\ subfolder in the HintPath depends on which TFM the package ships for. After restore, check the actual folder name. Common patterns:
lib\net45\ — works for net45 through net481lib\net472\ — specific to net472+lib\net48\ — specific to net48+lib\netstandard2.0\ — .NET Standard (works on .NET Framework 4.6.1+)msbuild {SolutionPath/ProjectPath} /t:Restore. If MSBuild restore is unavailable for a packages.config solution, use nuget restore as a fallback.msbuild {SolutionPath/ProjectPath} /t:Build to verify the project compiles.packages.config: <package id="PackageName" version="1.0.0" targetFramework="net481" />
<Reference> to csproj with appropriate <HintPath>: <Reference Include="PackageName">
<HintPath>..\packages\PackageName.1.0.0\lib\net45\PackageName.dll</HintPath>
</Reference>
msbuild {SolutionPath/ProjectPath} /t:Restore. If MSBuild restore is unavailable for a packages.config solution, use nuget restore as a fallback.<package> entry from packages.config.<Reference> from the csproj.using directives for the package's namespaces if no longer needed.Some old-style projects use <PackageReference> instead of packages.config. This is less common but valid.
Edit the Version attribute directly in the csproj:
<!-- Before -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<!-- After -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Then run msbuild {SolutionPath/ProjectPath} /t:Restore so restore uses MSBuild for old-style projects.
Add a <PackageReference> element to an <ItemGroup>:
<ItemGroup>
<PackageReference Include="PackageName" Version="1.0.0" />
</ItemGroup>
⚠️ Do NOT use dotnet add package — it may attempt to convert the project to SDK-style format or produce incorrect XML for old-style projects.
Remove the <PackageReference> element from the csproj.
| Feature | Legacy (this skill) | SDK-Style (managing-package-references) |
|---------|-------------------|-----------------------------------------|
| Package file | packages.config | None (inline in csproj) |
| Version location | packages.config + HintPath | <PackageReference Version="..."> |
| Central Package Management | Not supported | Supported via Directory.Packages.props |
| dotnet add package | Do NOT use | Recommended |
| Assembly references | Explicit <Reference> with HintPath | Automatic |
| Restore command | msbuild /t:Restore (nuget restore fallback for packages.config when needed) | dotnet restore |
| Package folder | packages/ at solution root | Global cache (~/.nuget/packages/) |
Symptom: Build error — assembly not found.
Cause: packages.config version was updated but <HintPath> in csproj still points to old version.
Fix: Update the version number in the HintPath to match the new package version.
Symptom: NuGet restore warning about package not supporting target framework.
Cause: Package doesn't have a compatible TFM folder.
Fix: Find a compatible version of the package, or check if a newer version supports net481.
Symptom: Some projects use packages.config, others use PackageReference.
Cause: Projects were created at different times or partially migrated.
Fix: Handle each project according to its format. Do NOT convert between formats during a Framework version upgrade.
After package changes, always build with msbuild:
msbuild {SolutionPath} /t:Build /p:Configuration=Debug
Or using the dotnet wrapper:
dotnet msbuild {SolutionPath} /t:Build /p:Configuration=Debug
Take microsoft/managing-legacy-dotnet-packages from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.