Since Visual Studio 2022 17.10 preview, we can see a new .NET solution file format with file extension .slnx.
For example for this simple solution:
The content of the .slnx file is:
1 2 3 4 5 6 7 8 |
<Solution> <Folder Name="/Test/"> <Project Path="UnitTests\UnitTests.csproj" Type="Classic C#" /> </Folder> <Folder Name="/Application/"> <Project Path="App\App.csproj" Type="Classic C#" /> </Folder> </Solution> |
Edit: 28th March 2024: Microsoft didn’t communicate when this format will become RTM. VS 17.10 RTM doesn’t support this format, while VS 17.11 Preview does.
Why a new Solution File Format?
For decades the .sln solution file format relied on a Microsoft proprietary file format, verbose, hardly readable, and based on GUIDs. At NDepend, given our focus on .NET tools, we’ve experienced firsthand the complexity of managing this file format effectively. Here is the content of the .sln file for the same simple solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.10.34814.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{F95781B3-A973-4D19-9585-974DA143E6A1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{6EC5A7A1-CA0C-42AC-BB97-19EF01B3C68C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{6C6714E6-D117-405B-9FFD-C4AF0643EA29}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{06F979AA-0ABF-4B86-91D5-7E32B7F2A081}" EndProject Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {85AD0F43-BB53-4378-94F7-8A7DF5A990D5} EndGlobalSection GlobalSection(NestedProjects) = preSolution {06F979AA-0ABF-4B86-91D5-7E32B7F2A081} = {6C6714E6-D117-405B-9FFD-C4AF0643EA29} {F95781B3-A973-4D19-9585-974DA143E6A1} = {6EC5A7A1-CA0C-42AC-BB97-19EF01B3C68C} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {06F979AA-0ABF-4B86-91D5-7E32B7F2A081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {06F979AA-0ABF-4B86-91D5-7E32B7F2A081}.Debug|Any CPU.Build.0 = Debug|Any CPU {06F979AA-0ABF-4B86-91D5-7E32B7F2A081}.Release|Any CPU.ActiveCfg = Release|Any CPU {06F979AA-0ABF-4B86-91D5-7E32B7F2A081}.Release|Any CPU.Build.0 = Release|Any CPU {F95781B3-A973-4D19-9585-974DA143E6A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F95781B3-A973-4D19-9585-974DA143E6A1}.Debug|Any CPU.Build.0 = Debug|Any CPU {F95781B3-A973-4D19-9585-974DA143E6A1}.Release|Any CPU.ActiveCfg = Release|Any CPU {F95781B3-A973-4D19-9585-974DA143E6A1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal |
We can see that solution folders are treated equally as projects and that a NestedProjects section defines the hierarchy. Also, the project configuration is duplicated for all projects. Each project is assigned a GUID, making it less user-friendly for humans.
The transition to the streamlined .slnx file format is a positive change for the entire .NET community. One concrete benefit I see is the improvement in handling solution file merge conflicts, a frequent and painful task for those on large teams. Because of GUIDs referencing other GUIDs the traditional .sln format makes resolving these conflicts nightmarish. The introduction of the new .slnx format promises significant enhancements, although XML is not the ideal format for resolving merge issues.
It echoes Microsoft’s earlier simplification of the .csproj C# project file format, which now includes only the essential information that a .NET IDE cannot infer:
1 2 3 4 5 6 7 8 |
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project> |
What About Specific Project Configuration?
From Build > Configuration Manager…, you can adjust the UnitTests project settings to prevent it from compiling in Release mode. This is practical since tests are usually only run in Debug mode.
Once changes are saved, the .slnx file content becomes:
1 2 3 4 5 6 7 8 9 10 |
<Solution> <Folder Name="/Test/"> <Project Path="UnitTests\UnitTests.csproj"> <Configuration Solution="Release|*" Project="*|*|NoBuild" /> </Project> </Folder> <Folder Name="/Application/"> <Project Path="App\App.csproj" /> </Folder> </Solution> |
Interestingly, when I converted a .sln file with an attached NDepend project file (.ndproj file extension) to .slnx, the resulting .slnx content was buggy. We use certain Visual Studio APIs to attach a .ndproj file to a solution, which seems to be unsupported at the moment. However, rest assured that with the official release of Visual Studio 2022 17.0, we will ensure compatibility with a new version of NDepend if needed.
How to Use .slnx File Format?
While Visual Studio 2022 17.10 remains in preview, it’s advisable to avoid using the .slnx format in production. This format may still undergo changes based on .slnx community feedback. It is not even yet mentioned in the Visual Studio 2022 Preview release note! JetBrains Rider people are also working on supporting .slnx.
To use it:
- You need Visual Studio 2022 17.10 Preview 3.0 or higher installed.
- In Tools > Options > Preview Features search for Use Solution File Persistence Model
- Then select the solution in the Solution Explorer panel. Then File > Save YourSolution.sln As…
- Saves as .slnx et voilà!
.slnx file extension is not yet per default associated with Visual Studio but you can bind it manually or drag and drop this file to VS 2022 Preview.