# 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:

   ```xml
   <PackageReference Include="SAIF.Platform.Authentication" Version="1.0.31" />
   ```

   With:

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

2. **Use package references (default)**:

   ```powershell
   dotnet build
   # or explicitly
   dotnet build -p:UseProjectReference=false
   ```

3. **Use project references**:
   ```powershell
   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:

```xml
<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:

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

### Step 2: Replace with Reference Items

Change these to use the new `ProjectOrPackageReference` item type:

```xml
<!-- 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:

```powershell
# 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`):

```xml
<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**:

```xml
<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

```xml
<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

```xml
<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`:
   - Generates candidate project paths for each `ProjectOrPackageReference` item
   - Checks if the project files exist using `Exists()`
   - Adds `ProjectReference` items for found projects
   - Falls back to `PackageReference` for missing projects
   - Removes original `ProjectOrPackageReference` items

2. When `UseProjectReference=false`:
   - Converts all `ProjectOrPackageReference` items directly to `PackageReference` items
   - Removes original `ProjectOrPackageReference` items

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