Compiling a .Net Core Console App with CoreRT and Dapper

1.4k Views Asked by At

I'm attempting to compile my code (a .net core console application) into a native .exe for win-x64 using CoreRT. I was able to follow the documentation right up until the section having to do with reflection and using an rd.xml file, which is where I am currently stuck.

My project uses Dapper as the ORM, which relies on reflection to bind objects from my database. I only have 2 different types that I am binding, so my assumption is that I need to include these types in the rd.xml.

Right now, when I try to run dotnet publish -r win-x64 -c release from the .net core cli, it finishes successfully, however at runtime, my compiled .exe throws an exception with the following snippet:

---> (Inner Exception #0) System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property. ---> EETypeRva:0x01202268(System.Reflection.MissingRuntimeArtifactException): This object cannot be invoked because it was metadata-enabled for browsing only: 'Dapper.SqlMapper.TypeHandlerCache<System.Data.DataTable>.SetHandler(Dapper.SqlMapper.ITypeHandler)' For more information, please visit http://go.microsoft.com/fwlink/?LinkID=616867

My rd.xml file looks like this:

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
        <Type Name="Dapper.SqlMapper.TypeHandlerCache{System.Data.DataTable}">
          <MethodInstantiation Name="SetHandler" Arguments="Dapper.SqlMapper.ITypeHandler" Dynamic="Required" />
      </Type>
  </Application>
</Directives>

I assume I need to include references to my models here which would be Foo and Bar, but the error getting thrown refers to Dapper specifically.

The rd.xml file is inside of my project directory, and is referenced in the MyProject.csproj like so:

<ItemGroup> <EmbeddedResource Include="rd.xml" /> </ItemGroup>

I'm wondering if this problem is due to my structure (perhaps the rd.xml should be referenced in a different way), or due to the content of my rd.xml file. Has anyone dealt with this, or used CoreRT on a project that uses Dapper?

2

There are 2 best solutions below

7
Joseph Moreno On

Try add this to directives:

<Assembly Name="System.Data.Common">
    <Type Name="System.Data.DataTable" Dynamic="Required All"/>
</Assembly>
2
Joseph Moreno On

To compile my project successfully I had to do the following:

  • Include all references in the System.Data.SqlClient nuget package as project references. In this case I also included those of System.Configuration.ConfigurationManager.

  • From the command line publish for the required operating system: dotnet publish -r win-x64

  • From publishing path copy the System.Data.SqlClient.dll and sni.dll files to a fixed path: ..\SQLClient\win-x64\

  • In csproj file make the conditional reference to the nuget package and to published dll, in this case through the parameter MSBuild NativeCompilation.

  • Finally, publish with CoreRT from the command line: dotnet publish -r win-x64 / p: NativeCompilation = true

And it worked!


GetIPVersionSQLSRV.csproj

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <OutputType>Exe</OutputType>
  </PropertyGroup>

  <ItemGroup Condition="'$(BuildingInsideVisualStudio)' == 'true' OR '$(NativeCompilation)' != 'true'">
    <!--System.Data.SqlClient Nuget Reference -->
    <PackageReference Include="System.Data.SqlClient" Version="4.6.1" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" />
    <!--System.Data.SqlClient References-->
    <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
    <PackageReference Include="System.Security.AccessControl" Version="4.5.0" />
    <PackageReference Include="System.Security.Principal.Windows" Version="4.5.0" />
    <PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
    <!--System.Configuration.ConfigurationManager References-->
    <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.5.0" />
    <PackageReference Include="System.Security.Permissions" Version="4.5.0" />
  </ItemGroup>

  <ItemGroup Condition="'$(BuildingInsideVisualStudio)' != 'true' AND '$(NativeCompilation)'=='true'">
    <!-- ILCompiler and rd.xml -->
    <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="1.0.0-alpha-*" />
    <RdXmlFile Include="rd.xml" />
    <!--System.Data.SqlClient published Dll Reference -->
    <Reference Include="System.Data.SqlClient">
      <HintPath>..\SQLClient\win-x64\System.Data.SqlClient.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

Program.cs

using System;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Net;

namespace GetIPVersionSQLSRV
{
    class Program
    {
        private static String config = ConfigurationManager.AppSettings["texto"];
        private static String cadena = ConfigurationManager.ConnectionStrings["default"].ConnectionString;
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World! " + config);
            using(SqlConnection conn = new SqlConnection(cadena))
            {
                conn.Open();
                using (SqlCommand comm = new SqlCommand("SELECT @@VERSION;", conn))
                    Console.WriteLine(comm.ExecuteScalar());
            }
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"http://api.ipify.org?format=json");
            using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
            using (Stream strm = res.GetResponseStream())
            using (StreamReader read = new StreamReader(strm))
                Console.WriteLine(read.ReadToEnd());
            req = null;

            Console.ReadKey(false);
        }
    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="texto" value="CONFIG2"/>
  </appSettings>
  <connectionStrings>
    <add name="default" connectionString="User ID=user;PWD=p455w0rd;Initial Catalog=master;Data Source=localhost"/>
  </connectionStrings>
</configuration>

rd.xml

<Directives>
    <Application>
        <Assembly Name="System.Configuration.ConfigurationManager">
            <Type Name="System.Configuration.ClientConfigurationHost" Dynamic="Required All"/>
            <Type Name="System.Configuration.AppSettingsSection" Dynamic="Required All"/>
        </Assembly>
    </Application>
</Directives>

nuget.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <packageSources>
    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
    <add key="dotnet-core"
  value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json"/>
<add key="nuget.org"
  value="https://api.nuget.org/v3/index.json" protocolVersion="3"/>
    <add key="nuget" value="https://api.nuget.org/v3/index.json" />
 </packageSources>
</configuration>