Do you use Directory.Build.Props to simplify multi-project build configurations?

Last updated by Daniel Mackay [SSW] 2 months ago.See history

When working on large enterprise scale projects .NET Solutions can often become unwieldy and difficult to maintain. This is particularly true of .csproj files which end up repeating configuration across all projects. How can one file save you hours of maintenance by keeping project configuration DRY?

What is a Directory.Build.props file?

A Directory.Build.props file is an MSBuild file used in .NET projects to define common properties and configurations that apply to multiple projects within a directory tree. This file helps centralize the configuration and reduce redundancy by allowing you to specify settings that will be inherited by all projects under the directory where the file is located.

Usages

This can be used for:

  • .NET framework version
  • Nullability
  • Implicit references
  • Configuring warnings as errors
  • Static code analysis
  • Author / Company

Examples

Project1.csproj:

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

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>

    <!-- Configure code analysis. -->
    <AnalysisLevel>latest</AnalysisLevel>
    <AnalysisMode>Recommended</AnalysisMode>
    <TreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
    <CodeAnalysisTreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</CodeAnalysisTreatWarningsAsErrors>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
  </PropertyGroup>

</Project>

Project2.csproj:

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

    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>

        <!-- Configure code analysis. -->
        <AnalysisLevel>latest</AnalysisLevel>
        <AnalysisMode>Recommended</AnalysisMode>
        <TreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
        <CodeAnalysisTreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</CodeAnalysisTreatWarningsAsErrors>
        <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    </PropertyGroup>

</Project>

Bad example - Redundant configuration

Project1.csproj:

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

Project2.csproj:

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

Directory.Build.props:

<Project>
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>

        <!-- Configure code analysis. -->
        <AnalysisLevel>latest</AnalysisLevel>
        <AnalysisMode>Recommended</AnalysisMode>
        <TreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
        <CodeAnalysisTreatWarningsAsErrors Condition="'$(Configuration)' == 'Release'">true</CodeAnalysisTreatWarningsAsErrors>
        <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    </PropertyGroup>
</Project>

Good example - Centralized configuration

Daniel Mackay
Luke Cook
We open source.Loving SSW Rules? Star us on GitHub. Star
Stand by... we're migrating this site to TinaCMS