Как запечь зависимости в консольной программе 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 обработчик. [У меня нет времени сейчас, но посмотрю позже...]

Другие вопросы по тегам