Quite often we want to create a solution that have a root namespace and also creates assembly names that match this. It keeps things tidy and also means that if, for example, your solution is packaged to be used in other solutions then the namespace reflects its purpose.

Now, have you ever opened a solution and found it structured somewhat like this?

Example of a solution without using prefixes

The first problem is that it takes a while to find the project that you need to work on. We can organise it into solution folders which will help.

Example of a solution without using prefixes - structured into solution folders

Solution folders don't physically map to file system folders, which can be quite frustrating as it means that the file system structure is untidy too. After restructuring the file system as well it's a lot tidier.

Example of a solution without using prefixes - file system folders

This is better, but we still have two issues:

  1. It's still really hard to read the purpose of each project as it's at the end of the project name.
  2. We have really long file paths. By default Windows stores solutions in C:\Users\(UserName)\source but this can be changed. As I have multiple accounts on Github and Azure DevOps I use C:\source\(Github|AzureDevOps)\(AccountName)\ which makes it somewhat longer. The maximum path length in Windows in 260 characters. The path C:\source\GitHub\PaulCodesStuff\AcmeWidgetCompany\src\Application\AcmeWidgetCompany.Application.Messaging is already 105 characters without any other folders and files.

N.B. You can enable longer file paths in Windows by editing the registry. However Visual Studio will still not support them.

We can rename the project folders that are created, e.g. AcmeWidgetCompany.Application.Messaging to Messaging, but this requires either removing the project from the solution and then adding it back in after the rename or closing the solution, renaming and then manually editing the solution file. This will need to be done whenever new projects are added as Visual Studio always uses the full project name for the folder.

Solution 1 - Project Level Override

We can create a class library called 'Abstractions', right click on it and click properties, and then manually override the assembly name to AcmeWidgetCompany.Domain.Abstractions, or better still, AcmeWidgetCompany.Domain.$(MSBuildProjectName). The same can then be done for default namespace (noting spaces are replaced with underscores) as shown below:

Method 1 - Manually editing project properties

This is time-consuming and requires discipline when working as a team. It's very easy for this to get overlooked.

Solution 2 - Using Directory.Build.props

The Directory.Build.props file instructs MSBuild to override default property settings at folder level. By placing one in the \src folder with the following content we can tell MSBuild that the assembly name should be prefixed with AcmeWidgetCompany. Visual Studio also uses this file to determine the default root namespace for files within the folder.

<Project>
  <PropertyGroup>
    <RootNamespace>AcmeWidgetCompany.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
    <AssemblyName>AcmeWidgetCompany.$(MSBuildProjectName)</AssemblyName>
  </PropertyGroup>
</Project>

Now, as long as we don't override these at project level, all of our projects will be automatically prefixed with 'AcmeWidgetCompany'.

So our solution now looks like this:

After adding Directory.Build.props to src - Solution

And our file system can be arranged like this:

After adding Directory.Build.props to src - File System

This has already made things more readable, however we can go further. As the Directory.Build.props file works at folder level, we can add separate ones to the Domain, Application, Infrastructure, Persistence and Presentation folders. We can also add ones to Messaging and Payments within the Infrastructure folder. In this example we only have a single project, without any prefix, in the Presentation and Persistence layers, so we'll miss these out for the time being. We can refactor at a later date if necessary.

After adding Directory.Build.props to folders within solution - Solution

Mirroring this on the filesystem:

After adding Directory.Build.props to folders within solution - File System

Conclusion

We can use Directory.Build.props as a simple way to prefix namespaces and assembly names at folder level. Doing so helps to keep the solution tidy and easier to navigate. It also helps us to limit the length of the file path which can be an issue on Windows based systems.

I recommend the Directory.Build.props option in preference to changing the project properties. In large solutions it requires less work and discipline from a team.

The two solutions above are available on Github.

An unhandled error has occurred. Reload 🗙