Cake: System.Data.SqlClient in Cake.CoreCLR Assembly Load Error

Created on 7 Sep 2018  路  24Comments  路  Source: cake-build/cake

What You Are Seeing?

When referencing System.Data.SqlClient in my Cake file, I get the following exception when run from the global tool in a Docker container:

Assembly with same name is already loaded

When running from Windows (build.ps1), the reference isn't needed, and even when present, causes no issues.

I asked for assistance in the chat, and was directed here.

What is Expected?

The Cake script should compile.

What version of Cake are you using?

dotnet core global tool 0.30.0

Are you running on a 32 or 64 bit system?

64-bit

What environment are you running on? Windows? Linux? Mac?

Docker (Linux on Windows) microsoft/dotnet:2.1.400-sdk-stretch

Are you running on a CI Server? If so, which one?

No

How Did You Get This To Happen? (Steps to Reproduce)

In my build.cake file:

#addin "nuget:?package=System.Data.SqlClient&version=4.5.0"
#addin "nuget:?package=Cake.Docker&version=0.9.6"
#addin "nuget:?package=dbup-core&version=4.1.0"
#addin "nuget:?package=dbup-sqlserver&version=4.1.0"

In my Docker file:

FROM microsoft/dotnet:2.1.400-sdk-stretch AS build-env

WORKDIR /app
COPY ./ ./
ENV PATH="/root/.dotnet/tools:${PATH}"
RUN dotnet tool install -g Cake.Tool --version 0.30.0
RUN dotnet cake build.cake

Output Log

~sh
root@dc8cbcdce3b2:/app# dotnet cake build.cake -v=Diagnostic
Module directory does not exist.
NuGet.config not found.
Analyzing build script...
Analyzing /app/build.cake...
Processing build script...
Installing tools...
Retrieving package 'ReportGenerator 4.0.0-rc4' from '/root/.nuget/packages/'.
Package ReportGenerator.4.0.0-rc4 has already been installed.
Successfully installed 'ReportGenerator 4.0.0-rc4' to /app/tools
Executing nuget actions took 68.73 ms
Installing addins...
Found package 'System.Data.SqlClient 4.5.0' in '/app/tools/Addins'.
Package System.Data.SqlClient.4.5.0 has already been installed.
Successfully installed 'System.Data.SqlClient 4.5.0' to /app/tools/Addins
Executing nuget actions took 2.18 ms
The addin System.Data.SqlClient will reference System.Data.SqlClient.dll.
The addin System.Data.SqlClient will reference System.Data.SqlClient.dll.
The addin System.Data.SqlClient will reference System.Data.SqlClient.dll.
Found package 'Cake.Docker 0.9.6' in '/app/tools/Addins'.
Package Cake.Docker.0.9.6 has already been installed.
Successfully installed 'Cake.Docker 0.9.6' to /app/tools/Addins
Executing nuget actions took 0.46 ms
The addin Cake.Docker will reference Cake.Docker.dll.
Found package 'dbup-core 4.1.0' in '/app/tools/Addins'.
Package dbup-core.4.1.0 has already been installed.
Successfully installed 'dbup-core 4.1.0' to /app/tools/Addins
Executing nuget actions took 0.65 ms
The addin dbup-core will reference dbup-core.dll.
Found package 'dbup-sqlserver 4.1.0' in '/app/tools/Addins'.
Package dbup-sqlserver.4.1.0 has already been installed.
Successfully installed 'dbup-sqlserver 4.1.0' to /app/tools/Addins
Executing nuget actions took 0.57 ms
The addin dbup-sqlserver will reference dbup-sqlserver.dll.
Verifying assembly 'System.Data.SqlClient, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
Error: System.IO.FileLoadException: Assembly with same name is already loaded
at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at Cake.Core.Reflection.AssemblyLoader.Load(FilePath path, Boolean verify) in C:\projects\cake\src\Cake.Core\Reflection\AssemblyLoader.cs:line 31
at Cake.Core.Scripting.ScriptRunner.Run(IScriptHost host, FilePath scriptPath, IDictionary`2 arguments) in C:\projects\cake\src\Cake.Core\Scripting\ScriptRunner.cs:line 171
at Cake.Commands.BuildCommand.Execute(CakeOptions options) in C:\projects\cake\src\Cake\Commands\BuildCommand.cs:line 41
at Cake.CakeApplication.Run(CakeOptions options) in C:\projects\cake\src\Cake\CakeApplication.cs:line 45
at Cake.Program.Main() in C:\projects\cake\src\Cake\Program.cs:line 73
~

Bug

Most helpful comment

Yes indeedy

All 24 comments

@mgw854 Looks like dbup-sqlserver is trying to reference System.Data.SqlClient, Version=4.4.0.0 while you've explicitly added a reference to System.Data.SqlClient 4.5.0.

You could try to reference System.Data.SqlClient version 4.4.0 instead of version 4.5.0 or simply remove the explicit reference.

@patriksvensson The package reference in dbup-sqlserver is >= 4.4.0. No matter what I change the System.Data.SqlClient version to (including 4.4.0), it won't work.

The explicit reference is required by code in the Cake file that connects to the SQL Server before running dbup on it.

@mgw854 Since dbup-sqlserver loads the assembly, you should be able to exclude #addin "nuget:?package=System.Data.SqlClient&version=4.5.0" and add a usage declaration for the namespace you use in your Cake script (i.e. using System.Data.SqlClient).

I created a test project and this works:

#addin "nuget:?package=dbup-sqlserver&version=4.1.0"
#addin "nuget:?package=Cake.Docker&version=0.9.6"
#addin "nuget:?package=dbup-core&version=4.1.0"

using System.Data.SqlClient;

using (var connection = new SqlConnection("Server=(localdb)\\mssqllocaldb;Database=Foo;Trusted_Connection=True;"))
{
    var command = new SqlCommand("Select * FROM Bar", connection);
    command.Connection.Open();
    command.ExecuteNonQuery();
}

@mgw854 Actually, I noticed that it didn't work when running on .NET Core. Only on full framework. Will see if I can find a solution.

@mgw854 Something is indeed wrong when running this under CoreCLR.
@mholo65 Can you take a look at this?

#addin "nuget:?package=System.Data.SqlClient&version=4.5.0"

using System.Data.SqlClient;

using (SqlConnection connection = new SqlConnection("Server=(localdb)\\mssqllocaldb;Database=Foo;Trusted_Connection=True;"))
{
    var command = new SqlCommand("Select * FROM Test", connection);
    command.Connection.Open();
    command.ExecuteNonQuery();
}

When executed with .\build.ps1 --verbosity=diagnostic it fails with the following output:

Patrik@SPECTRE-2 [C:\Users\Patrik\Desktop\foo]
 X 1  位 .\build.ps1 --verbosity=diagnostic
.NET Core SDK v2.1.401 is already installed globally (wanted v2.1.401).
Cake.CoreClr (0.30.0) is already installed.
Executing script (dotnet)...
Module directory does not exist.
NuGet.config not found.
Analyzing build script...
Analyzing C:/Users/Patrik/Desktop/foo/build.cake...
Processing build script...
Installing addins...
Retrieving package 'System.Data.SqlClient 4.5.0' from 'C:\Users\Patrik\.nuget\packages\'.
Adding package 'System.Data.SqlClient.4.5.0' to folder 'C:\Users\Patrik\Desktop\foo\tools\Addins'
Added package 'System.Data.SqlClient.4.5.0' to folder 'C:\Users\Patrik\Desktop\foo\tools\Addins'
Added package 'System.Data.SqlClient.4.5.0' to folder 'C:\Users\Patrik\Desktop\foo\tools\Addins' from source 'C:\Users\Patrik\.nuget\packages\'
Successfully installed 'System.Data.SqlClient 4.5.0' to C:/Users/Patrik/Desktop/foo/tools/Addins
Executing nuget actions took 193,79 ms
The addin System.Data.SqlClient will reference System.Data.SqlClient.dll.
The addin System.Data.SqlClient will reference System.Data.SqlClient.dll.
The addin System.Data.SqlClient will reference System.Data.SqlClient.dll.
Verifying assembly 'System.Data.SqlClient, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
Error: System.IO.FileLoadException: Assembly with same name is already loaded
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)
   at Cake.Core.Reflection.AssemblyLoader.Load(FilePath path, Boolean verify) in C:\projects\cake\src\Cake.Core\Reflection\AssemblyLoader.cs:line 31
   at Cake.Core.Scripting.ScriptRunner.Run(IScriptHost host, FilePath scriptPath, IDictionary`2 arguments) in C:\projects\cake\src\Cake.Core\Scripting\ScriptRunner.cs:line 171
   at Cake.Commands.BuildCommand.Execute(CakeOptions options) in C:\projects\cake\src\Cake\Commands\BuildCommand.cs:line 41
   at Cake.CakeApplication.Run(CakeOptions options) in C:\projects\cake\src\Cake\CakeApplication.cs:line 45
   at Cake.Program.Main() in C:\projects\cake\src\Cake\Program.cs:line 73

Any idea what is going on?

Yes, saw this issue on Gitter last night and requested @mgw854 to submit an issue since behaviour felt like a bug. I鈥檒l look into it in the next couple of days.

Investigated. It's related to how we resolve lib items in NuGetContentResolver.
It loaded when I removed the runtimes folder from the extracted NuPkg

image

We should either:

  • Skip runtimes folder in content resolver, or
  • Use PackageFolderReader to get lib items, as described in my blog here

PackageFolderReader seems most robust right?

Yes indeedy

We can also use that to retrieve Framework Assemblies as well.

Sounds like a plan 馃憤

However... "Root file" support will not work anymore. I.e. NuGet packages without TFMs.

@mholo65 can we fallback? Should we fallback? :)

I think not. It's time to not support these packages anymore 馃槃 We have had the warning a long time now, hopefully there are no packages left that do this.

Very few addins without monikers
https://github.com/cake-contrib/Home/blob/master/Audit_for_Cake_0.28.0.md
and my guess is that those won't work with 0.28.0+ of Cake anyways.

How about tools distributed over NuGet?

@patriksvensson we shouldn't be loading any assemblies for tools, only registering for tool resolution.

Yes, I know 馃槉 I'm more concerned about how we use the NuGetContentResolver with tools.

Is there a fix for this? I get either:

_The type or namespace name 'SqlClient' does not exist in the namespace 'System.Data' (are you missing an assembly reference?)_

if I don't try and add System.Data.SqlClient as an addin, I get:

_Error: System.IO.FileLoadException: Assembly with same name is already loaded_

if I manually try and include System.Data.SqlClient in my cake script.

Any workaround or timeline for a fix?

thanks

@IvorBright, this have not bern fixed yet. If my previous investigations are still valid, then:

Skip runtimes folder in content resolver,

Should be a quick fix we could look into for 0.31.0.

@IvorBright we bumped this to next release.

However, as a workaround it should be possible to add &exclude=runtimes/**/*.dll to your #addin directive. For more info, check documentation here

Hi. Do we have an expected release for this? I've revisited the problem and I seem to hit the same problems...

If I do this:

Task("Default")
.Does(() =>
{
var connection = new SqlConnection("connectionString");
});

RunTarget("Default");

I get:
error CS0246: The type or namespace name 'SqlConnection' could not be found (are you missing a using directive or an assembly reference?)

If I do this:

addin "System.Data.SqlClient&version=4.6.1"

Task("Default")
.Does(() =>
{
var connection = new SqlConnection("connectionString");
});

RunTarget("Default");

I get this:
Error: Assembly with same name is already loaded

If I do this:
#addin System.Data.SqlClient&version=4.6.0&exclude=runtimes/*/.dll

Task("Default")
.Does(() =>
{
var connection = new SqlConnection("connectionString");
});

RunTarget("Default");

I get this:
The type or namespace name 'SqlConnection' could not be found (are you missing a using directive or an assembly reference?)

This sounds promising but if I add a using statement:

addin System.Data.SqlClient&version=4.6.0&exclude=runtimes/*/.dll

using System.Data.SqlClient;

Task("Default")
.Does(() =>
{
var connection = new SqlConnection("connectionString");
});

RunTarget("Default");

I get this:
Resolving assembly System.Data.SqlClient.resources, Version=4.5.0.0, Culture=en-GB, PublicKeyToken=b03f5f7f11d50a3a
Exception while resolving assembly System.Data.SqlClient.resources: Could not load file or assembly 'System.Data.SqlClient.resources, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
One or more errors occurred. (System.Data.SqlClient is not supported on this platform.)

Is there a workaround or a recommended way of called Sql from Cake Core CLR?

(I'm on Windows)

@IvorBright had a look at this, it seems we should load the one from runtimes instead of lib.

I came pretty far with this code:

#addin nuget:?package=System.Data.SqlClient&version=4.6.1&exclude=runtimes/unix/**/*.dll&exclude=lib/**/*.dll

using System.Data.SqlClient;

Task("Default")
.Does(() =>
{
    using(var connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=master;Integrated Security=True"))
    {
        connection.Open();

        using (var cmd = new SqlCommand("SELECT name from sys.databases", connection))
        {
            using (var dr = cmd.ExecuteReader())
            {
                while (dr.Read())
                {
                    Information(dr[0].ToString());
                }
            }
        }
    }
});

RunTarget("Default");

Only problem now is that I'm gettin following exception:

Error: System.AggregateException: One or more errors occurred. (Unable to load DLL 'sni.dll' or one of its dependencies: The specified module could not be found. (Exception from HRESULT: 0x8007007E)) ---> System.DllNotFoundException: Unable to load DLL 'sni.dll' or one of its dependencies: The specified module could not be found. (Exception from HRESULT: 0x8007007E)

So now we need to download also the native sni.dll (this is an umbrella package that we can use, or just pick the x64). Problem is now that we must tell the runtime where to load it from, which is not an easy task from within a C# script.

@devlead how does Cake.Git know where to get native libs for libgit2?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tompazourek picture tompazourek  路  3Comments

RichardJFoster picture RichardJFoster  路  4Comments

johncrim picture johncrim  路  4Comments

gabrielweyer picture gabrielweyer  路  3Comments

Gargony picture Gargony  路  3Comments