The Visual Studio solution files have long been an explicit and messy format, with lots of configuration that could be inferred from conventions. However, with the release of the latest .NET 9 SDK (9.0.200) earlier this month, things have changed. The new XML-based solution format, SLNX, is now out of preview, bringing clean, convention-based defaults while still allowing for explicit configuration when needed.
What has changed?
Let's look at a simple "Hello World" example to illustrate the difference between the old and new formats.
Traditional .sln file - HelloWorld.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld", "HelloWorld\HelloWorld.csproj", "{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld.Tests", "HelloWorld.Tests\HelloWorld.Tests.csproj", "{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Debug|x64.ActiveCfg = Debug|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Debug|x64.Build.0 = Debug|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Debug|x86.ActiveCfg = Debug|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Debug|x86.Build.0 = Debug|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Release|Any CPU.Build.0 = Release|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Release|x64.ActiveCfg = Release|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Release|x64.Build.0 = Release|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Release|x86.ActiveCfg = Release|Any CPU
{979C8E48-A2EA-4647-A3A1-8647AB5F20C6}.Release|x86.Build.0 = Release|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Debug|x64.ActiveCfg = Debug|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Debug|x64.Build.0 = Debug|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Debug|x86.ActiveCfg = Debug|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Debug|x86.Build.0 = Debug|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Release|Any CPU.Build.0 = Release|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Release|x64.ActiveCfg = Release|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Release|x64.Build.0 = Release|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Release|x86.ActiveCfg = Release|Any CPU
{3B7AB8F1-88C0-4303-856B-A1E1EDE0A736}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
New SLNX file - HelloWorld.slnx
<Solution>
<Project Path="HelloWorld/HelloWorld.csproj" />
<Project Path="HelloWorld.Tests/HelloWorld.Tests.csproj" />
</Solution>
The code speaks for itself. The SLNX file is much cleaner and easier to read, with sensible defaults mean you only add exceptions when needed.
Getting started
Prerequisites
To get started with the new SLNX format, you need to update your .NET SDK to version 9.0.200
or later. You can verify your current version by running the following command:
dotnet --version
If you need to update, you can download the latest version from https://get.dot.net/ or update using the Visual Studio installer.
For Visual Studio you might still need to enable the new format under Tools
-> Options
-> Environment
-> Preview Features
-> Use Solution File Persistence Model
.
Create a new SLNX file
To create a new SLNX
file, you can use the following command:
dotnet new sln --format slnx
This will create a new solution file with the SLNX format.
Convert an existing .sln
file to SLNX
To convert an existing .sln
file to SLNX, you can use the following command:
dotnet sln migrate <SLN_FILE>
i.e.
dotnet sln migrate HelloWorld.sln
This will create a new solution file with the SLNX format based on the existing .sln
file.
Working with SLNX programmatically
Microsoft provides the Microsoft.VisualStudio.SolutionPersistence NuGet package, which provides a clean API for working with both traditional .sln
and new .slnx
files programmatically.
The entry point to serializers can be found on the SolutionSerializers
static class. This has the helper GetSerializerByMoniker
that can pick the serializer for a file extension, or a specific serializers can be used.
Here's a simple example of how to read and write SLNX files:
using Microsoft.VisualStudio.SolutionPersistence.Serializer;
// Open and deserialize the SLNX file
var solution = await SolutionSerializers.SlnXml.OpenAsync("HelloWorld.slnx", cancellationToken);
// Iterate through all projects in the solution
foreach (var project in solution.SolutionProjects)
{
// Print the file path of each project
Console.WriteLine(project.FilePath);
}
More examples can be found in the project GitHub wiki at github.com/microsoft/vs-solutionpersistence/wiki/Samples.
Conclusion
The new SLNX format is a great step forward, bringing clean, convention-based defaults while still allowing explicit configuration when needed. I belive this longterm will improve tooling and maintainability of solution files. It will also improve the developer experience by simplifying authoring and maintenance, reducing merge conflicts, and making it easier to sort them when they occur.
So if you haven't already, give it a try and let me know what you think!
This post is licensed under a Creative Commons Attribution 4.0 International License