Fody/Costura

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

Closed this issue · 12 comments

NET Framework 4.8
Costura.Fody 5.7.0
Windows 10

My application starts and connects to SQL Server, then open a Forms etc
It worked fine.
I have replaced System.Data.SqlClient with recommended Microsoft.Data.SqlClient.
I have built the app with Costura.Fody and run it.
During the SqlCnnection.Open(str)
The type initializer for 'Microsoft.Data.SqlClient.TdsParser' threw an exception

How to fix it?
What should I include to Costura files?

We have no fodyweavers.xml contents, so we can only guess. But I think you should include Microsoft.Data.Sql* in your fodyweavers and all should work.

My fodyweavers.xml

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura>
  </Costura>
</Weavers>

Should I add Microsoft.Data.SqlClient.dll (only) to this file?

I have made

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura>
       <IncludeAssemblies>
		  Microsoft.Data.SqlClient
	</IncludeAssemblies>
  </Costura>
</Weavers>

and rebuilt the app (Release). The bin\Release\net48 contains large set of assemblies. it seems not packed by costura

You need more than "just" Microsoft.Data.SqlClient. You can use wildcards.

Thank you, but little bit more details
If I use default file

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura>
  </Costura>
</Weavers>

after VS2022 build I have a 15MB exe..
But when I use

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura>
       <IncludeAssemblies>
		  Microsoft.Data.SqlClient
	</IncludeAssemblies>
  </Costura>
</Weavers>

then i have a large file set .
Could you please write me: what is incorrect?

If you use the 2nd one: only Microsoft.Data.SqlClient will be embedded, the rest will not be embedded. I think you also need to embeded the native runtime assemblies. Please check the example apps on how to do this, because officially there is no support for Costura anymore.

0xced commented

I wrote How to package a single-file executable using the SQLite EF Core Database Provider on .NET Framework? for SQLite but you can probably adapt it for Microsoft.Data.SqlClient. Sorry I can't help more from my phone.

If you use the 2nd one: only Microsoft.Data.SqlClient will be embedded, the rest will not be embedded. I think you also need to embeded the native runtime assemblies. Please check the example apps on how to do this, because officially there is no support for Costura anymore.

"no support for Costura anymore" - why?
Where can I find examples?

I wrote How to package a single-file executable using the SQLite EF Core Database Provider on .NET Framework? for SQLite but you can probably adapt it for Microsoft.Data.SqlClient. Sorry I can't help more from my phone.

Microsoft.Data.SqlClient is NuGet package. How to include NuGet dlls + all referenced dlls to fodyweavers.xml?

If you use the 2nd one: only Microsoft.Data.SqlClient will be embedded, the rest will not be embedded. I think you also need to embeded the native runtime assemblies. Please check the example apps on how to do this, because officially there is no support for Costura anymore.

I have checked the exe: it contains microsoft.data.sqlclient.dll in Resources
// 0x001F42AA: costura.microsoft.data.sqlclient.dll.compressed‎ (628010 bytes, Embedded, Private)

What can I do else?

As stated in the readme, Costura is no longer actively supported, closing this issue.

Please look for another solution to create single file executables.

0xced commented

I forgot that I had already documented how to package Microsoft.Data.SqlClient with Costura in the Microsoft.Data.SqlClient repository, see dotnet/SqlClient#793 🤦

Here's a full working sample code producing a single exe.

SqlServerSingleExe.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net48</TargetFramework>
    <LangVersion>10.0</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <PropertyGroup>
    <DebugType>embedded</DebugType>
    <AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
    <GenerateSupportedRuntime>false</GenerateSupportedRuntime>
    <CopySNIFiles>false</CopySNIFiles>
  </PropertyGroup>

  <Target Name="EmbedSqlClientNativeLibraries" BeforeTargets="ResolveReferences">
    <ItemGroup>
      <EmbeddedResource Include="@(SNIDllFiles)">
        <Visible>false</Visible>
        <Link Condition="$([MSBuild]::ValueOrDefault('%(Identity)', '').Contains('x86'))">costura32\%(Filename)%(Extension)</Link>
        <Link Condition="$([MSBuild]::ValueOrDefault('%(Identity)', '').Contains('x64'))">costura64\%(Filename)%(Extension)</Link>
      </EmbeddedResource>
    </ItemGroup>
  </Target>

  <ItemGroup>
    <PackageReference Include="Costura.Fody" Version="5.7.0" PrivateAssets="all" />
    <PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.1" />
  </ItemGroup>

</Project>

FodyWeavers.xml

<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura />
</Weavers>

Program.cs

using System;
using Microsoft.Data.SqlClient;

var connectionString = args.Length == 1 ? args[0] : "Server=sqlprosample.database.windows.net;Database=sqlprosample;User=sqlproro;Password=nh{Zd?*8ZU@Y}Bb#";

try
{
    using var connection = new SqlConnection(connectionString);
    await connection.OpenAsync();
    using var command = new SqlCommand("SELECT @@VERSION", connection);
    var sqlServerVersion = await command.ExecuteScalarAsync();
    Console.WriteLine($"✔️ Successfully connected to {sqlServerVersion}");
    return 0;
}
catch (Exception exception)
{
    Console.Error.WriteLine($"{exception}");
    return 1;
}

Executing dotnet run -c Release should produce the following output.

✔️ Successfully connected to Microsoft SQL Azure (RTM) - 12.0.2000.8
Jul 17 2023 18:40:52
Copyright (C) 2022 Microsoft Corporation

You'll also find a single file (SqlServerSingleExe.exe) inside the bin\Release\net48 directory.