Getting started in .NET can be overwhelming, because frankly, .NET can do almost everything: mobile, web, native, and embedded programming. For folks beginning, they’ll need to understand how .NET solutions are structured to get the most out of their time with the .NET development environment.

This post will look at some standard files developers will find in a .NET solution folder, and we’ll talk a bit about what each file does.

The Solution (.SLN) File

Generally, most .NET solutions will have multiple projects. The .sln file is the glue that binds all of the individual projects together into a logical unit. The .sln file is a text-based format used to load projects, define the Visual Studio version format support, and list build definitions.

Let’s take a look at an example sln file.

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication2", "WebApplication2\WebApplication2.csproj", "{665B08A8-5AD5-4021-8F85-C9ED559F2B89}"
EndProject
Global
   GlobalSection(SolutionConfigurationPlatforms) = preSolution
      Debug|Any CPU = Debug|Any CPU
      Release|Any CPU = Release|Any CPU
   EndGlobalSection
   GlobalSection(ProjectConfigurationPlatforms) = postSolution
      {665B08A8-5AD5-4021-8F85-C9ED559F2B89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
      {665B08A8-5AD5-4021-8F85-C9ED559F2B89}.Debug|Any CPU.Build.0 = Debug|Any CPU
      {665B08A8-5AD5-4021-8F85-C9ED559F2B89}.Release|Any CPU.ActiveCfg = Release|Any CPU
      {665B08A8-5AD5-4021-8F85-C9ED559F2B89}.Release|Any CPU.Build.0 = Release|Any CPU
   EndGlobalSection
EndGlobal

This file may look terrifyingly complex, but there’s good news. No human should be editing these files. Integrated Development Environment (IDE) tooling will handle creating and editing these files. Developers can use programs like JetBrains Rider, Visual Studio, Visual Studio for Mac, and VS Code (with an extension) to manage .NET Solutions.

While technically optional, sln files are highly recommended for long-term .NET solutions. They allow developers to add new projects and refactor the overall solution.

Read more about solutions here.

Project Files

Project files contain code files, package references, target frameworks, and general project information. The project file uses a strict XML schema format processed by the .NET build engine MSBuild. Project files can come in multiple flavors depending on the programming language used but generally has a proj suffix. For example, C# projects will have the extension csproj, while F# and Visual Basic will have fsproj and vbproj extensions, respectively. Irrespective of the language, these files are identical. Let’s look at a C# web project and an F# console project.

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>
</Project>

And the F# project.

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <Compile Include="Program.fs"/>
    </ItemGroup>
</Project>

The difference between C# and F# projects is that F# compiles files in order of references, meaning we need to reference files in order of compilation in the XML.

Developers will refer to the project files we’ve seen so far as SDK-style, as they are an updated version of the traditional format. “Older” formats of project files are still in use today with legacy applications and Xamarin mobile development projects that target Mono.

We can build applications using a single project and skip the solution file altogether. It’s not a recommended practice, but it is possible.

Read more about projects here

Project and Package References

Part of the SDK-style upgrade was making it easier to add references to other projects and packages. When starting with .NET, you’ll find the need to add references external to the existing project. We can choose to create another project, or we can utilize NuGet packages. NuGet is a package management store where the community shares both free open-source solutions and paid solutions.

Let’s start by looking at a project reference. In the same project file from above, let’s add a reference to a new class library project.

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
      <ProjectReference Include="..\ConsoleApp1\ConsoleApp1.fsproj" />
    </ItemGroup>
</Project>

We utilize the ProjectReference element and include a relative path to the referenced project we want.

To add a reference to a NuGet package, we can use the PackageReference element.

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
      <ProjectReference Include="..\ConsoleApp1\ConsoleApp1.fsproj" />
    </ItemGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0" />
    </ItemGroup>

</Project>

Referencing external dependencies allows us to reference code that we would otherwise have to write ourselves. One of the biggest strengths of any modern technology stack is sharing ideas through package management.

Code Files

Code files will end in a language-specific extension. For C# developers, files will end in a .cs, while F# files will end with .fs. We usually add these files to a project, and the build process will compile our code into an artifact: a class library, mobile artifact, executable, and other targets.

Let’s look at the contents of a Program.cs from a “Hello, World!” application.

using System;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

User Setting Files

You may find files in your solution that seem superfluous. One of these files is the Solution User Options (.suo) file. The .suo file stores a current developer’s preference settings. Visual Studio will generate this file, and developers should not check it into source control.

Read More about the Solution User Options file.

EditorConfig Files

The .editorconfig can help IDEs enforce styling rules of an existing solution. It’s not .NET specific, but you’ll find many development communities have adopted this specification. As solutions tend to have a mixture of .NET and other technologies, the .editorconfig file is a great choice.

EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs. The EditorConfig project consists of a file format for defining coding styles and a collection of text editor plugins that enable editors to read the file format and adhere to defined styles. EditorConfig files are easily readable, and they work nicely with version control systems. – EditorConfig

Let’s look at an example.

# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true

# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py}]
charset = utf-8

# 4 space indentation
[*.py]
indent_style = space
indent_size = 4

# Tab indentation (no size specified)
[Makefile]
indent_style = tab

# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2

# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2

Conclusion

.NET Solutions might be a bit confusing at first, with strangely formatted files that contain unreadable identifiers. Starting developers only need to understand that a solution is an overarching logical construct meant to connect projects. Projects include our code along with references to other projects and packages. Finally, there may be files at the solution directory level which can mostly be ignored by newcomers.

For folks getting started, lean on IDEs to better understand the relationship between .NET components, and advice for new and experienced devs: keep the solution simple.

I hope you found this post helpful, and let me know in the comments if there are other strange files in the solution you need explaining. I will gladly add them to this post.