Incorrect binding redirects generated for SqlClient's runtime dependencies
- Dominant language
- C#
- Stars
- 989
- Forks
- 340
- Avg merge
- 4d 19h
- Merged PRs (30d)
- 72
Description
### Describe the bug
`SqlClient` was compiled with `Azure.Core` version 1.**35**.0.0. When building a project using version 1.**38**.0.0 (or indeed any other version), the appropriate binding redirect is not generated. This results in `FileLoadException`s in the AD authentication codepath - example:
```
Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'Azure.Core, Version=1.35.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
at Microsoft.Data.SqlClient.ActiveDirectoryAuthenticationProvider.AcquireTokenAsync(SqlAuthenticationParameters parameters)
at Program.Main() in D:\test\Program.cs:line 7
```
(My minimal repro, below, trips on `Azure.Core` but I've also seen errors mentioning `ValueTuple` and `System.Threading.Tasks.Extensions` in other contexts. I believe they're all due to the same issue.)
The problem here is that the `ResolveAssemblyReferences` target (which is responsible for determining which libraries need binding redirects) consumes **reference** assemblies from Nuget (when they exist), and `SqlClient`'s reference assemblies do not declare the library's runtime dependency on `Azure.Core`.
The reference assembly in ILSpy (`ref\net462\Microsoft.Data.SqlClient.dll`):

The code assembly (`lib\net462\Microsoft.Data.SqlClient.dll`):

This means `ResolveAssemblyReferences` doesn't realise there's a conflict (it thinks `SqlClient` doesn't require `Azure.Core` at all) so fails to generate the correct binding redirects. When `SqlClient`'s **code** assembly is deployed into the bin folder and run, it requires version 1.35, and, absent the required binding redirect, it dies because it can only find 1.38.
### To reproduce
The issue manifests when the _other_ assemblies in your compilation all reference v1.38 of the `Azure.Core` assembly. This combination of versions reproduces the issue (though there are other scenarios that produce the same issue with various other assemblies):
```xml
Exe
net472
```
```csharp
// Program.cs
using Microsoft.Data.SqlClient;
public class Program
{
public static void Main()
{
// We just need to cause AcquireTokenAsync to be jitted.
// In practice this'll typically happen during a call to
// SqlConnection.Open() when authenticating via AD
new ActiveDirectoryAuthenticationProvider().AcquireTokenAsync(null);
}
}
```
Build this project and observe the lack of binding redirect for `Azure.Core` (and others, eg `Tasks.Extensions`) in `bin\Debug\net472\test.exe.config`:
```xml
```
Running the project using `dotnet run` causes the exception above.
### Expected behavior
The reference assemblies for `SqlClient` should correctly declare all of the library's (immediate) runtime dependencies. This will allow `ResolveAssemblyReference` to solve the versions correctly and generate the required binding redirects.
### Further technical details
Microsoft.Data.SqlClient version: 5.2.0 or 3.1.5 (but probably others too)
.NET target: net472
SQL Server version: Any
Operating system: Windows 11
**Additional context**
Probably not relevant, but: I found this issue in a large repo with thousands of projects. The repo is in the process of being migrated off of CoreXT and onto CentralPackageVersions.
Contributor guide
Assessment
This issue has not been assessed yet.