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?
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>