Introduction

If you’ve been working with .NET for a while, you know that as a solution grows, managing it can become a headache. Solution files get bloated with unreadable GUIDs, NuGet package versions drift out of sync across projects, and you end up copying and pasting the same XML into every new .csproj file.

Fortunately, the .NET ecosystem has introduced several fantastic tools to declutter repositories and make enterprise-level management significantly easier. In this post, we’ll look at three game-changers for organizing .NET projects:

1. The Evolution of Solution Files: .sln vs .slnx

For decades, the standard Visual Studio solution file has been the .sln file. While it gets the job done, it has a notoriously poor developer experience when it comes to source control.

The Problem with .sln

Open a traditional .sln file in a text editor and you are greeted with obscure, proprietary syntax and endless GUIDs.

Common Issues:

The Solution: .slnx

To address these issues, Microsoft introduced the .slnx (Solution XML) format. It is a modern, lightweight, XML-based alternative to the classic .sln file.

Key Advantages of .slnx

2. Centralizing Dependencies with Directory.Packages.props

In multi-project solutions, managing NuGet packages can quickly turn into “version hell.” One project might reference Newtonsoft.Json v12.0 while another uses v13.0. This leads to:

Enter Central Package Management (CPM)

By creating a Directory.Packages.props file at the root of your repository, you can manage all NuGet package versions in one place.

Step 1: Define Package Versions Centrally

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageVersion Include="MediatR" Version="12.2.0" />
  </ItemGroup>
</Project>

Step 2: Reference Packages Without Versions in .csproj

<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" />
</ItemGroup>

Advantages of Central Package Management

3. Streamlining Configurations with Directory.Build.props

Just like package versions, build configurations are often duplicated across projects. If you want every project to:

You would normally have to repeat these settings in every .csproj file.

Applying the DRY Principle to MSBuild

Directory.Build.props is automatically discovered by MSBuild. If placed in a project directory (or any parent directory), its properties are imported into all child projects.

By placing a Directory.Build.props file at the repository root, you can define global build settings for all projects.

Example: Directory.Build.props

<Project>
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>latest</LangVersion>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>

    <Authors>Your Name</Authors>
    <Company>Your Company</Company>
  </PropertyGroup>
</Project>

Advantages of Directory.Build.props

Summary

By combining:

You transform your repository from a tangled web of duplicated settings and unreadable configuration files into a modern, maintainable, and enterprise-ready codebase.

If you haven’t adopted these tools yet, take a few minutes to implement them in your current project. Your future self — and your teammates — will appreciate the clarity and consistency.