Claude
Skills
Sign in
Back

dotnet-csproj-reading

Included with Lifetime
$97 forever

Reading or modifying .csproj files. SDK-style structure, PropertyGroup/ItemGroup, CPM, props.

Backend & APIs

What this skill does


# dotnet-csproj-reading

## Overview / Scope Boundary

Teaches agents to read and safely modify SDK-style .csproj files. Covers project structure, PropertyGroup conventions, ItemGroup patterns, conditional expressions, Directory.Build.props/.targets, and central package management (Directory.Packages.props). Each subsection provides annotated XML examples and common modification patterns.

**Out of scope:** Project organization and SDK selection (owned by [skill:dotnet-project-structure]). Build error interpretation (owned by [skill:dotnet-build-analysis]). Common agent coding mistakes (owned by [skill:dotnet-agent-gotchas]).

## Prerequisites

.NET 8.0+ SDK. SDK-style projects only (legacy .csproj format is not covered). MSBuild (included with .NET SDK).

Cross-references: [skill:dotnet-project-structure] for project organization and SDK selection, [skill:dotnet-build-analysis] for interpreting build errors from project misconfiguration, [skill:dotnet-agent-gotchas] for common project structure mistakes agents make.

---

## Subsection 1: SDK-Style Project Structure

SDK-style projects use a `<Project Sdk="...">` declaration that imports hundreds of default targets and props. Understanding what the SDK provides implicitly is essential to avoid redundant or conflicting declarations.

### Annotated XML Example

```xml
<!-- The Sdk attribute imports default props at the top and targets at the bottom -->
<!-- This single line replaces dozens of Import statements from legacy .csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <!--
    Common SDK values:
    - Microsoft.NET.Sdk           -> Console apps, libraries, class libraries
    - Microsoft.NET.Sdk.Web       -> ASP.NET Core (adds Kestrel, MVC, Razor, shared framework)
    - Microsoft.NET.Sdk.Worker    -> Background worker services
    - Microsoft.NET.Sdk.Razor     -> Razor class libraries
    - Microsoft.NET.Sdk.BlazorWebAssembly -> Blazor WASM apps
  -->

  <!-- SDK-style projects auto-include all *.cs files via default globs -->
  <!-- No need to list individual .cs files in <Compile Include="..."> -->
  <!-- Default globs: **/*.cs for Compile, **/*.resx for EmbeddedResource -->

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
  </PropertyGroup>

</Project>
```

### Common Modification Patterns

**Changing SDK type** -- when an agent creates a web project with the wrong SDK:

```xml
<!-- WRONG: console SDK for a web project -->
<Project Sdk="Microsoft.NET.Sdk">

<!-- CORRECT: Web SDK includes ASP.NET Core shared framework -->
<Project Sdk="Microsoft.NET.Sdk.Web">
```

**Disabling default globs** -- rare, but needed when migrating from legacy format or when explicit file control is required:

```xml
<PropertyGroup>
  <!-- Disable automatic inclusion of *.cs files -->
  <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
  <!-- Disable all default items (Compile, EmbeddedResource, Content) -->
  <EnableDefaultItems>false</EnableDefaultItems>
</PropertyGroup>
```

**Verifying which SDK a project uses:**

```bash
# Check the first line of the .csproj for the Sdk attribute
head -1 src/MyApp/MyApp.csproj
# Output: <Project Sdk="Microsoft.NET.Sdk.Web">
```

---

## Subsection 2: PropertyGroup Conventions

PropertyGroup elements contain scalar MSBuild properties. The most important properties control the target framework, language features, and output type.

### Annotated XML Example

```xml
<PropertyGroup>
  <!-- Target Framework Moniker (TFM) -- determines runtime and API surface -->
  <!-- Use the latest LTS or STS release; prefer the repo's existing TFM. -->
  <TargetFramework>net9.0</TargetFramework>

  <!-- For multi-targeting, use plural form (see Subsection 4) -->
  <!-- <TargetFrameworks>net8.0;net9.0</TargetFrameworks> -->

  <!-- Enable nullable reference types (recommended for all new projects) -->
  <Nullable>enable</Nullable>

  <!-- Enable implicit global usings (System, System.Linq, etc.) -->
  <ImplicitUsings>enable</ImplicitUsings>

  <!-- Output type: Exe for apps, omit or Library for libraries -->
  <OutputType>Exe</OutputType>
  <!-- Omitting OutputType defaults to Library (produces .dll) -->

  <!-- Root namespace -- defaults to project name if omitted -->
  <RootNamespace>MyApp.Api</RootNamespace>

  <!-- Assembly name -- defaults to project name if omitted -->
  <AssemblyName>MyApp.Api</AssemblyName>

  <!-- Language version -- usually omitted (SDK sets default for TFM) -->
  <!-- Only set explicitly when using preview features -->
  <LangVersion>preview</LangVersion>
</PropertyGroup>
```

### Common Modification Patterns

**Enabling nullable for an existing project:**

```xml
<!-- Add to the main PropertyGroup -->
<Nullable>enable</Nullable>
<!-- This enables nullable warnings project-wide. Existing code will produce warnings. -->
<!-- To adopt incrementally, use #nullable enable in individual files instead. -->
```

**Setting output type for a console app:**

```xml
<!-- Required for executable projects; without this, dotnet run fails -->
<OutputType>Exe</OutputType>
```

**Adding TreatWarningsAsErrors (recommended for CI parity):**

```xml
<PropertyGroup>
  <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
  <!-- Enable unconditionally -- do NOT use CI-only conditions -->
</PropertyGroup>
```

---

## Subsection 3: ItemGroup Patterns

ItemGroup elements contain collections: package references, project references, file inclusions, and other build items. Understanding the three main item types prevents common agent mistakes.

### Annotated XML Example

```xml
<ItemGroup>
  <!-- PackageReference: NuGet package dependency -->
  <!-- Version attribute is required unless using central package management -->
  <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />

  <!-- PrivateAssets="All" prevents the dependency from flowing to consumers -->
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />

  <!-- IncludeAssets controls which assets from the package are used -->
  <PackageReference Include="Nerdbank.GitVersioning" Version="3.7.115"
                    PrivateAssets="All" IncludeAssets="runtime;build;native;analyzers" />
</ItemGroup>

<ItemGroup>
  <!-- ProjectReference: reference to another project in the solution -->
  <!-- Use forward slashes for cross-platform compatibility -->
  <ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />

  <!-- Set PrivateAssets to prevent transitive exposure to consumers -->
  <ProjectReference Include="../MyApp.Internal/MyApp.Internal.csproj"
                    PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
  <!-- None: files included in the project but not compiled -->
  <!-- CopyToOutputDirectory controls deployment behavior -->
  <None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />

  <!-- Content: files that are part of the published output -->
  <Content Include="wwwroot/**" CopyToOutputDirectory="PreserveNewest" />

  <!-- EmbeddedResource: files compiled into the assembly -->
  <EmbeddedResource Include="Resources/**/*.resx" />
</ItemGroup>
```

### Common Modification Patterns

**Adding a NuGet package:**

```bash
# Prefer CLI to avoid formatting issues
dotnet add src/MyApp/MyApp.csproj package Microsoft.EntityFrameworkCore --version 9.0.0
```

```xml
<!-- Or add manually -- ensure Version is specified -->
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
```

**Adding a project reference:**

```bash
# CLI ensures correct relative path
dotnet add src/MyApp.Api/MyApp.Api.csproj reference src/MyApp.Core/MyApp.Core.csproj
```

```xml
<!-- Verify path actually resolves to an existing .csproj -->
<ProjectReference Include="../MyApp.Core/MyApp.Core.csproj" />
```

**Including non-compiled files in output:**

```xml
<!-- Copy config files to output on build -->
<None Update="config/*.json" CopyToOutputDirectory="PreserveNewest" />
<!-- Note: Update (not Include) when the file is already matche

Related in Backend & APIs