Cannot run multi-file dotnet core 2 assembly
mmoerman opened this issue · 3 comments
With a stable deploy of Kubeless 1.0.6 have the following issue:
I have a dotnet C# project with 3 files. 2 Code (cs files) and 1 cert for accessing a cockroach db.
The csproj file is as follows:
dbtest.csproj:
Project Sdk="Microsoft.NET.Sdk">
I zip the 3 files as follows:
zip dbtest.zip DbTest.cs DbConnection.cs certs/client.roach.crt
And then deploy as follows:
kubeless function deploy dbtest --from-file dbtest.zip --handler module.handler --dependencies dbtest.csproj --runtime dotnetcore2.0
The compilation stage and preparation stage work fine but when the POD tries to start the following error occurs.
Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
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 Kubeless.Core.Invokers.CompiledFunctionInvoker.LoadAssemblyDepedencies() in /app/src/Kubeless.Core/Invokers/CompiledFunctionInvoker.cs:line 29
at kubeless_netcore_runtime.Startup.ConfigureServices(IServiceCollection services) in /app/src/Kubeless.WebAPI/Startup.cs:line 47
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
at kubeless_netcore_runtime.Program.BuildWebHost(String[] args) in /app/src/Kubeless.WebAPI/Program.cs:line 23
at kubeless_netcore_runtime.Program.Main(String[] args) in /app/src/Kubeless.WebAPI/Program.cs:line 18
Here is the code fro the 2 code files I use:
DbConnection.cs - is a support class:
sing System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using Npgsql;
public class DBConnection {
private NpgsqlConnection conn = null;
private X509Certificate cert = null;
private X509Certificate getCertificate() {
if (cert == null) {
Assembly assembly = this.GetType().Assembly;
Stream resource = assembly.GetManifestResourceStream("dbtest.certs.client.roach.crt");
int length = (int)resource.Length;
byte[] data = new byte[length];
resource.Read(data, 0, length);
cert = new X509Certificate(data);
}
return cert;
}
public NpgsqlConnection getConnecion() {
if (conn == null) {
var connectionString = new NpgsqlConnectionStringBuilder {
Host = "localhost",
Port = 26257,
Username = "roach",
Password = "blabla",
Database = "dbtest",
SslMode = SslMode.Require,
TrustServerCertificate = true
}.ConnectionString;
conn = new NpgsqlConnection(connectionString);
conn.ProvideClientCertificatesCallback += (clientCerts) => {
clientCerts.Add(getCertificate());
};
conn.Open();
}
return conn;
}
~DBConnection() {
if (conn != null) {
conn.Close();
}
}
}
DbTest.cs - is the main module:
using System;
using Kubeless.Functions;
using Npgsql;
public class module
{
private DBConnection connection = new DBConnection();
public object handler(Event k8Event, Context k8Context)
{
var conn = connection.getConnecion();
// Insert some data
var cmd = new NpgsqlCommand("INSERT INTO data (some_field) VALUES (@p)", conn);
cmd.Parameters.AddWithValue("p", "Hello world");
cmd.ExecuteNonQuery();
// Retrieve all rows
var result = "{values: [";
var reader = new NpgsqlCommand("SELECT some_field FROM data", conn).ExecuteReader();
while (reader.Read()) {
if (result.Length == 0)
result = "{values: [" + reader.GetString(0);
else
result += ", " + reader.GetString(0);
};
result += "]}";
return result;
}
}
Hi!
Thanks for raising this. Currently dotnet runtime can't handle multiple files (since it internally doesn't handle different files linking). We are open to contributions in order fix that!
On the other hand, in this meanwhile, if you try to use it with a single file, it should work.
I've just done that. in compile-function.sh
, there is a check if there is a module.cs
, then use cs compiler, if there is module.fs
then use fs compiler, otherwise use vb compiler. test also requires file size to be greater than zero.
if your multi file project does not have a module.cs
, then image compiles it using vb, producing a 4kb dll with no executable code.
I've created a multiple file project, and cannot make it work until I created a dummy module.cs
only with a comment. then it works.
I think I've also found a more effective way to check for files after spending some time with stackexchange, I'd like to send it as a push request, but I have no idea how to test it in kubeless, so here it is.
#!/bin/bash
CSFILE=$(find . -maxdepth 1 -size 1 \( -name \*.cs \) -print -quit)
VBFILE=$(find . -maxdepth 1 -size 1 \( -name \*.vb \) -print -quit)
if [[ -s $VBFILE ]]; then
echo found some vb files $VBFILE
elif [[ -s $CSFILE ]]; then
echo found some cs files $CSFILE
else
echo fs it is
fi
I also facing the same limitation of the dotnetcore3.1 runtime. Can you add zipped source code support?