/msbuild-modernization
Guide for modernizing and migrating MSBuild project files to SDK-style format. USE FOR: converting legacy .csproj/.vbproj with verbose XML to SDK-style, migrating packages.config to PackageReference, removing Properties/AssemblyInfo.cs in favor of auto-generation, eliminating
$ npx -y skills add managedcode/dotnet-skills --skill msbuild-modernization --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/msbuild-modernization
Context preview
The summary Claude sees to decide when to auto-load this skill.
Guide for modernizing and migrating MSBuild project files to SDK-style format. USE FOR: converting legacy .csproj/.vbproj with verbose XML to SDK-style, migrating packages.config to PackageReference, removing Properties/AssemblyInfo.cs in favor of auto-generation, eliminating
SKILL.md
msbuild-modernization.SKILL.mdname: msbuild-modernization
description: "Guide for modernizing and migrating MSBuild project files to SDK-style format. USE FOR: converting legacy .csproj/.vbproj with verbose XML to SDK-style, migrating packages.config to PackageReference, removing Properties/AssemblyInfo.cs in favor of auto-generation, eliminating explicit <Compile Include> lists via implicit globbing, consolidating shared settings into Directory.Build.props. Indicators of legacy projects: ToolsVersion attribute, <Import Project=\"$(MSBuildToolsPath)\">, .csproj files > 50 lines for simple projects. DO NOT USE FOR: projects already in SDK-style format, non-.NET build systems (npm, Maven, CMake), .NET Framework projects that cannot move to SDK-style."
license: MIT
MSBuild Modernization: Legacy to SDK-style Migration
Identifying Legacy vs SDK-style Projects
**Legacy indicators:**
- `<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />`
- Explicit file lists (`<Compile Include="..." />` for every `.cs` file)
- `ToolsVersion` attribute on `<Project>` element
- `packages.config` file present
- `Properties\AssemblyInfo.cs` with assembly-level attributes
**SDK-style indicators:**
- `<Project Sdk="Microsoft.NET.Sdk">` attribute on root element
- Minimal content — a simple project may be 10–15 lines
- No explicit file includes (implicit globbing)
- `<PackageReference>` items instead of `packages.config`
**Quick check:** if a `.csproj` is more than 50 lines for a simple class library or console app, it is likely legacy format.
<!-- Legacy: ~80+ lines for a simple library -->
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>MyLibrary</RootNamespace>
<AssemblyName>MyLibrary</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<!-- ... 60+ more lines ... -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project><!-- SDK-style: ~8 lines for the same library -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
</Project>Migration Checklist: Legacy → SDK-style
Step 1: Replace Project Root Element
**BEFORE:**
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!-- ... project content ... -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>**AFTER:**
<Project Sdk="Microsoft.NET.Sdk">
<!-- ... project content ... -->
</Project>
Remove the XML declaration, `ToolsVersion`, `xmlns`, and both `<Import>` lines. The `Sdk` attribute replaces all of them.
Step 2: Set TargetFramework
**BEFORE:**
<PropertyGroup>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
</PropertyGroup>
**AFTER:**
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
**TFM mapping table:**
| Legacy `TargetFrameworkVersion` | SDK-style `TargetFramework` | |---------------------------------|-----------------------------| | `v4.6.1` | `net461` | | `v4.7.2` | `net472` | | `v4.8` | `net48` | | (migrating to .NET 6) | `net6.0` | | (migrating to .NET 8) | `net8.0` |
Step 3: Remove Explicit File Includes
**BEFORE:**
<ItemGroup>
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Models\User.cs" />
<Compile Include="Models\Order.cs" />
<Compile Include="Services\AuthService.cs" />
<Compile Include="Services\OrderService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<!-- ... 50+ more lines ... -->
</ItemGroup>
<ItemGroup>
<Content Include="Views\Home\Index.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
<!-- ... more content files ... -->
</ItemGroup>
**AFTER:**
Delete all of these `<Compile>` and `<Content>` item groups entirely. SDK-style projects include them automatically via implicit globbing.
**Exception:** keep explicit entries only for files that need special metadata or reside outside the project directory:
<ItemGroup>
<Content Include="..\shared\config.json" Link="config.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
Step 4: Remove AssemblyInfo.cs
**BEFORE** (`Properties\AssemblyInfo.cs`):
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("MyLibrary")]
[assembly: AssemblyDescription("A useful library")]
[assembly: AssemblyCompany("Contoso")]
[assembly: AssemblyProduct("MyLibrary")]
[assembly: AssemblyCopyright("Copyright © Contoso 2024")]
[assembly: ComVisible(false)]
[assembly: Guid("...")]
[assembly: AssemblyVersion("1.2.0.0")]
[assembly: AssemblyFileVersion("1.2.0.0")]**AFTER** (in `.csproj`):
<PropertyGroup>
<AssemblyTitle>MyLibrary</AssemblyTitle>
<Description>A useful library</Description>
<Company>Contoso</Company>
<Product>MyLibrary</Product>
<Copyright>Copyright © Contoso 2024</Copyright>
<Version>1.2.0</Version>
</PropertyGroup>
Delete `Properties\AssemblyInfo.cs` — the SDK auto-generates assembly attributes from these proper
Read more
name: msbuild-modernization description: "Guide for modernizing and migrating MSBuild project files to SDK-style format. USE FOR: converting legacy .csproj/.vbproj with verbose XML to SDK-style, migrating packages.config to PackageReference, removing Properties/AssemblyInfo.cs in favor of auto-generation, eliminating explicit <Compile Include> lists via implicit globbing, consolidating shared settings into Directory.Build.props. Indicators of legacy projects: ToolsVersion attribute, <Import Project=\"$(MSBuildToolsPath)\">, .csproj files > 50 lines for simple projects. DO NOT USE FOR: projects already in SDK-style format, non-.NET build systems (npm, Maven, CMake), .NET Framework projects that cannot move to SDK-style." license: MIT
MSBuild Modernization: Legacy to SDK-style Migration
Identifying Legacy vs SDK-style Projects
**Legacy indicators:**
- `<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />`
- Explicit file lists (`<Compile Include="..." />` for every `.cs` file)
- `ToolsVersion` attribute on `<Project>` element
- `packages.config` file present
- `Properties\AssemblyInfo.cs` with assembly-level attributes
**SDK-style indicators:**
- `<Project Sdk="Microsoft.NET.Sdk">` attribute on root element
- Minimal content — a simple project may be 10–15 lines
- No explicit file includes (implicit globbing)
- `<PackageReference>` items instead of `packages.config`
**Quick check:** if a `.csproj` is more than 50 lines for a simple class library or console app, it is likely legacy format.
<!-- Legacy: ~80+ lines for a simple library -->
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>MyLibrary</RootNamespace>
<AssemblyName>MyLibrary</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<!-- ... 60+ more lines ... -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project><!-- SDK-style: ~8 lines for the same library -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
</Project>Migration Checklist: Legacy → SDK-style
Step 1: Replace Project Root Element
**BEFORE:**
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!-- ... project content ... -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>**AFTER:**
<Project Sdk="Microsoft.NET.Sdk"> <!-- ... project content ... --> </Project>
Remove the XML declaration, `ToolsVersion`, `xmlns`, and both `<Import>` lines. The `Sdk` attribute replaces all of them.
Step 2: Set TargetFramework
**BEFORE:**
<PropertyGroup> <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> </PropertyGroup>
**AFTER:**
<PropertyGroup> <TargetFramework>net472</TargetFramework> </PropertyGroup>
**TFM mapping table:**
| Legacy `TargetFrameworkVersion` | SDK-style `TargetFramework` | |---------------------------------|-----------------------------| | `v4.6.1` | `net461` | | `v4.7.2` | `net472` | | `v4.8` | `net48` | | (migrating to .NET 6) | `net6.0` | | (migrating to .NET 8) | `net8.0` |
Step 3: Remove Explicit File Includes
**BEFORE:**
<ItemGroup> <Compile Include="Controllers\HomeController.cs" /> <Compile Include="Models\User.cs" /> <Compile Include="Models\Order.cs" /> <Compile Include="Services\AuthService.cs" /> <Compile Include="Services\OrderService.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <!-- ... 50+ more lines ... --> </ItemGroup> <ItemGroup> <Content Include="Views\Home\Index.cshtml" /> <Content Include="Views\Shared\_Layout.cshtml" /> <!-- ... more content files ... --> </ItemGroup>
**AFTER:**
Delete all of these `<Compile>` and `<Content>` item groups entirely. SDK-style projects include them automatically via implicit globbing.
**Exception:** keep explicit entries only for files that need special metadata or reside outside the project directory:
<ItemGroup> <Content Include="..\shared\config.json" Link="config.json" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup>
Step 4: Remove AssemblyInfo.cs
**BEFORE** (`Properties\AssemblyInfo.cs`):
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("MyLibrary")]
[assembly: AssemblyDescription("A useful library")]
[assembly: AssemblyCompany("Contoso")]
[assembly: AssemblyProduct("MyLibrary")]
[assembly: AssemblyCopyright("Copyright © Contoso 2024")]
[assembly: ComVisible(false)]
[assembly: Guid("...")]
[assembly: AssemblyVersion("1.2.0.0")]
[assembly: AssemblyFileVersion("1.2.0.0")]**AFTER** (in `.csproj`):
<PropertyGroup> <AssemblyTitle>MyLibrary</AssemblyTitle> <Description>A useful library</Description> <Company>Contoso</Company> <Product>MyLibrary</Product> <Copyright>Copyright © Contoso 2024</Copyright> <Version>1.2.0</Version> </PropertyGroup>
Delete `Properties\AssemblyInfo.cs` — the SDK auto-generates assembly attributes from these proper
Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.
Repo: managedcode/dotnet-skills
Other skills on dotnet-skills.
- /aspnet-core
Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging, and deployment patterns on current .NET. USE FOR: working on ASP.NET Core apps, services, or middleware; changing auth, routing, configuration,
Open skill - /aspire
Build, upgrade, and operate Aspire 13.4.x C# or TypeScript application hosts with the current CLI, AppHost, ServiceDefaults, integrations, dashboard, testing, MCP, and deployment patterns for distributed apps. USE FOR: Aspire.AppHost.Sdk, Aspire.Hosting.*,
Open skill - /azure-functions
Build, review, or migrate Azure Functions in .NET with correct execution model, isolated worker setup, bindings, DI, and Durable Functions patterns. USE FOR: working on Azure Functions in .NET; migrating from the in-process model to the isolated worker model; adding Durable
Open skill - /blazor
Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices. USE FOR: building interactive web UIs with C# instead of JavaScript; choosing between Server, WebAssembly, or
Open skill - /entity-framework6
Maintain or migrate EF6-based applications with realistic guidance on what to keep, what to modernize, and when EF Core is or is not the right next step. USE FOR: EF6 codebases; runtime versus ORM migration decisions; EDMX, code-first, ObjectContext, and legacy data-access
Open skill - /entity-framework-core
Design, tune, or review EF Core data access with proper modeling, migrations, query translation, performance, and lifetime management for modern .NET applications. USE FOR: DbContext, migrations, model configuration, EF queries, tracking, loading, performance, transactions, and
Open skill

