`ExcludeAssets="runtime"` ignored by Microsoft.Data.SqlClient.SNI package - native DLLs copied unconditionally
- 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
Assessment
This issue has not been assessed yet.