dotnet / dotnet/SqlClient

`ExcludeAssets="runtime"` ignored by Microsoft.Data.SqlClient.SNI package - native DLLs copied unconditionally

Open
#4,208 4 comments 2 reactions 0 assignees View on GitHub
Area\Native SNI
Dominant language
C#
Stars
989
Forks
340
Avg merge
4d 19h
Merged PRs (30d)
72

Description

## Title
`ExcludeAssets="runtime"` ignored by Microsoft.Data.SqlClient.SNI package - native DLLs copied unconditionally

## Description

The `Microsoft.Data.SqlClient.SNI` package does not respect `ExcludeAssets="runtime"` on the parent `Microsoft.Data.SqlClient` package reference. Native SNI DLLs (Microsoft.Data.SqlClient.SNI.x64.dll, x86.dll, arm64.dll and their PDBs) are copied to the output directory even when runtime assets should be excluded.

## Steps to Reproduce

1. Create a .NET Framework 4.7.2 project
2. Add package reference with runtime exclusion:
```xml

```
3. Build the project
4. Check the output directory

## Expected Behavior

With `ExcludeAssets="runtime"`, no runtime DLLs or PDBs from Microsoft.Data.SqlClient or its dependencies should be copied to the output directory.

## Actual Behavior

The following files are copied to the output directory despite the exclusion:
- Microsoft.Data.SqlClient.SNI.x64.dll
- Microsoft.Data.SqlClient.SNI.x64.pdb
- Microsoft.Data.SqlClient.SNI.x86.dll
- Microsoft.Data.SqlClient.SNI.x86.pdb
- Microsoft.Data.SqlClient.SNI.arm64.dll
- Microsoft.Data.SqlClient.SNI.arm64.pdb

## Root Cause

The `Microsoft.Data.SqlClient.SNI` package (version 6.0.2) contains a `.targets` file at:
- `build/net462/Microsoft.Data.SqlClient.SNI.targets`
- `buildTransitive/net462/Microsoft.Data.SqlClient.SNI.targets`

This targets file unconditionally injects `CopySNIFiles` into the build process:

```xml


$(BuildDependsOn);
CopySNIFiles;


$(PrepareForRunDependsOn);
CopySNIFiles;

```

This bypasses NuGet's `ExcludeAssets` mechanism entirely.

## Investigation Results

Adding diagnostic MSBuild targets confirmed that NuGet correctly excludes the assets:
- `RuntimeCopyLocalItems`: empty ✓
- `NativeCopyLocalItems`: empty ✓
- `ReferenceCopyLocalPaths`: empty ✓

However, the custom `CopySNIFiles` target runs directly through `BuildDependsOn`, ignoring the exclusion.

## Workaround

Users must exclude build assets as well to prevent the targets file from being imported:
```xml

```

This is not ideal as it prevents all build-time functionality, not just the problematic copy behavior.

## Suggested Fixes

### Option 1: Add opt-out property (Quick fix)
```xml


true


$(BuildDependsOn);
CopySNIFiles;


$(PrepareForRunDependsOn);
CopySNIFiles;

```

### Option 2: Use NuGet runtime assets (Best practice)
Remove the custom `.targets` file and properly package SNI DLLs as runtime assets using the `runtimes/{rid}/native/` folder structure in the `.nupkg`. This would automatically respect `ExcludeAssets="runtime"`.

### Option 3: Check for exclusion markers
The targets file could check MSBuild properties or item metadata to detect if runtime assets should be excluded, though this is complex and fragile.

## Environment

- Microsoft.Data.SqlClient version: 7.0.0
- Microsoft.Data.SqlClient.SNI version: 6.0.2 (transitive dependency for net462/net472)
- Target Framework: .NET Framework 4.7.2 (net472)
- SDK Style: Yes
- NuGet Package Management: Central Package Management

## Additional Context

This issue affects scenarios where:
- Projects need compile-time references but not runtime deployment
- Projects want to control exactly which native DLLs are deployed
- Build output cleanliness is important
- Custom deployment strategies are used

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.