Как запечь зависимости в консольной программе C#?
У меня есть C#
консольная программа, которая использует nuget
плагин SocketIO4Net
Когда я строю exe
и перенести его на мой сервер Windows 2008, он не работает, тогда как на моей локальной машине он работает.
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'SocketIOClient, Version=0.6.26.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Есть ли способ, которым я могу испечь все свои зависимости в exe
?
Я пытался сделать:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var resName = "converter.SocketIOClient.dll";
var thisAssembly = Assembly.GetExecutingAssembly();
using (var input = thisAssembly.GetManifestResourceStream(resName))
{
return input != null
? Assembly.Load(StreamToBytes(input))
: null;
}
};
Но это не сработало. Возможно, я получаю resourceName
неправильно?
2 ответа
Вот мой пример, который основан на встраивании одной dll в другую как встроенный ресурс, а затем вызывает ее из моего кода, но имеет несколько полезных снимков экрана.
using System;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using MyEmbbedFile;
namespace ProjectNameSpace
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var resName = "ProjectNameSpace.MyEmbbedFile.dll";
var thisAssembly = Assembly.GetExecutingAssembly();
using (var input = thisAssembly.GetManifestResourceStream(resName))
{
return input != null
? Assembly.Load(StreamToBytes(input))
: null;
}
};
}
private void button1_Click(object sender, EventArgs e)
{
MyEmbbedFileApp app = new MyEmbbedFileApp();
app.DoStuff();
}
private static byte[] StreamToBytes(Stream input)
{
var capacity = input.CanSeek ? (int)input.Length : 0;
using (var output = new MemoryStream(capacity))
{
int readLength;
var buffer = new byte[4096];
do
{
readLength = input.Read(buffer, 0, buffer.Length);
output.Write(buffer, 0, readLength);
}
while (readLength != 0);
return output.ToArray();
}
}
}
}
Есть еще 2 вещи, которые вам нужно будет сделать:
Вам все равно нужно будет убедиться, что вы добавили свою сборку в качестве ссылки, чтобы ваш код компилировался. Просто убедитесь, что он не копируется в выходной каталог.
Второе, что вам нужно сделать, это добавить ссылку на проект в виде обычного файла. Затем установите его действие сборки в Embedded Resource в свойствах.
Да.
Используйте AppDomain.AssemblyResolve, чтобы "гидрировать" встроенные сборки во время выполнения.
Этот проект SQLDiagCmd на Github содержит пример этого. Он основан на методе Джеффри Риктера:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
"Хитрость" - это то, где находится встроенная сборка и (как вы уже нашли) строка, используемая для ссылки на нее в AssemblyResolve
обработчик. [У меня нет времени сейчас, но посмотрю позже...]