Skip to content

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

@Matteo-T

Description

@Matteo-T

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:
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.0" ExcludeAssets="runtime" PrivateAssets="all" />
  1. Build the project
  2. 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:

<PropertyGroup>
  <BuildDependsOn>
	$(BuildDependsOn);
	CopySNIFiles;
  </BuildDependsOn>
  <PrepareForRunDependsOn>
	$(PrepareForRunDependsOn);
	CopySNIFiles;
  </PrepareForRunDependsOn>
</PropertyGroup>

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:

<PackageReference Include="Microsoft.Data.SqlClient" 
				  ExcludeAssets="runtime;build;buildTransitive" 
				  PrivateAssets="all" />

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)

<PropertyGroup>
  <!-- Allow users to opt out of SNI file copying -->
  <CopySNIFiles Condition="'$(CopySNIFiles)' == ''">true</CopySNIFiles>
</PropertyGroup>

<PropertyGroup>
  <BuildDependsOn Condition="'$(CopySNIFiles)' == 'true'">
	$(BuildDependsOn);
	CopySNIFiles;
  </BuildDependsOn>
  <PrepareForRunDependsOn Condition="'$(CopySNIFiles)' == 'true'">
	$(PrepareForRunDependsOn);
	CopySNIFiles;
  </PrepareForRunDependsOn>
</PropertyGroup>

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area\Native SNIIssues that are targeted to the Native SNI codebase.

    Type

    No fields configured for Bug.

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions