Microsoft.Data.SqlClient.SNI.dll not output by VS build

1.8k Views Asked by At

I'm having trouble bringing in class libraries which have recently been migrated to NetStandard2.0 into an old-style AspNet web application project (framework 4.7.2).

The updated assemblies reference NuGet package Microsoft.Data.SqlClient v5.1.0

When running, the app generates the following error trace when attempting to open a SQL connection:

The type initializer for 'Microsoft.Data.SqlClient.TdsParser' threw an exception.

The type initializer for 'Microsoft.Data.SqlClient.SNILoadHandle' threw an exception.

Unable to load DLL 'Microsoft.Data.SqlClient.SNI.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Sure enough, there is no instance of Microsoft.Data.SqlClient.SNI.dll in the output bin folder - screenshot below - but there are instances of x64, x86 and arm64 dlls.

What's been tried:

  • Adding NuGet package Microsoft.Data.SqlClient v5.1.0 package directly into the web application project.

  • Located this resource which recommends that a .targets file (from the Microsoft.Data.SqlClient package) is explicitly referenced in the application's .csproj file, but doesn't elaborate on how to do that.

  • Located this question which asks almost the same question, and have attempted to incorporate the following tag in the application's .csproj file, but with no apparent effect or further diagnostic output:

    <Target Name="_CopySNIFilesToWebProjectOutputDir" AfterTargets="CopySNIFiles" Condition="'$(WebProjectOutputDir)' != ''">
      <Copy SourceFiles="@(SNIFiles)" DestinationFiles="@(SNIFiles -> '$(WebProjectOutputDir)\bin\%(RecursiveDir)%(Filename)%(Extension)')" />
    </Target>
    
  • Specified x64 as target platform. No impact.

I'm now at a loss for further avenues to pursue. How do I get Microsoft.Data.SqlClient.SNI.dll into my application's bin folder?

SqlClient dlls output

2

There are 2 best solutions below

0
On

I had the same issue in a net 4.8 WinForms project, which fixed by adding the latest System.Buffers nuget.

-- History

I converted a set of libraries used in common for winforms and asp.net from .net 4.8 to standard 2.0, which required replacing System.Data.SqlClient with Microsoft.Data.SqlClient.

Winforms however is still on 4.8. It would run fine locally, but the installed would not. After opening a connection, touching anything on a property, such as the connection property, connection state, etc., would throw an instance of object not referenced... exception.

I added the above idea (modified the path) to include the SNI artificats in the build for installer, but this was of no help.
So i manually copied over all Microsoft.*.dll assemblies from my local bin to the program files directory of install on local machine. Then it gave a Systems.buffer assemblies version error. While the System.Buffers versions were identical on both the local bin and the installed program files (even the revision and patch parts), the file size was different (seriously Microsoft, follow best practices).

So i added a latest nuget of System.Buffers to my winforms project, created a new build on installer (to clear out my experiments) and did a new install onto local machine, and works now.

This took a lot of trial and error. I also noticed that System.Tuples.Values (yes that one), has a different file size. So the local build used in visual studio 2022 for winforms has some secret sauce that the Project deployer does not. I also noticed that the local project bin in vs 2022 was using the full version of Microsoft.Data.SqlClient (at about 2 MB), while the installer pulled over a 72kb version (from targets).

0
On

We had a similar problem and solved it by using the solution from your third point. Our setup is ASP.NET Framework 4.7.2 project with dependency on .Net Standard 2.0 project (logging with Serilog to MsSql).

  <Target Name="CopySNIFilesToOutputPath" AfterTargets="CopySNIFiles" Condition="'$(WebProjectOutputDir)' != ''">
    <Copy SourceFiles="@(SNIFiles)" DestinationFiles="@(SNIFiles -> '$(WebProjectOutputDir)\bin\%(RecursiveDir)%(Filename)%(Extension)')" />
  </Target>