Skip to content

MSBuild Reference Swapping

This document explains how to use the MSBuild Reference Swap System to switch between PackageReference and ProjectReference dependencies in SAIF Platform projects.

Overview

The reference swap system allows developers to easily switch between using NuGet packages and local project references during development. This is particularly useful for:

  • Development: Use local project references to debug and develop across multiple SAIF platform components
  • CI/CD: Use package references for stable builds and deployments
  • Testing: Quickly switch between modes to test different scenarios

How It Works

The system uses MSBuild targets to transform ProjectOrPackageReference items into either PackageReference or ProjectReference items based on a boolean property.

Key Components

  • UseProjectReference property: Controls the reference mode (default: false)
  • ProjectOrPackageReference items: New item type that can resolve to either package or project references
  • Directory.Build.targets: Contains the MSBuild logic to perform the transformation
  • Automatic path generation: Projects are found using a configurable path pattern

Usage

Basic Usage

  1. Replace PackageReference with Reference: In your .csproj file, replace:
<PackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />

With:

<ProjectOrPackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
  1. Use package references (default):
dotnet build
# or explicitly
dotnet build -p:UseProjectReference=false
  1. Use project references:
    dotnet build -p:UseProjectReference=true
    

Project Structure Requirements

The system expects SAIF platform projects to follow this structure:

src/dotnet/
├── SAIF.Platform.Authentication/
│   └── src/SAIF.Platform.Authentication/
│       └── SAIF.Platform.Authentication.csproj
├── SAIF.Platform.Kiota.HttpClientLibrary/
│   └── src/SAIF.Platform.Kiota.HttpClientLibrary/
│       └── SAIF.Platform.Kiota.HttpClientLibrary.csproj
└── ...

Path Pattern Configuration

The default path pattern is ..\..\..\{0}\src\{0}\{0}.csproj, which resolves from a project directory like:

  • From: SAIF.Platform.Kiota.HttpClientLibrary\src\SAIF.Platform.Kiota.HttpClientLibrary\
  • To: SAIF.Platform.Authentication\src\SAIF.Platform.Authentication\SAIF.Platform.Authentication.csproj

You can override the path pattern by setting the ReferenceProjectPathPattern property:

<PropertyGroup>
  <ReferenceProjectPathPattern>custom\path\pattern\{0}.csproj</ReferenceProjectPathPattern>
</PropertyGroup>

Migration Guide

Step 1: Identify SAIF Platform Dependencies

Find all SAIF platform package references in your project:

<PackageReference Include="SAIF.Platform.*" Version="..." />

Step 2: Replace with Reference Items

Change these to use the new ProjectOrPackageReference item type:

<!-- Before -->
<ItemGroup>
  <PackageReference Include="Microsoft.Kiota.Abstractions" Version="1.19.1" />
  <PackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
</ItemGroup>

<!-- After -->
<ItemGroup>
  <PackageReference Include="Microsoft.Kiota.Abstractions" Version="1.19.1" />
  <ProjectOrPackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
</ItemGroup>

Step 3: Test Both Modes

Verify both modes work correctly:

# Test package mode
dotnet clean
dotnet restore
dotnet build -p:UseProjectReference=false

# Test project mode (ensure referenced projects are restored first)
dotnet clean
dotnet build -p:UseProjectReference=true

Troubleshooting

Project Not Found Warnings

If you see warnings like:

Project not found for 'SAIF.Platform.Authentication' at '...\path\...' - falling back to package reference

Solutions:

  1. Verify the project exists at the expected path
  2. Check that the path pattern is correct for your project structure
  3. Use an explicit ProjectPath attribute if needed
  4. Ensure the referenced project has been restored

Duplicate PackageReference Warnings

This should not occur with the current implementation. If you see duplicate warnings:

  1. Clean the project: dotnet clean
  2. Check for any remaining PackageReference items for the same package
  3. Verify you're not mixing ProjectOrPackageReference and PackageReference for the same package

Build Errors in Referenced Projects

When using UseProjectReference=true, if referenced projects fail to build:

  1. Ensure all referenced projects have been restored: dotnet restore
  2. Build referenced projects individually to identify specific issues
  3. Check that all projects target compatible frameworks

Examples

Example 1: Basic Migration

Before (SAIF.Platform.Kiota.HttpClientLibrary.csproj):

<ItemGroup>
  <PackageReference Include="Microsoft.Kiota.Abstractions" Version="1.19.1" />
  <PackageReference Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="1.19.1" />
  <PackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
</ItemGroup>

After:

<ItemGroup>
  <PackageReference Include="Microsoft.Kiota.Abstractions" Version="1.19.1" />
  <PackageReference Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="1.19.1" />
  <ProjectOrPackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
</ItemGroup>

Example 2: Multiple SAIF Platform References

<ItemGroup>
  <!-- External packages remain as PackageReference -->
  <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />

  <!-- SAIF Platform packages use Reference for swappable mode -->
  <ProjectOrPackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
  <ProjectOrPackageReference Include="SAIF.Platform.Azure" Version="1.0.31" />
  <ProjectOrPackageReference Include="SAIF.Platform.EntityFramework" Version="1.0.31" />
</ItemGroup>

Example 3: Custom Path Pattern

<PropertyGroup>
  <ReferenceProjectPathPattern>..\..\{0}\{0}.csproj</ReferenceProjectPathPattern>
</PropertyGroup>

<ItemGroup>
  <ProjectOrPackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
</ItemGroup>

Best Practices

  1. Keep external packages as PackageReference: Only use ProjectOrPackageReference for SAIF platform packages that you might want to develop against locally

  2. Use consistent patterns: Stick to the standard SAIF project structure when possible to avoid custom path patterns

  3. Test both modes: Always verify that your project builds correctly in both package and project reference modes

  4. Document dependencies: If your project requires specific SAIF platform projects to be available locally, document this in your README

  5. CI/CD considerations: Use UseProjectReference=false in CI/CD pipelines unless you specifically need to build against local projects

MSBuild Target Details

The system works by implementing a target that runs before CollectPackageReferences and Restore:

  1. When UseProjectReference=true:
  2. Generates candidate project paths for each ProjectOrPackageReference item
  3. Checks if the project files exist using Exists()
  4. Adds ProjectReference items for found projects
  5. Falls back to PackageReference for missing projects
  6. Removes original ProjectOrPackageReference items

  7. When UseProjectReference=false:

  8. Converts all ProjectOrPackageReference items directly to PackageReference items
  9. Removes original ProjectOrPackageReference items

The target is designed to be safe and provide clear feedback about what transformations are occurring.