Table of Contents

Project References and Dependency Management

This document describes how DBTools projects reference each other, manage dependencies, and use file linking patterns.

Project Dependency Graph

                                 +-----------------------+
                                 |   DBTools.Themes      |
                                 |  (WPF theme resources)|
                                 +-----------+-----------+
                                             |
                    +------------------------+------------------------+
                    |                                                 |
          +---------v---------+                             +---------v---------+
          |   DBTools.Core    |<----------------------------+   DBTools.App     |
          | (shared services, |                             | (assembly output: |
          |  UI, Revit infra) |                             |   DBTools.dll)    |
          +---------+---------+                             +---------+---------+
                    ^                                                 ^
                    |                                                 |
        +-----------+-----------+                         +-----------+-----------+
        |                       |                         |                       |
+-------+-------+       +-------+-------+         +-------+-------+       +-------+-------+
| DBTools.GM    |       | DBTools.SGT   |         | File-linked   |       | File-linked   |
| (XAML design) |       | (XAML design) |         | tool sources  |       | tool assets   |
+---------------+       +---------------+         +---------------+       +---------------+
        ^                       ^
        |                       |
+-------+-------+       +-------+-------+
|DBTools.GM.Tests|      |DBTools.SGT.Tests|
+---------------+       +---------------+

+-------------------+       +-------------------+
| DBTools.Loader    |       | DBTools.Sandbox   |
| (Revit entrypoint)|       | (standalone exe)  |
+-------------------+       +-------------------+

Source: src/DBTools.App/DBTools.App.csproj:56-59

Key Relationships

From To Reference Type Purpose
DBTools.App DBTools.Core ProjectReference Core services, UI infrastructure
DBTools.App DBTools.Themes ProjectReference WPF theme resources
DBTools.Core DBTools.Themes ProjectReference ComponentResourceKey definitions
Tool projects DBTools.Core ProjectReference Shared infrastructure
Test projects DBTools.App + DBTools.Core ProjectReference Test compilation
DBTools.Sandbox DBTools.Core + DBTools.Themes ProjectReference Standalone preview

File Linking vs Project References

DBTools uses two distinct patterns for code sharing:

Pattern 1: Project References (Standard)

Used when the referenced assembly should be included as a separate DLL in output.

<!-- From DBTools.Core.csproj:153 -->
<ProjectReference Include="..\DBTools.Themes\DBTools.Themes.csproj" />

Source: src/DBTools.Core/DBTools.Core.csproj:153

When to use:

  • Shared infrastructure code (Core, Themes)
  • Code that defines types needed at runtime via reflection
  • WPF resources that use pack:// URIs

Pattern 2: File Linking (Compile-time inclusion)

Used when source files should be compiled directly into another assembly.

<!-- From DBTools.App.csproj:64-67 -->
<Compile Include="..\Tools\**\*.cs"
         Exclude="..\Tools\**\Tests\**\*.cs;..\Tools\**\obj\**\*.cs"
         Link="Tools\%(RecursiveDir)%(Filename)%(Extension)" />

Source: src/DBTools.App/DBTools.App.csproj:64-67

When to use:

  • Tool source code compiled into DBTools.dll
  • Shared test utilities across test projects
  • Polyfill files for net48 compatibility

File Linking Patterns in Detail

Tool Source Files into DBTools.App

All tool code from src/Tools/ is file-linked into DBTools.App:

<!-- C# source files -->
<Compile Include="..\Tools\**\*.cs"
         Exclude="..\Tools\**\Tests\**\*.cs;..\Tools\**\obj\**\*.cs"
         Link="Tools\%(RecursiveDir)%(Filename)%(Extension)" />

<!-- XAML files -->
<Page Include="..\Tools\**\*.xaml"
      Exclude="..\Tools\**\obj\**\*.xaml;..\Tools\**\Properties\DesignTimeResources.xaml"
      Link="Tools\%(RecursiveDir)%(Filename)%(Extension)" />

<!-- Icon assets -->
<EmbeddedResource Include="..\Tools\**\Assets\*.png"
                  Link="Resources\Icons\%(RecursiveDir)%(Filename)%(Extension)" />

Source: src/DBTools.App/DBTools.App.csproj:63-78

Why file linking for tools?

  • Single deployable assembly (DBTools.dll)
  • Eliminates plugin DLL proliferation
  • Tool projects exist primarily for XAML designer support

Shared Test Utilities

Test projects link shared test infrastructure:

<!-- From DBTools.GM.Tests.csproj:62-79 -->
<Compile Include="..\..\..\..\..\testing\TestSupport\ApsEnv.cs" Link="TestSupport\ApsEnv.cs" />
<Compile Include="..\..\..\..\..\testing\TestSupport\CommonTestDoubles.cs" Link="TestSupport\CommonTestDoubles.cs" />
<Compile Include="..\..\..\..\..\testing\TestSupport\TestHost\RevitHost.cs" Link="TestSupport\TestHost\RevitHost.cs" />
<!-- ... more linked files ... -->

Source: src/Tools/Common/GM/Tests/DBTools.GM.Tests.csproj:62-79

BCL Polyfills for net48

Polyfill files enable C# 10+ features on .NET Framework:

<!-- From Directory.Build.props:215-219 -->
<Compile Include="$(MSBuildThisFileDirectory)build/BuildSupport/Polyfills/IsExternalInit.cs" 
         Condition="'$(TargetFramework)'=='net48'" />
<Compile Include="$(MSBuildThisFileDirectory)build/BuildSupport/Polyfills/StringExtensions.cs" 
         Condition="'$(TargetFramework)'=='net48'" />

Source: Directory.Build.props:215-219


Centralized Package Management

Directory.Packages.props

All NuGet package versions are centralized:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>

  <ItemGroup>
    <!-- Package versions defined once -->
    <PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.2" />
    <PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
    <!-- ... -->
  </ItemGroup>
</Project>

Source: Directory.Packages.props:1-5

Consuming Packages

Projects reference packages without specifying versions:

<!-- From DBTools.Core.csproj:107-127 -->
<PackageReference Include="CSharpFunctionalExtensions" />
<PackageReference Include="Ardalis.GuardClauses" />
<PackageReference Include="AutoMapper" />
<PackageReference Include="Serilog" />

Source: src/DBTools.Core/DBTools.Core.csproj:107-127

Version Pinning Strategy

Package Category Version Strategy Rationale
M.E.* (DI, Config, Logging) 8.x Match Revit 2026 .NET 8 runtime
Serilog 4.x/6.x/8.x Compatible with both TFMs
BCL packages (System.Memory) Pinned Net48 compatibility / reduce host conflicts

Source: Directory.Packages.props:73-95


Multi-Targeting Configuration

Target Framework Definitions

All Revit-facing projects target both frameworks:

<!-- From Revit.props:2-6 -->
<PropertyGroup Label="Revit TFMs">
  <DBT_RevitLegacyTFM>net48</DBT_RevitLegacyTFM>
  <DBT_RevitModernTFM>net8.0-windows</DBT_RevitModernTFM>
  <DBT_RevitTargetFrameworks>$(DBT_RevitLegacyTFM);$(DBT_RevitModernTFM)</DBT_RevitTargetFrameworks>
</PropertyGroup>

Source: build/Revit.props:2-6

Consuming in Projects

<!-- Standard pattern in all Revit projects -->
<TargetFrameworks>$(DBT_RevitTargetFrameworks)</TargetFrameworks>

Source: src/DBTools.Core/DBTools.Core.csproj:3

Revit API Reference Patterns

References are conditional on TFM and build type:

<!-- net48 references Revit 2024 -->
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
  <Reference Include="RevitAPI">
    <HintPath>$(REVIT2024_DIR)\RevitAPI.dll</HintPath>
    <Private>false</Private>
  </Reference>
</ItemGroup>

<!-- net8 references Revit 2025/2026 -->
<ItemGroup Condition="'$(TargetFramework)'=='net8.0-windows'">
  <Reference Include="RevitAPI" Condition="'$(REVIT_NET8_DIR)'!=''">
    <HintPath>$(REVIT_NET8_DIR)\RevitAPI.dll</HintPath>
    <Private>false</Private>
  </Reference>
</ItemGroup>

Source: src/DBTools.App/DBTools.App.csproj:110-165


Vendored Dependencies

Why Vendored?

Some UI libraries are vendored (renamed) to avoid conflicts with other Revit add-ins:

<!-- From DBTools.Themes.csproj:53-59 -->
<Reference Include="DBTools.HandyControl">
  <HintPath>$(DBT_VendorArtifactsRoot)handycontrol\$(TargetFramework)\DBTools.HandyControl.dll</HintPath>
  <Private>true</Private>
</Reference>

Source: src/DBTools.Themes/DBTools.Themes.csproj:53-59

Vendored Libraries

Original Vendored As Reason
HandyControl DBTools.HandyControl Avoid host conflicts

Source: src/DBTools.Themes/DBTools.Themes.csproj:53-62


Assembly Embedding (DBTools.App)

Embedded Assembly Strategy

DBTools.App embeds most dependencies into the main DLL:

<!-- From DBTools.App.csproj:234-270 -->
<Target Name="DBT_EmbedCopyLocalAssemblies"
        AfterTargets="ResolveReferences"
        Condition="'$(DesignTimeBuild)'!='true'">
  <ItemGroup>
    <_EmbedCandidate Include="@(ReferenceCopyLocalPaths)"
                     Condition="..." />
    <!-- Exclude host-provided assemblies -->
    <_EmbedCandidate Remove="@(_EmbedCandidate)"
                     Condition="'%(Filename)%(Extension)' == 'RevitAPI.dll'" />
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Include="%(_EmbedLogicalDistinct.SourcePath)"
                      LogicalName="%(_EmbedLogicalDistinct.Identity)" />
  </ItemGroup>
</Target>

Source: src/DBTools.App/DBTools.App.csproj:234-270

What Gets Embedded

Embedded Not Embedded Reason
DBTools.Core RevitAPI/RevitAPIUI Revit provides at runtime
Serilog.* Newtonsoft.Json Revit provides
Most dependencies DBTools.HandyControl, DBTools.Themes WPF needs file-based Location

Test Project References

Reference Strategy

Test projects reference both App and Core:

<!-- From DBTools.GM.Tests.csproj:83-86 -->
<ItemGroup>
  <ProjectReference Include="..\..\..\..\DBTools.App\DBTools.App.csproj" />
  <ProjectReference Include="..\..\..\..\DBTools.Core\DBTools.Core.csproj" />
</ItemGroup>

Source: src/Tools/Common/GM/Tests/DBTools.GM.Tests.csproj:83-86

Why reference both?

  • Tool code is file-linked into App (need App for tool types)
  • Core exposes internal types via InternalsVisibleTo
  • Tests need access to both layers

InternalsVisibleTo Declarations

<!-- From DBTools.Core.csproj:27-32 -->
<ItemGroup>
  <InternalsVisibleTo Include="DBTools.App" />
  <InternalsVisibleTo Include="DBTools.GM.Tests" />
  <InternalsVisibleTo Include="DBTools.SGT.Tests" />
  <InternalsVisibleTo Include="DBTools.TDV.Tests" />
</ItemGroup>

Source: src/DBTools.Core/DBTools.Core.csproj:27-32


Common Pitfalls and Solutions

Pitfall 1: Circular Reference Between Themes and Core

Problem: DBTools.Core needs theme resources; themes might need Core types.

Solution: Theme dictionaries that need Core types are kept as raw Resource XAML (not compiled BAML):

<!-- From DBTools.Themes.csproj:38-46 -->
<ItemGroup>
  <Page Remove="Themes\App.Converters.xaml" />
  <Resource Include="Themes\App.Converters.xaml" />
</ItemGroup>

Source: src/DBTools.Themes/DBTools.Themes.csproj:38-46

Pitfall 2: Forbidden Host Assemblies in Output

Problem: Transitive dependencies may copy Revit-provided DLLs to output.

Solution: Build targets explicitly remove forbidden assemblies:

<!-- From DBTools.App.csproj:169-177 -->
<ItemGroup>
  <ForbiddenHostAssembly Include="RevitAPI.dll" />
  <ForbiddenHostAssembly Include="Newtonsoft.Json.dll" />
  <!-- ... -->
</ItemGroup>

<Target Name="DBT_RemoveForbiddenAfterCopy" AfterTargets="CopyFilesToOutputDirectory">
  <Delete Files="@(_DBT_ForbiddenToClear)" />
</Target>

Source: src/DBTools.App/DBTools.App.csproj:169-196

Pitfall 3: XAML Designer Cannot Load x64 Assemblies

Problem: XDesProc.exe is 32-bit; DBTools.App is x64 for Revit.

Solution: Override PlatformTarget during design-time builds:

<!-- From Directory.Build.targets:27-30 -->
<PropertyGroup Condition="'$(DBT_IsDesignerBuild)'=='true' and '$(TargetFramework)'=='net48'">
  <PlatformTarget>AnyCPU</PlatformTarget>
  <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>

Source: Directory.Build.targets:27-30

Pitfall 4: Test Projects Missing Revit API Types

Problem: Revit API references aren't transitive.

Solution: Test projects explicitly reference Revit APIs:

<!-- From DBTools.GM.Tests.csproj:95-109 -->
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
  <Reference Include="RevitAPI">
    <HintPath>$(REVIT2024_DIR)\RevitAPI.dll</HintPath>
    <Private>false</Private>
  </Reference>
</ItemGroup>

Source: src/Tools/Common/GM/Tests/DBTools.GM.Tests.csproj:95-109

Pitfall 5: DBTools.Themes Polyfill Conflicts

Problem: Themes is referenced by other net48 projects; polyfill types could conflict.

Solution: Themes explicitly removes polyfill files:

<!-- From DBTools.Themes.csproj:24-29 -->
<ItemGroup Condition="'$(TargetFramework)'=='net48'">
  <Compile Remove="$(MSBuildThisFileDirectory)../../build/BuildSupport/Polyfills/IsExternalInit.cs" />
  <Compile Remove="$(MSBuildThisFileDirectory)../../build/BuildSupport/Polyfills/StringExtensions.cs" />
</ItemGroup>

Source: src/DBTools.Themes/DBTools.Themes.csproj:24-29


Build Configuration Inheritance

Directory.Build.props Flow

Directory.Build.props
    |
    +-- Imports Version.props (version numbers)
    +-- Imports build/Revit.props (TFM definitions)
    +-- Sets artifact paths (.artifacts/)
    +-- Configures analyzers, warnings
    +-- Defines shared package references

Source: Directory.Build.props:1-6

Directory.Build.targets Flow

Directory.Build.targets
    |
    +-- Enforces NUKE entrypoint (DBT_Entry)
    +-- Handles WPF temp project intermediates
    +-- Copies vendored DLLs for XAML designer
    +-- Cleans up wpftmp artifacts

Source: Directory.Build.targets:1-299


Quick Reference: Adding a New Project

Tool Project Checklist

  1. Create project in src/Tools/{Category}/{ToolName}/
  2. Use standard template:
    <TargetFrameworks>$(DBT_RevitTargetFrameworks)</TargetFrameworks>
    <ProjectReference Include="..\..\..\DBTools.Core\DBTools.Core.csproj" />
    
  3. Add conditional Revit API references (copy from existing tool)
  4. Tool sources are automatically file-linked into DBTools.App via wildcard

Test Project Checklist

  1. Create in src/Tools/{Category}/{ToolName}/Tests/
  2. Reference both App and Core:
    <ProjectReference Include="..\..\..\..\DBTools.App\DBTools.App.csproj" />
    <ProjectReference Include="..\..\..\..\DBTools.Core\DBTools.Core.csproj" />
    
  3. Link shared test utilities from testing/TestSupport/
  4. Add explicit Revit API references (not transitive)


Verification Status

Check Status
Source anchors for all claims Yes
UNVERIFIED markers where needed No (all verified)
Cross-references added Yes
Examples tested N/A
No assumptions without evidence Yes

Verified by: docs-run-20260124-020412
Date: 2026-01-24