Развертывание и выполнение в виде отдельного файла
Объединение всех зависящих от приложения файлов в один двоичный файл предоставляет разработчику приложения привлекательный вариант развертывания и распространения приложения в виде одного файла. Эта модель развертывания была доступна с момента выпуска .NET Core 3.0 и улучшена в .NET 5. Ранее в .NET Core 3.0, когда пользователь запускал приложение с одним файлом, узел .NET Core перед запуском приложения сначала извлекал все файлы в каталог. В .NET 5 этот подход был улучшен, позволяя запускать код напрямую без необходимости извлекать файлы из приложения.
Развертывание одного файла доступно как для модели развертывания, зависящей от платформы , так и для автономных приложений. Размер отдельного файла в автономном приложении будет большим, так как в нем будут содержаться среды выполнения и библиотеки платформы, хотя в .NET 6 можно опубликовать обрезанные файлы, чтобы уменьшить общий размер приложений, совместимых с обрезками. Вариант развертывания в виде одного файла можно сочетать с параметрами публикации ReadyToRun и Обрезка.
Развертывание в виде одного файла несовместимо с Windows 7.
Различия в выходных данных по сравнению с .NET 3.x
В .NET Core 3.x при публикации в виде одного файла создавался ровно один файл, состоящий из самого приложения, зависимостей и других файлов, находящихся в папке во время публикации. При запуске приложения одиночный файл приложения распаковывался в папку и запускался оттуда. Начиная с .NET 5 в исполняемый файл приложения включаются только управляемые библиотеки DLL. При запуске приложения управляемые библиотеки DLL извлекаются и загружаются в память, что позволяет избежать извлечения в папку. В Windows это означает, что управляемые двоичные файлы включаются в пакет с одним файлом, однако собственные двоичные файлы основной среды выполнения представляют собой отдельные файлы. Чтобы включить эти файлы для извлечения и получить ровно один выходной файл, как в .NET Core 3.x, установите для свойства IncludeNativeLibrariesForSelfExtract значение true . Дополнительные сведения об извлечении см. в разделе Включение собственных библиотек.
Несовместимость API
Некоторые API несовместимы с моделью развертывания с одним файлом. Поэтому, возможно, потребуется изменить приложения, если они используют такие API. Если вы работаете со сторонними платформами или пакетами, возможно, они также используют один из таких API и требуют изменения. Распространенная причина многих проблем — это зависимость от путей к файлам или библиотекам DLL, поставляемых с приложением.
В таблице ниже приведены соответствующие сведения об API библиотеки среды выполнения для использования с одним файлом.
| API | Примечание |
|---|---|
| Assembly.CodeBase | Выдает исключение PlatformNotSupportedException. |
| Assembly.EscapedCodeBase | Выдает исключение PlatformNotSupportedException. |
| Assembly.GetFile | Выдает исключение IOException. |
| Assembly.GetFiles | Выдает исключение IOException. |
| Assembly.Location | Возвращает пустую строку. |
| AssemblyName.CodeBase | Возвращает null . |
| AssemblyName.EscapedCodeBase | Возвращает null . |
| Module.FullyQualifiedName | Возвращает строку со значением <Unknown> или вызывает исключение. |
| Module.Name | Возвращает строку со значением <Unknown> . |
Вот некоторые рекомендации по исправлению для распространенных сценариев:
Чтобы получить доступ к файлам, расположенным рядом с исполняемым файлом, используйте AppContext.BaseDirectory.
Чтобы найти имя исполняемого файла, используйте первый элемент Environment.GetCommandLineArgs() или, начиная с .NET 6, используйте имя файла из ProcessPath.
Чтобы не допустить доставку свободных файлов в целом, используйте внедренные ресурсы.
Подключение отладчика
В Linux SOS с LLDB — это единственный отладчик, который может подключаться к автономным процессам с одним файлом или выполнять отладку аварийных дампов.
В Windows и Mac для отладки аварийных дампов можно использовать Visual Studio и VS Code. Для подключения к исполняемому файлу выполняемого автономного приложения с одним файлом требуется дополнительный файл: mscordbi. .
При отсутствии этого файла Visual Studio может выдать сообщение об ошибке, информирующее о том, что не удается присоединиться к процессу, компонент отладки не установлен. «и VS Code может вызвать ошибку» не удалось присоединиться к процессу: неизвестная ошибка: 0x80131c3c «.
Чтобы устранить эти ошибки, нужно скопировать mscordbi и вставить рядом с исполняемым файлом. по умолчанию mscordbi является ED в подкаталоге с идентификатором среды выполнения приложения. так, например, если бы один из них был опубликован автономного исполняемого файла с одним файлом с помощью dotnet интерфейса командной строки для Windows с помощью параметров -r win-x64 , исполняемый файл будет помещен в dotnet . Копия mscordbi.dll будет находиться в папке bin/debug/NET 5.0/Win-x64.
Включение собственных библиотек
По умолчанию один файл не включает собственные библиотеки. В Linux предварительно связывается среда выполнения с пакетом, а в каталоге, в котором размещается приложение с одним файлом, развертываются только собственные библиотеки приложения. В Windows предварительно связывается только код размещения, а в каталоге, в котором размещается приложение с одним файлом, развертываются как библиотеки среды выполнения, так и собственные библиотеки приложения. Это позволяет обеспечить эффективную отладку, для которой требуется, чтобы собственные файлы были исключены из одного файла.
Начиная с .NET 6 среда выполнения включена в пакет на всех платформах.
Можно задать флаг IncludeNativeLibrariesForSelfExtract , чтобы включить собственные библиотеки в один пакет, но эти файлы будут извлечены в каталог на клиентском компьютере при запуске приложения с одним файлом.
При указании IncludeAllContentForSelfExtract будут извлечены все файлы (даже управляемые сборки) перед запуском исполняемого файла. Это позволяет сохранить исходное поведение развертывания одного файла в .NET Core.
При извлечении файлы извлекаются на диск перед запуском приложения:
- Если для переменной среды DOTNET_BUNDLE_EXTRACT_BASE_DIR задан путь, файлы будут извлечены в каталог по этому пути.
- В противном случае при запуске в Linux или MacOS файлы будут извлечены в каталог в $HOME/.net .
- При запуске в Windows файлы будут извлечены в каталог в %TEMP%/.net .
Чтобы предотвратить незаконное изменение, эти каталоги не должны быть доступны для записи пользователями или службами с разными привилегиями (поэтому не/tmp или /Вар/ТМП в большинстве систем Linux и MacOS).
В некоторых средах Linux (например, в системе) Извлечение по умолчанию не будет работать, так как не определено. В таких случаях рекомендуется явно задать значение $DOTNET_BUNDLE_EXTRACT_BASE_DIR .
Для обеспечения нормальной работы рекомендуется определить DOTNET_BUNDLE_EXTRACT_BASE_DIR в файле единицы службы, как , что система разворачивается правильно для $HOME/.net учетной записи, в которой выполняется служба.
Другие замечания
Все связанные PDB-файлы будут храниться рядом с приложением с одним файлом, и они не будут упакованы по умолчанию. Если вы хотите включить PDB в сборку для создаваемых проектов, задайте для embedded параметра DebugType значение, как описано DebugType .
Управляемые компоненты C++ не подходят для развертывания с одним файлом. Поэтому рекомендуется писать приложения на C# или другом неуправляемом языке на базе C++, если требуется совместимость с развертыванием в одном файле.
Исключить файлы из внедрения
Некоторые файлы можно явно исключить из внедрения в один файл, установив следующие метаданные.
Например, чтобы поместить некоторые файлы в каталог публикации, но не объединять их в один файл, укажите следующие параметры.
Добавление PDB-файлов в пакет
PDB-файл для сборки можно внедрить в саму сборку ( .dll ), используя параметр, приведенный ниже. Так как символы являются частью сборки, они также будут частью приложения с одним файлом:
Например, добавьте следующее свойство в файл проекта сборки, чтобы внедрить PDB-файл в эту сборку:
Сжатие сборок в приложении с одним файлом
Начиная с .NET 6, можно создавать приложения с одним файлом, включая в них сжатие внедренных сборок. Для этого задайте для свойства EnableCompressionInSingleFile значение true . Созданный одиночный файл будет содержать все внедренные сборки, что может значительно уменьшить размер исполняемого файла. Однако из-за этого может снизиться производительность. При запуске приложения сборки распаковываются в память, что занимает некоторое время. Рекомендуется оценить влияние активации функции сжатия на размер и начальные затраты, прежде чем использовать эту функцию, так как в конечном счете результат может быть разным для различных приложений.
Публикация приложения с одним файлом — пример файла проекта
Ниже приведен пример файла проекта, в котором задана публикация одного файла:
Эти свойства имеют следующие функции:
- PublishSingleFile — включение однофайловой публикации. Также включает однофайловые предупреждения во время dotnet build .
- SelfContained — определение того, будет ли приложение автономным или зависимым от платформы.
- RuntimeIdentifier — Указывает целевой RuntimeIdentifier . Также задает по <SelfContained>true</SelfContained> умолчанию.
- PublishReadyToRun — Включает PublishReadyToRun .
Примечания.
- Приложения с одним файлом всегда связаны с конкретной ОС и архитектурой. Необходимо опубликовать приложение для каждой конфигурации, например Linux x64, Linux ARM64, Windows x64 и т. д.
- Файлы конфигурации среды выполнения, такие как *. runtimeconfig. JSON и *. Deps. JSON, включаются в один файл. Если требуется дополнительный файл конфигурации, его можно поместить вместе с одним файлом приложения.
Публикация приложения с одним файлом с помощью CLI
Опубликуйте приложение с одним файлом с помощью команды dotnet publish.
Добавьте <PublishSingleFile>true</PublishSingleFile> в файл проекта.
Это приведет к созданию однофайлового приложения при автономной публикации. При сборке также отображаются предупреждения о совместимости с одним файлом.
Опубликуйте приложение как для определенного идентификатора среды выполнения с помощью dotnet publish -r <RID>
В следующем примере приложение для Windows публикуется как автономное приложение с одним файлом.
dotnet publish -r win-x64
В следующем примере приложение для Linux публикуется как зависимое от платформы приложение с одним файлом.
dotnet publish -r linux-x64 —self-contained false
В файле проекта следует задать <PublishSingleFile> , чтобы включить анализ одного файла во время сборки, однако эти параметры также можно передать в качестве аргументов dotnet publish :
Публикация приложения с одним файлом с помощью Visual Studio
Visual Studio создает многократно используемые профили публикации, которые управляют процессом публикации приложения.
Добавьте <PublishSingleFile>true</PublishSingleFile> в файл проекта.
В обозревателе решений щелкните правой кнопкой мыши проект, который нужно опубликовать. Нажмите кнопку Опубликовать.

Если у вас еще нет профиля публикации, следуйте инструкциям по его созданию и выберите Папка в качестве типа целевого объекта.
Нажмите кнопку Изменить.

В диалоговом окне Параметры профиля задайте следующие параметры.
- Параметру Режим развертывания задайте значение Автономное или Зависимое от платформы.
- В качестве значения параметра Целевая среда выполнения укажите платформу, на которую будет выполнена публикация. (Значение должно быть отличным от Переносимый.)
- Выберите Создать отдельный файл.
Нажмите кнопку Сохранить, чтобы сохранить параметры и вернуться в диалоговое окно Публикация.

Чтобы опубликовать приложение с одним файлом, нажмите кнопку Опубликовать.
Публикация приложения с одним файлом с помощью Visual Studio для Mac
В Visual Studio для Mac отсутствует возможность публикации приложения в виде одного файла. Вам потребуется опубликовать приложение вручную, выполнив инструкции из раздела Публикация приложения с одним файлом с помощью CLI. Дополнительные сведения см. в статье Публикация приложений .NET с помощью интерфейса командной строки.
Создание проекта в VisualStudio

После установки Visual Studio можно приступать к созданию первого проекта. В Visual Studio редко когда требуется начинать с пустого файла и добавления в него кода C#. (Разумеется, возможность создания пустого проекта приложения существует. Это нужно, если действительно возникла потребность в написании кода с нуля, либо при создании решения, которое должно содержать в себе несколько проектов.)
Вместо этого, необходимо просто указать Visual Studio, проект какого типа должен быть создан, и среда автоматически сгенерирует файлы и код C#, образующие соответствующий указанному типу проекта каркас. Далее останется добавить в этот каркас собственный код.
Давайте создадим консольное приложение, выбрав в меню File (Файл) пункт New — Project (Создать — Проект):

Как можно увидеть на рисунке, в Visual Studio поддерживается возможность выбора версии .NET Framework (2.0, 3.x или 4.0), для которой должно создаваться приложение, с помощью раскрывающегося списка, отображаемого в правом верхнем углу диалогового окна New Project (Новый проект).
Solution Explorer
Утилита Solution Explorer (Обозреватель решений), доступная через меню View (Вид), позволяет просматривать набор всех файлов с содержимым и ссылаемых сборок, которые входят в состав текущего проекта:

Обратите внимание, что внутри папки References (Ссылки) в окне Solution Explorer отображается список всех сборок, на которые в проекте были добавлены ссылки. В зависимости от типа выбираемого проекта и целевой версии .NET Framework, этот список выглядит по-разному.
Добавление ссылок на внешние сборки
Если необходимо сослаться на дополнительные сборки, щелкните на папке References правой кнопкой мыши и выберите в контекстном меню пункт Add Reference (Добавить ссылку). После этого откроется диалоговое окно, позволяющее выбрать желаемые сборки (в Visual Studio это аналог параметра /reference в компиляторе командной строки). На вкладке Assemblies этого окна, показанной на рисунке, отображается список наиболее часто используемых сборок .NET; на вкладке Browse (Обзор) предоставляется возможность найти сборки .NET, которые находятся на жестком диске; на вкладке Recent (Недавние) приводится перечень сборок, на которые часто добавлялись ссылки в других проектах:

Просмотр свойств проекта
И, наконец, напоследок важно обратить внимание на наличие в окне утилиты Solution Explorer пиктограммы Properties (Свойства). Двойной щелчок на ней приводит к открытию редактора конфигурации проекта, окно которого называется Project Properties (Свойства проекта):

В этом окне можно устанавливать различные параметры безопасности, назначать сборке надежное имя, развертывать приложение, вставлять необходимые для приложения ресурсы и конфигурировать события, которые должны происходить перед и после компиляции сборки.
Утилита Object Browser
В Visual Studio доступна еще одна утилита для изучения множества сборок, на которые имеются ссылки в текущем проекте. Называется эта утилита Object Browser (Браузер объектов) и получить к ней доступ можно через меню View. После открытия ее окна останется просто выбрать сборку, которую требуется изучить:

Отличие проектов от решений
Одной из важных вещей, которые необходимо понимать, является понимание разницы между проектом и решением:
Под понимается набор всех файлов исходного кода и ресурсов, которые будут компилироваться в единственную сборку (или в ряде случаев — в единственный модуль). Например, проектом может быть библиотека классов или приложение Windows с графическим пользовательским интерфейсом.
Под решением (solution) понимается набор всех проектов, которые будут образовывать определенный программный пакет (приложение).
Чтобы еще больше прояснить, в чем состоит отличие между проектом и решением, давайте посмотрим, что происходит при поставке проекта, состоящего из нескольких сборок. Например, это может быть интерфейс пользователя, специальные элементы управления и другие компоненты, поставляемые в виде библиотек в отдельных частях приложения. Кроме того, может существовать другой пользовательский интерфейс, предназначенный специально для администраторов. Каждая из этих частей приложения может содержаться внутри отдельной сборки и, следовательно, рассматриваться в Visual Studio как отдельный проект. Однако существует вероятность того, что все эти части будут кодироваться параллельно в сочетании друг с другом. В таком случае полезно иметь возможность редактировать их в Visual Studio как единое целое. Visual Studio позволяет делать это, рассматривая все проекты как образующие одно решение и воспринимая это решение как единый компонент, который должен считываться и делаться доступным для работы.
Как скомпилировать единый exe файл в проекте Visual Studio?

Вам нужно опубликовать Build -> Publish приложение, в параметрах публикации выбрать Folder, далее выбрать win-x64 файл и поставить галочку Produce single file.
Публикация приложения с одним файлом с помощью Visual Studio
- В обозревателе решений щелкните правой кнопкой мыши проект, который нужно опубликовать. Нажмите кнопку Опубликовать.

Если у вас еще нет профиля публикации, следуйте инструкциям по его созданию и выберите Папка в качестве типа целевого объекта. - Нажмите кнопку Изменить.

- В диалоговом окне Параметры профиля задайте следующие параметры.
- Параметру Режим развертывания задайте значение Автономное или Зависимое от платформы.
- В качестве значения параметра Целевая среда выполнения укажите платформу, на которую будет выполнена публикация. (Значение должно быть отличным от Переносимый.)
- Выберите Создать отдельный файл. Нажмите кнопку Сохранить, чтобы сохранить параметры и вернуться в диалоговое окно Публикация.

- Чтобы опубликовать приложение с одним файлом, нажмите кнопку Опубликовать.
По поводу того, чем опции Self-contained и Framework-dependent отличаются, я ранее рассказывал здесь.
Если все прошло хорошо, профиль публикации Properties\PublishProfiles\FolderProfile.pubxml будет выглядеть вот так
А в интерфейсе публикации оно будет выглядеть так

Примечание для .NET 5 и более новых версий
Так как в .NET 5 оптимизировали технологию запуска приложения из одиночного файла, теперь по умолчанию он не включает в себя нативные библиотеки, а включает только управляемые.
Если ваша сборка зависит от нативных библиотек, и вы столкнулись с тем, что dll файлы при публикации все равно лежат отдельно, то чтобы это вылечить, в первую секцию <PropertyGroup> .cproj файла нужно добавить опцию: