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
- Create project in
src/Tools/{Category}/{ToolName}/ - Use standard template:
<TargetFrameworks>$(DBT_RevitTargetFrameworks)</TargetFrameworks> <ProjectReference Include="..\..\..\DBTools.Core\DBTools.Core.csproj" /> - Add conditional Revit API references (copy from existing tool)
- Tool sources are automatically file-linked into DBTools.App via wildcard
Test Project Checklist
- Create in
src/Tools/{Category}/{ToolName}/Tests/ - Reference both App and Core:
<ProjectReference Include="..\..\..\..\DBTools.App\DBTools.App.csproj" /> <ProjectReference Include="..\..\..\..\DBTools.Core\DBTools.Core.csproj" /> - Link shared test utilities from
testing/TestSupport/ - Add explicit Revit API references (not transitive)
Related Documentation
- Build Pipeline - How projects are built
- ILRepack & Embedding - Assembly merging details
- Architecture Overview - High-level system architecture
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