Runtime: Поддержка однофайлового распространения

Созданный на 5 окт. 2018  ·  225Комментарии  ·  Источник: dotnet/runtime

Эта проблема отслеживает ход выполнения функции распространения одного файла .NET Core 3.0.
Вот дизайн-документ и план создания этой функции.

area-Single-File

Самый полезный комментарий

Ожидается, что первый запуск будет намного медленнее — приложение извлекается на диск — так много операций ввода-вывода.

Этого никогда не должно было случиться, вы делаете пользовательский опыт ужасным ПО ДИЗАЙНУ, ужасным выбором, вот как вы заставляете пользователей ненавидеть технологию, которую разработчик использует для них.

Как уже упоминалось @Safirion , мы работаем над следующим улучшением для одного файла, который должен запускать большую часть управляемого кода из .exe напрямую (без извлечения на диск). Пока не могу обещать выпуск поезда.

Зачем выпускать это официально сейчас, если это скоро изменится? должен быть помечен как предварительный/экспериментальный

на мой взгляд, это пустая трата времени и ресурсов, сосредоточьтесь на компиляции AOT и древотрясении, поместите туда все свои ресурсы, перестаньте заниматься хаками

Все 225 Комментарий

Ради интереса, как эта инициатива соотносится с CoreRT? Они кажутся похожими усилиями?

Связано ли это с « возможно, собственным кодом пользователя », то есть это по-прежнему позволит компилировать код JIT, а не только AOT?

Кроме того, я предполагаю, что компоненты среды выполнения (« Собственный код (среда выполнения, хост, собственные части фреймворка... ») будут из репозитория CoreCLR?

Вы задаете отличные вопросы, но, поскольку это все еще находится на ранней стадии разработки, у меня пока нет хороших ответов.

Ради интереса, как эта инициатива соотносится с CoreRT? Они кажутся похожими усилиями?

Скорее всего, будут похожие результаты (один файл), но дизайн может иметь разные характеристики производительности или функции, которые работают/не работают. Например, возможной схемой может быть объединение всех файлов автономного приложения .NET Core в один файл. Это 10 МБ и может начаться медленнее, но, с другой стороны, это позволит использовать все возможности CoreCLR, включая загрузку плагинов, отражение и расширенную диагностику. CoreRT можно считать другим концом спектра — это однозначное число МБ и очень быстрое время запуска, но из-за отсутствия JIT он не может загружать плагины или использовать отражение, а время сборки медленнее, чем у большинства . NET-разработчики привыкли. В настоящее время у него есть несколько других ограничений, которые со временем могут быть устранены, но могут не быть улучшены в .NET Core 3.0 (возможно, требуются аннотации для отражения, отсутствуют некоторые сценарии взаимодействия, ограниченная диагностика в Linux). Есть также идеи где-то между ними. Если у людей есть компромиссы, которые они хотели бы сделать или избежать, нам было бы любопытно узнать о них.

Связано ли это с «возможно, собственным пользовательским кодом», то есть это все еще позволит JIT-компилировать код, а не только AOT?

Под «собственным кодом пользователя» я имел в виду, что ваше приложение может иметь некоторый собственный код C++ (написанный вами или сторонним компонентом). Могут быть ограничения на то, что мы можем делать с этим кодом — если он скомпилирован в .dll, единственный способ запустить его — вне диска; если это .lib, возможно, его можно связать, но это приводит к другим осложнениям.

Кроме того, я предполагаю, что компоненты среды выполнения («Собственный код (среда выполнения, хост, собственные части фреймворка...») будут из репозитория CoreCLR?

Исходя из всего вышесказанного, разберемся, какие репозитории задействованы. «Нативные части фреймворка» будут включать собственные файлы CoreFX, такие как ClrCompression и Unix PAL.

Распределение одного файла таким образом, даже если время запуска несколько медленнее, может быть бесценным для простоты развертывания. Я бы предпочел иметь возможность обладать полной властью, чем быть вынужденным отказаться от части этого.

Некоторые сценарии, которые представляют для нас интерес. Как это будет работать с точки зрения кроссплатформенности?
Я предполагаю, что у нас будет отдельный «файл» для каждой платформы?

Что касается нативного кода, как я могу выбирать различные нативные компоненты в зависимости от платформы?

Некоторые сценарии, которые представляют для нас интерес. Как это будет работать с точки зрения кроссплатформенности?
Я предполагаю, что у нас будет отдельный «файл» для каждой платформы?
Что касается нативного кода, как я могу выбирать различные нативные компоненты в зависимости от платформы?

@ayende , я цитирую комментарий @morganbr :

возможный дизайн может состоять в том, чтобы по существу объединить все файлы в автономном приложении .NET Core в один файл.

Текущая кроссплатформенная история автономных приложений заключается в создании пакета развертывания для каждой платформы, на которую вы хотите ориентироваться, потому что вы отправляете приложение со средой выполнения, которая зависит от платформы.

@morganbr Я ценю, что вы нашли время, чтобы дать такой подробный ответ

Мне будет интересно посмотреть, куда пойдет дизайн, это действительно интересная инициатива.

У меня есть несколько вопросов к людям, которые хотели бы использовать один файл. Ваши ответы помогут нам сузить наши возможности:

  1. С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)
  2. Включает ли ваше приложение (не .NET) C++/собственный код?
  3. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?
  4. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?
  5. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?
  6. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?
  7. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?
  8. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?
  1. Консольное/UI-приложение на всех платформах.
  2. Возможно, как сторонний компонент.
  3. Возможно, да.
  4. Да, особенно если есть простая система типа ClickOnce.
  5. Некоторое начальное замедление можно допустить. Может ли пункт 3 помочь с этим?
  6. Зависит от активов. Привет, мир должен иметь размер порядка МБ.
  7. Неважно, если это просто производство.
  8. Нравится добавление в белый список вещей для отражения? да.

@morganbr , как вы думаете, эти вопросы лучше задавать более широкой аудитории; т.е. шире, чем люди, которые знают об этой проблеме GitHub?

Например, возможной схемой может быть объединение всех файлов автономного приложения .NET Core в один файл.

Глядя на сжатие его; или с использованием сжатой файловой системы в файле?

@tpetrina , спасибо! Пункт 3 охватывает несколько аспектов дизайна:

  1. Встряхивание дерева не очень хорошо сочетается с загрузкой плагинов, которые шейкер дерева не видел, поскольку это может исключить код, на который опирается плагин.
  2. В настоящее время CoreRT не имеет возможности загружать плагины.
    Пункт 5 больше о том, будем ли мы оптимизировать размер или время запуска (и насколько)
    Пункт 8, да, я в основном думал о размышлениях

@TheBlueSky , мы также связались с другими людьми, но это помогает получить информацию от увлеченных людей в сообществе GitHub.

@benaadams , сжатие обсуждается, но в настоящее время я думаю об этом как о ортогональном общем дизайне. Легкие эксперименты показывают, что архивация может уменьшить размер примерно на 50% за счет нескольких секунд времени запуска (и времени сборки). Для меня это достаточно радикальный компромисс, и если мы это сделаем, это должно быть необязательным.

@morganbr несколько секунд времени запуска при использовании сжатия? Мне трудно поверить, учитывая, что UPX заявляет о скорости декомпрессии

~10 МБ/с на древнем Pentium 133, ~200 МБ/с на Athlon XP 2000+.

@morganbr , для меня ответы таковы:

1) Служба (в основном консольное приложение под управлением Kestrel). Работает как служба Windows/демон Linux или в докере.
2) Да
3) Да, обычно управляемые сборки используют AssemblyContext.LoadFrom . Они предоставляются конечным пользователем.
4) Да, это ожидаемо. На самом деле, мы в любом случае уже связываем всю структуру, так что с этой точки зрения никаких изменений.
5) Как сервис, нас не волнует время запуска. 5 секунд было бы разумно.
6) 75Мб наверное предел. Многое зависит от фактического сжатого размера, так как все пакеты доставляются сжатыми.
7) Для выпускных сборок допустимо более длительное (даже намного более длительное) время сборки.
8) Да, абсолютно. Размер не так важен, но чем меньше, тем лучше.

Что-то, о чем я не упоминал, и это очень важно, это возможность отладки этого.
Я надеюсь, что это не испортит трассировку стека, и мы хотели бы иметь возможность включать файлы pdb или какие-то символы отладки.

Что касается сжатия, примите во внимание тот факт, что почти во всех случаях фактический механизм доставки уже сжат.
Например, пакеты nuget.
Пользователи также довольно хорошо разбираются в распаковке, так что это не большая проблема.
Я думаю, вы можете сделать компрессию сбоку.

Спасибо, @ayende! Вы правы в том, что я должен был упомянуть об отладке. Я думаю, что есть только несколько незначительных способов повлиять на отладку:

  1. Может оказаться невозможным использовать команду «Редактировать и продолжить» для одного файла (из-за необходимости перестроить и перезагрузить исходную сборку).
  2. Однофайловая сборка может создать PDB или некоторые другие файлы, необходимые для отладки помимо тех, которые поставляются с вашими сборками.
  3. Если используется CoreRT, у него могут быть некоторые функции отладки, которые со временем заполняются (особенно в Linux/Mac).

Когда вы говорите «включить pdb-файлы», вы хотите, чтобы эти _внутри_ одного файла или просто возможность их генерировать и использовать на случай, если вам понадобится отладить однофайловую сборку?

1) Для нас это не проблема. E&C здесь неуместны, поскольку они, скорее всего, будут использоваться только для фактического развертывания, а не для повседневного использования.
2) В идеале у нас один файл на все, включая PDB, а не один файл и набор pdb на стороне. Уже есть встроенный вариант PDB, если бы он работал, было бы здорово.
3) Говоря об отладке, я имею в виду время производства, а не подключение отладчика в реальном времени. В частности, информация о трассировке стека, включая номера файлов и строк, возможность разрешения символов при чтении дампа и т. д.

  1. В основном сервисы, но некоторый пользовательский интерфейс
  2. Некоторые делают, но это не будет срочно
  3. да
  4. да
  5. несколько секунд нормально
  6. Нам все равно. Сумма размера dll в порядке
  7. В идеале не
  8. Размер для нас не имеет первостепенного значения

Другой вопрос для нас: сможете ли вы сделать это и для отдельных компонентов (возможно, даже поэтапно)? Например, у нас есть библиотеки dll, которые используют множество зависимостей. Если бы мы могли упаковать их, это избавило бы от многих проблем с управлением версиями и т. Д. Если бы их, в свою очередь, можно было бы упаковать в exe, это было бы еще лучше?

  1. Сервисы и некоторый пользовательский интерфейс.
  2. Не в данный момент.
  3. да. В идеале плагины, которые можно загрузить из папки и перезагрузить во время выполнения.
  4. да
  5. Не проблема, пока мы не нажимаем 10-15+.
  6. Сумма размеров DLL или аналогичная.
  7. да. Для производственной сборки время на самом деле не является проблемой, если сборки для отладки/тестирования строятся достаточно быстро.
  8. Зависит, но вариант был бы удобен.
  1. Сервис и интерфейс.
  2. Иногда.
  3. Да, обычно.
  4. да.
  5. Лучше не более 5 секунд.
  6. Пользовательский интерфейс менее 5 секунд, Сервис не имеет значения.
  7. Время сборки не важно, главное эффект от оптимизации.
  8. да.

@tpetrina @ayende @bencyoung @Kosyne @expcat вы ответили «да» на вопрос 3 («Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку вашего приложения?») — можете ли вы рассказать нам больше о своем использовании кейс?

Основным преимуществом распространения одного файла является то, что для распространения доступен только один файл. Если в вашем приложении есть плагины в отдельных файлах, какую ценность вы получите от одного дистрибутива, который в любом случае содержит несколько файлов? Почему «app.exe+plugin1.dll+plugin2.dll» лучше, чем «app.exe+coreclr.dll+clrjit.dll+...+plugin1.dll+plugin2.dll»?

app.exe + 300+ dll - текущее состояние на сегодняшний день действительно неудобно.
app.exe + 1-5 dll, которые обычно определяет сам пользователь, намного проще.

Наш сценарий заключается в том, что мы разрешаем определенные расширения пользователем, поэтому обычно мы развертываем только один exe , а пользователь может добавлять дополнительные функции по мере необходимости.

Дело не столько в том, что мы _планируем_ сделать это, но мы хотим _быть в состоянии_ сделать это, если возникнет необходимость.

@ayende Согласен, то же самое и с нами.

Кроме того, если бы мы могли сделать это на уровне dll, мы могли бы упаковать зависимости внутри наших сборок, чтобы они не конфликтовали с клиентскими сборками. Т.е. выбирая версию NewtonSoft.Json вы в данный момент определяете ее для всех программ, плагинов и сторонних сборок в одной папке, но если бы вы могли ее встроить то у третьих сторон есть гибкость и повышается совместимость версий

Согласен с @ayende .

Спасибо, всем за ваши ответы! Основываясь на количестве людей, которые либо будут использовать нативный код, либо должны загружать плагины, мы считаем, что наиболее совместимый подход, которым мы можем управлять, — это правильное место для начала. Для этого мы воспользуемся подходом «упаковать и извлечь».

Это будет инструментарий, который, по сути, встраивает все приложения и файлы .NET в качестве ресурсов в исполняемый файл экстрактора. Когда исполняемый файл запускается, он извлекает все эти файлы во временный каталог, а затем запускается, как если бы приложение было опубликовано как не однофайловое приложение. Это не начнется со сжатия, но мы потенциально можем добавить его в будущем, если это будет оправдано.

Самая сложная деталь этого плана — куда извлекать файлы. Нам нужно учитывать несколько сценариев:

  • Первый запуск — приложение просто нужно распаковать куда-нибудь на диск.
  • Последующие запуски — чтобы не платить за извлечение (вероятно, несколько секунд) при каждом запуске, было бы предпочтительнее, чтобы местоположение извлечения было детерминированным и позволяло второму запуску использовать файлы, извлеченные при первом запуске.
  • Обновление — если запускается новая версия приложения, она не должна использовать файлы, извлеченные старой версией. (Обратное также верно: люди могут захотеть запустить несколько версий одновременно). Это говорит о том, что детерминированный путь должен основываться на содержимом приложения.
  • Удаление — пользователи должны иметь возможность найти извлеченные каталоги, чтобы удалить их при желании.
  • Отказоустойчивость — если первый запуск завершился сбоем после частичного извлечения его содержимого, второй запуск должен повторить извлечение.
  • Запуск с повышенными правами — процессы, запущенные от имени администратора, должны запускаться только из мест, доступных для записи администратору, чтобы предотвратить вмешательство в них процессов с низким уровнем целостности.
  • Запуск без повышенных прав — процессы, запущенные без прав администратора, должны запускаться из мест, доступных для записи пользователем.

Я думаю, что мы можем учесть все это, построив путь, который включает:

  1. Общеизвестный базовый каталог (например, %LOCALAPPDATA%\dotnetApps в Windows и расположения профилей пользователей в других ОС).
  2. Отдельный подкаталог для повышенных
  3. Идентификатор приложения (может быть, просто имя exe)
  4. Идентификатор версии. Числовая версия, вероятно, полезна, но недостаточна, поскольку она также должна включать точные версии зависимостей. Для каждой сборки может подойти руководство или хэш.

Вместе это может выглядеть примерно так: c:\users\username\AppData\Local\dotnetApps\elevated\MyCoolApp\1.0.0.0_abc123\MyCoolApp.dll
(Если приложение называется MyCoolApp, его номер версии — 1.0.0.0, а его хеш/код — abc123, и оно было запущено с повышенными правами).

Также потребуется работа по встраиванию файлов в экстрактор. В Windows мы можем просто использовать собственные ресурсы, но в Linux и Mac может потребоваться дополнительная работа.

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

CC @swaroop-sridhar @jeffschwMSFT @vitek-karas

Я чувствую, что это лекарство хуже, чем болезнь. Если нам приходится иметь дело с внешними каталогами (разными для разных ОС), обновлением, удалением и т.п., это идет вразрез с моим желанием использовать эту функцию в первую очередь (сохраняя все простым, переносимым, автономным и чистым).

Если это абсолютно необходимо, для моего проекта я бы предпочел, чтобы один основной исполняемый файл и распакованные файлы находились в каталоге рядом с этим исполняемым файлом или, возможно, возможность решать, куда этот каталог идет.

Это только я, хотя, мне любопытно услышать и от других.

Я должен согласиться здесь, использование другого каталога может иметь много интересных проблем - например, вы помещаете файл конфигурации рядом с exe, и этот exe не подхватывается, потому что «настоящий» каталог находится где-то еще.
Дисковое пространство может быть проблемой, а также случайные блокировки файлов из-за политик доступа и т. д. стр.
Я хотел бы использовать эту функцию, но только не в том случае, если она добавит множество отказоустойчивых режимов, которые невозможно обнаружить раньше.

Согласен с @Kosyne . Предлагаемое первоначальное решение, похоже, просто автоматизирует своего рода «установщик». Если бы это был предел проблемы, которую мы пытаемся решить с помощью одного исполнителя, я думаю, что мы все просто выполнили бы эту автоматизацию сами.

Ключевой целью предложения single exec должна быть возможность запуска исполняемого файла в неуправляемой системе. Кто знает, есть ли у него доступ на запись к любому выбранному целевому каталогу «установки»? Он, конечно же, не должен оставлять артефактов после запуска (не по умолчанию).

В качестве небольшой модификации существующего предложения, чтобы удовлетворить вышеизложенное: нельзя ли распаковать в память и запустить оттуда?

Согласна с остальными комментариями. Распаковка в другое место _уже_ доступна.
У нас может быть самораспаковывающийся zip, который будет довольно легко запускать извлеченные значения. Это не решает многих проблем, на которые это призвано ответить, и является просто другим названием для установки.

Расположение файла важно. Например, в нашем случае это будет означать:

  • Поиск файла конфигурации (который мы генерируем на лету, если его нет, и позволяем пользователю настроить)
  • Поиск/создание файлов данных, которые обычно относятся к исходному exe.
  • PID/имя процесса должны совпадать, чтобы обеспечить надлежащий мониторинг/поддержку.

Одному из наших пользователей нужно запустить наше программное обеспечение с DVD, как это работает, в системе, которая на самом деле может не иметь HD для запуска.

Согласен, что лучше было бы все делать по памяти. И беспокойство по поводу времени запуска не так уж велико, я был бы в порядке, платя за каждый перезапуск или вручную делая шаг, чтобы облегчить это, если это необходимо.

Другой проблемой здесь является фактический размер. Если это просто (фактически) установщик, это означает, что мы говорим о размерах файлов для разумного приложения в сотнях МБ, не так ли?

Кажется, что построение предлагаемого решения не требует (много, если вообще требуется) изменений CLR. Пользователи уже могут создавать подобные решения. Нет смысла добавлять это в CoreCLR. Тем более, что вариант использования для этого довольно узок и специфичен.

@GSPP Кажется, это то, что я могу сделать сегодня с 7z-Extra , я согласен, что в этом случае было бы лучше _не_ иметь его вообще.

Извините, я опоздал на эту вечеринку, я попал сюда после того, как перешел по ссылке, размещенной в дублирующем билете, который я отслеживал.
Прочитав последние комментарии здесь, мне жаль видеть, что вы рассматриваете возможность упаковки и извлечения. Это кажется излишним, почему бы не начать с возможности развертывания SFA для базовых консольных приложений? Мне кажется, что должно быть возможно создать элементарное консольное приложение с некоторой сетью, вводом-выводом и некоторыми внешними зависимостями (nuget и т. д.), которое находится в одном файле.
Я думаю, что я пытаюсь сказать, что вместо того, чтобы собирать требования всех, не собирайте требования ничьих и вместо этого начните с малого с первой итерации, которая имеет смысл для всех и быстро дает результаты.

Кажется, это то, что я могу сделать сегодня с 7z-Extra.

Вы правы в том, что сегодня существует множество независимых от среды программирования решений для решения этой проблемы. Еще один пример из многих: https://www.boxedapp.com/exe_bundle.html

Дополнительным преимуществом здесь будет интеграция в инструментарий dotnet, чтобы даже неопытные пользователи могли легко это сделать. Опытные пользователи могут сделать это уже сегодня, объединив существующие инструменты, как вы указали.

Лично я с вами согласен в том, что непонятно, правильно ли мы здесь делаем выбор. У нас было много дискуссий по этому поводу в основной команде.

Поставить на него стажера и выйти с глобальным инструментом (который рекомендуется, но не поддерживается) будет так же хорошо, и его также можно довольно легко установить.

По сути, мы говорим о dotnet publish-single-file , и это сделает все необходимое за кулисами.

Я не вижу ничего, что на самом деле требуется фреймворку или среде выполнения для поддержки этого сценария, и, делая это явно вне фреймворка, вы предоставите пользователям гораздо больше свободы в том, как это изменить.
Нет «необходимости» получать PR (со всеми сопутствующими церемониями, обратным компактом, безопасностью и т. д.), который вы получили бы, если бы захотели внести изменения в фреймворк.
Вы просто делаете форк общего побочного проекта и используете его.

Обратите внимание, что как бы я ни хотел эту функцию, я бы предпочел не иметь чего-то внутри (что означает, что это _всегда_ будет внутри), что можно было бы сделать так же хорошо извне.

Я хочу задать вопрос более высокого уровня: какова основная мотивация клиентов, желающих распространять один файл?
Это в первую очередь:

  1. Упаковка? Если да, то независимо от того, является ли решение входящим или сторонним инструментом, какие характеристики наиболее важны?
    а) Время запуска (после первого запуска)
    б) Возможность запуска в среде без записи
    в) Не оставлять файлы после запуска
    г) Не нужно запускать установщик
    2) Производительность?
    а) Скорость (статическая компоновка нативного кода, избежание многократной загрузки библиотек, кросс-модульные оптимизации и т. д.)
    б) Размер кода (нужен только один сертификат, встряска дерева и т. д.)
    3) Любые другие?

Я немного обеспокоен тем, что некоторые считают эту функцию не столь важной, или, по крайней мере, не стоит включать ее в основной набор функций. Я хотел бы просто повторить, что я думаю, что это было бы чрезвычайно мощным для любого приложения, которое действует как служба или подмодуль более крупного приложения. Тот, разработчиком которого вы, автор, возможно, даже не являетесь. Я не хочу передавать требования зависимостей, которые могут быть решены только с помощью установок (автоматических или иных), или артефактов после выполнения на диске, которые могут потребовать дополнительного повышения безопасности пользователем и т. д.
Прямо сейчас .NET просто не лучший выбор для этой нишевой проблемы. Но это может быть (и должно быть ИМО).

Скомпилированный исполняемый файл должен:

  • Пакет всех соответствующих зависимостей
  • Нет артефактов выполнения (нет записи на диск)

Re @swaroop-sridhar Я осмелюсь сказать, что каждое приложение будет иметь свой собственный уникальный порядок потребностей в производительности, и поэтому я полагаю, что лучший подход после решения основного решения — выбрать низко висящие плоды и двигаться дальше.

@swaroop-sridhar Для меня это упаковка и простота использования для конечного пользователя.
Не нужно иметь дело с установкой общесистемных вещей, просто нажмите и запустите.

Это важно, потому что мы позволяем встраивать наше программное обеспечение, а надстройкой с одним файлом намного проще управлять.

@strich Вопрос о встраивании хороший. Нас обычно используют в качестве компонента в архитектуре микросервисов, и сокращение накладных расходов на развертывание упростит эту задачу.

Проблема не в том, что это важная особенность. Проблема заключается в том, что предлагаемое решение (по сути, архивирование вещей на данный момент) должно быть _в ядре_.
Материал, который находится в ядре, имеет гораздо более высокие стандарты для изменений. Было бы лучше иметь это как внешний инструмент, потому что его легче модифицировать и расширять.

Честно говоря, я бы предпочел увидеть лучший вариант вообще. Например, можно загружать dll из памяти вместо файлов (требуется некоторая работа, но возможно).
Если это произойдет, вы можете запустить _целую_ вещь исключительно из памяти, при этом распаковка будет выполняться в чистую память и без обращений к диску.

Это то, что должно быть в ядре, потому что для этого, скорее всего, потребуются модификации среды выполнения.
И это было бы ценно само по себе. И не то, что мы можем сделать в настоящее время.

Так что хороший пример — взглянуть на опыт инструментов Go, таких как Consul от Hashicorp. Один исполняемый файл, который вы можете закинуть на любую машину во время запуска. Никаких установщиков, никакого копирования папок, никакой охоты за конфигурационными файлами в списках из сотен файлов, просто действительно приятное взаимодействие с конечным пользователем.

Для нас я не уверен, что подход в памяти будет работать, поскольку мы также хотели бы, чтобы он работал и для dll плагинов (поэтому удаление плагина также будет одним файлом, а не всеми его зависимостями), но любой прогресс будет будь хорошим. Мы посмотрели на Fody.Costura, и он хорошо работает для некоторых вещей, но у нас были проблемы с .NET Core для этого.

Так что хороший пример — взглянуть на опыт использования инструментов Go, таких как Consul от Hashicorp.

Эх, для таких инструментов, как consul, идеальным решением был бы corert, а не эта самоизвлекающаяся импровизация.

@mikedn Почему это? Я не понимаю, какое отношение компиляция AOT или JIT имеет к методу развертывания?

Я хочу поддержать слова @strich , развертывание отдельных файлов было бы глотком свежего воздуха для развертываний микросервисной архитектуры, а также для любого консольного приложения, которое является — или, по крайней мере, начинает свою жизнь — небольшим инструментом с командной строкой. переключатели.

Почему это? Я не понимаю, какое отношение компиляция AOT или JIT имеет к методу развертывания?

Потому что он дает вам именно то, что вы хотите - один exe-файл, который вы можете скинуть на любую машину (ну, на любую машину с подходящей ОС, в конце концов, это родной файл) и запустить. Он также имеет тенденцию использовать меньше ресурсов, что для таких агентов, как консул, хорошо. Это в значительной степени эквивалент того, что дает вам Go, а не самоизвлекающееся решение.

@mikedn Наверное, но

1) В производственной форме (насколько мне известно) его еще не существует!
2) Мы используем много динамических функций (генерация IL, произвольное отражение)
3) Еще хотим иметь возможность добавлять плагины (опять же идеально уплотненные)

Видите ли, поскольку этот выпуск был о том, чтобы спросить людей, чего они хотят, мы всего лишь делимся своим мнением! Мы действительно не хотим переключаться на другую модель времени выполнения только для того, чтобы получить это преимущество. Для меня они ортогональные проблемы

Я не понимаю, какое отношение компиляция AOT или JIT имеет к методу развертывания?

Без JIT легче сделать достаточно хорошо такие вещи, как история отладки. Часть JIT усложняет проблему, поэтому вы не найдете ее в Go. Это инженерия, поэтому вы либо бросаете больше инженеров на более сложную проблему и живете с новой сложностью, либо ограничиваете ее в другом месте. Самораспаковывающийся инструмент ограничен, потому что количество инженеров с необходимыми навыками ограничено.

Люди с проектами, которые больше похожи на проекты Go (без требований JIT), могут быть вполне довольны CoreRT, если их устраивает ярлык «экспериментальный». В наши дни это довольно легко попробовать . Он использует тот же сборщик мусора, генератор кода, CoreFX и большую часть CoreLib, что и полноценный CoreCLR, и создает небольшие исполняемые файлы (мегабайты с одной цифрой), которые являются автономными.

Он еще не существует в производственной форме (насколько мне известно)!

Да, мой комментарий в большей степени был нацелен на людей из МС : grin: . У них есть все эти параллельные, связанные, текущие проекты/идеи (корерт, иллинкер), и теперь они добавляют еще одну, эту самораспаковывающуюся штуку, которая, как многие уже отмечали, немного «ну, мы можем это сделать». сами" типа того. Но у него есть и недостатки, например, извлечение файлов в «скрытый» каталог.

Мы используем множество динамических функций (генерация IL, произвольное отражение)

Это то, что сообщество в целом, возможно, захочет еще раз подумать. Конечно, это полезно, но это противоречит другим желаниям, таким как развертывание одного файла. Вы все еще можете получить развертывание с одним файлом, но это, как правило, дорого обходится — файл довольно большой. Если вас это устраивает, то это прекрасно. Но по моему опыту, чем больше файл, тем менее полезным становится аспект «одного файла».

@MichalStrehovsky Конечно, есть разные варианты. Однако для нас мы не можем использовать экспериментальный вариант (убедиться, что пора переходить на .NET Core, было достаточно сложно), и я не думаю, что извлечение во временную папку будет работать в нашем случае. Однако в худшем случае мы продолжаем работать как есть и не используем эту функцию.

Это то, чего мы хотели бы, если бы все пошло так, как мы хотели бы :)

@mikedn Я согласен. Несколько параллельных решений еще больше сбивают с толку. Я думаю, что нашим идеальным решением был бы какой-то супер подход ILLinker/weaver, но я рад позволить этому разыграться и посмотреть, чем мы закончим.

Я действительно очень взволнован появлением этой функциональности, но, честное слово, я в равной степени не в восторге от первоначального предложения, которое вы разместили @morganbr. Мои ответы на поставленный вами список вопросов аналогичны тому, что задавали другие (поэтому я думаю, что есть общий желаемый набор возможностей), но ИМХО предлагаемое решение «распаковать на диск» — это совсем не то, что я надеюсь увидеть реализовано и, как говорили другие, будет почти хуже, чем «болезнь». @jkotas

Я согласен с @strich и @ayende
Скомпилированный исполняемый файл должен:
Пакет всех соответствующих зависимостей
Нет артефактов выполнения (нет записи на диск)

Загрузка .dll из памяти вместо диска может оказаться непростой задачей, но именно такие возможности IMO стоили бы глубокого опыта низкоуровневых разработчиков MSFT (а затем использования в CoreClr) по сравнению с приведенным выше предложением, которое можно было бы просто реализовать как внешний инструмент (и уже есть, см. https://github.com/dgiagio/warp). Если бы это было достигнуто, интересно, какая разница во времени была бы между первым и последующими запусками? Для вдохновения/примера я думаю, что в Linux 3.17+ есть memfd_create, который может использоваться dlopen.

Что касается другой темы, мне интересно, является ли требование поддержки плагинов чрезмерным индексированием предложения по дизайну? Стоит ли делать эту функцию опциональной, чтобы только люди, которым эта возможность нужна, подвергались потенциальным штрафам (отсутствие встряхивания дерева и т. д.), а все остальные (значительное большинство?) получали бы уменьшенный развертываемый размер, преимущества производительности (?)

Отступая назад @swaroop-sridhar @MichalStrehovsky , я вижу два широких варианта использования, которые могут иметь достаточно разные цели/желания, чтобы было трудно удовлетворить всех одним решением:

  • Инструментарий CLI в идеале требует быстрой работы каждый раз, небольшой распространяемый объем; может лучше подойдет для CoreRT?
  • микросервис, вероятно, может выдержать более длительный первый запуск (в идеале <1 с), более крупный распространяемый пакет в обмен на более богатые функциональные возможности, такие как JIT и функции динамического кода.

Я надеюсь, что этот мозговой дамп имеет какой-то смысл, я не пытаюсь быть придурком, а просто оставляю отзыв, потому что мне очень интересна эта тема. Спасибо за всю вашу тяжелую работу и запрос мнения сообщества! :)

О плагинах.
По сути, единственное, чего я хотел бы, это _не_ блокироваться при вызовах Assembly.LoadFrom или LoadLibrary .
Мне больше ничего не нужно, остальное я могу сделать сам.

@ayende Не могли бы вы объяснить немного подробнее, что вы подразумеваете под «быть заблокированным в LoadFrom и тому подобное»?

Например, некоторые из предложений для этого включали CoreRT, что означало, что мы (вероятно) не сможем просто загрузить управляемую dll.
Но пока я могу указать путь к управляемой dll и получить сборку или вызвать LoadLibrary в родной dll, я согласен с тем, что это механизм плагина.

Я говорю это, чтобы прояснить, что сценарии плагинов не должны _рассматриваться_, а скорее то, что не должно _блокироваться_.

Я потратил некоторое время, копаясь в коде, и на первый взгляд кажется, что это должно быть _возможно_ (говоря о Windows только для простоты):

  • Упакуйте весь CoreCLR в exec (скажем, как встроенный ресурс или что-то в этом роде).
  • Перечислите собственные dll, вызовите что-то вроде MemoryModule (https://github.com/fancycode/MemoryModule), чтобы загрузить их в память.
  • Запустите среду выполнения и загрузите сборку из памяти.

Я собираюсь предположить, что это _не_ так просто. Например, ICLRRuntimeHost2::ExecuteAssembly не предоставляет никакого способа предоставить ему буфер, только файл на диске.
Это делает его первым (из многих, я уверен, будет) демонстрационной пробкой, которая на самом деле заставит его работать.

Я почти уверен, что есть много кода, который может относиться к связанным вещам как к файлам, которые могут дать сбой, но это то, что я имею в виду, когда говорю, что мне нужен один файл exec и почему такой вид решение нужно делать в CoreCLR, а не извне (как в примере с zip).

вызовите что-то вроде MemoryModule

Двоичные файлы, загруженные с помощью MemoryModule, не поддаются диагностике (например, ни один из обычных отладчиков, профилировщиков и т. д. не будет работать с ними), а MemoryModule пропускает все встроенные меры безопасности ОС (например, антивирусы и т. д.). Это не то, что мы могли бы когда-либо поставлять в качестве поддерживаемого решения.

Я собираюсь предположить, что это не так просто, как это.

Правильно, потребуются новые API (как управляемые, так и неуправляемые) для поддержки выполнения из нерасширенного пакета одного файла. Существующие программы и библиотеки не будут «просто работать».

Может ли быть разумным попросить, чтобы интерфейс сканирования на наличие вредоносных программ был
реализован инженерами Windows на MemoryModule, как это недавно было для
все сборки .net, в том числе загруженные из памяти?

https://twitter.com/WDSecurity/status/1047380732031762432?s=19

РЕДАКТИРОВАТЬ: Хм, MemoryModule звучало как что-то встроенное в ОС для загрузки собственных модулей, но, видимо, это не так, вероятно, это достаточная причина, чтобы игнорировать мое предложение выше.

В среду, 5 декабря 2018 г., 01:46 Ян Котас, [email protected] написал:

вызовите что-то вроде MemoryModule

Двоичные файлы, загруженные с помощью MemoryModule, не поддаются диагностике (например, ни один из
обычные отладчики, профилировщики и т. д.) будут работать на них, а MemoryModule
пропускает все встроенные меры безопасности ОС (например, антивирусы и т. д.). Это не
что-то, что мы могли бы когда-либо поставлять в качестве поддерживаемого решения.

Я собираюсь предположить, что это не так просто, как это.

Верно, потребуются новые API (как управляемые, так и неуправляемые) для
поддержка выполнения из нерасширенного пакета одного файла. Существующий
программы и библиотеки не будут «просто работать».


Вы получаете это, потому что подписаны на эту тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/dotnet/coreclr/issues/20287#issuecomment-444314969 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AEBfudvVHxpbeKa-L_vTQjbnNZZsn6Meks5u1xdlgaJpZM4XK-X_
.

Спасибо всем за отзывы.
Вскоре мы опубликуем обновленный план поддержки однофайлового распространения.

@NinoFloris см. dotnet/coreclr#21370

Я понимаю, что опоздал на эту дискуссию, поэтому прошу прощения, если это не поможет.

Чтобы повторить то, что сказал @mikedn , наличие всех этих параллельных решений может сбивать с толку, и возникает вопрос, на чем в будущем будет сосредоточено внимание MS. Тот факт, что блестящая работа, проделанная над CoreRT, до сих пор считается экспериментальной без официальной дорожной карты и с аналогичной функциональностью, реализованной в CoreCLR (CPAOT, теперь публикация отдельных файлов), затрудняет принятие бизнес-решений на основе этой технологии. Я бы не хотел снова выбрать не ту лошадь (Silverlight...).

Почему бы не придерживаться блестящей среды выполнения в CoreRT и не сосредоточить работу на включении JIT (и расширении работы интерпретатора до тех пор, пока он не будет готов) в CoreRT для тех, кто хочет использовать все возможности фреймворка, но при этом иметь собственный код, созданный для них? Разве нельзя было бы, в случае необходимости JIT-способностей, сохранить метаданные и JIT внутри исполняемого файла, скомпилированного в собственном коде CoreRT?
Разве это не лучший из миров? Например. у вас будут самые маленькие исполняемые файлы, самое быстрое время запуска, ограничения кода AOT в CoreRT могут быть расширены за счет наличия JIT и сохранения метаданных и кода IL для тех, кто хочет сохранить полную функциональность платформы.
ИМО, основное внимание должно быть сосредоточено на «наилучшем возможном» решении, а не на краткосрочной функциональности, которая может отвлекать от долгосрочных целей.

Возможно, я ошибаюсь, но я думаю, что публикация одного файла в рамках CoreCLR еще больше отвлечет клиентов от CoreRT, что во многих случаях было бы для них потенциально лучшим решением. Например. если это получит название «теперь вы можете публиковать свой код .NET в виде одного файла», но он создает огромные файлы, будет страдать при запуске и т. д., тогда я вижу, как люди снова начинают жаловаться на эту «раздутую среду выполнения .NET». . В то время как .NET на самом деле уже имеет блестящее решение именно для этого в CoreRT, при этом ему не хватает официальной поддержки / официального обязательства по продукту, чтобы пройти весь путь.

Возможно, меня больше всего беспокоит то, что я хотел бы видеть меньше параллельных продуктов (снова цитируя @mikedn) и больше внимания уделять глубокой приверженности, расширению и поддержке тех, что есть (включая совместное использование дорожных карт).

меньше параллельных продуктов

У нас есть только один продукт: .NET Core. CoreRT не является отдельным продуктом и никогда не будет. Речь идет о добавлении опций к этому одному продукту. Вот несколько примеров вариантов, которые у нас есть сегодня: сборщик мусора рабочей станции и сборщик мусора сервера; публикация автономного приложения по сравнению с публикацией приложений, зависящих от фреймворка.

@jkotas Я понимаю и полностью согласен, что добавление опций обычно здорово. Если вы замените мое использование слова «продукты» на «варианты/решения», хотя я по-прежнему придерживаюсь своей озабоченности тем, что не полностью знаю, является ли приверженность нашего продукта CoreRT как варианту/решению внутри общего продукта .NET Core тем, что мы можно смело делать ставку на поддержку в течение многих лет. Представьте, что было бы, если бы API со временем вносили непредсказуемые критические изменения и внезапно устарели, а вы не знали бы, можете ли вы доверять API, чтобы оставаться там. Для организации, не являющейся MS, инструменты/опции, являющиеся частью продукта, воспринимаются одинаково. Мы зависим от нескольких возможностей CoreRT, которые мы не смогли бы сделать (по крайней мере, в настоящее время) с CoreCLR (одна из них — способность защищать наши исполняемые файлы с помощью PACE и удалять много-много метаданных, IL и т. д., простое статическое связывание, более легкое понимание базовой платформы, перспектива встраивания обфускации непосредственно в компилятор и т. д.). По сути, я чувствую, что ваша, Михальская и другие работы над CoreRT должны быть просто приоритетными, поскольку IMO — это одна из лучших вещей, которые произошли в экосистеме .NET с момента ее первой разработки. Каждый раз, когда говорят о новом инструменте/варианте, который затем можно было бы внутренне рассматривать как конкурирующий с CoreRT, а не вариант CoreRT, который нужно доработать и расширить, мне кажется неправильным распределением ресурсов. Извините, я не хотел затягивать дискуссию, просто хотел убедиться, что вы понимаете, насколько ценна работа CoreRT, и что некоторые из нас здесь считают, что это должно быть будущее платформы.
Я воздержусь от дальнейшего загрязнения этой дискуссии. Желаю командам всего наилучшего и с нетерпением жду того, что вы придумаете, я уверен, что это будет здорово.

@christianscheuer Ваши отзывы по этому вопросу и другим вопросам, связанным с CoreRT, были очень ценными. Вы нисколько не засоряете эту дискуссию.

говорят о новом инструменте/варианте, который внутренне можно рассматривать как конкурирующий с CoreRT.

Среди основной команды мы обсуждаем несколько разных, амбициозных или безумных вариантов. Я не считаю функцию «распаковать на диск» значительным конкурентом полнофункциональному AOT CoreRT. Каждый из них предназначен для определенного сегмента пользователей/приложений .NET.

Наша команда менеджеров по продукту, которая собирает данные из множества разных каналов (включая проблемы с github или личные беседы с клиентами), предположила, что решение, подобное предложенному здесь, принесет наибольшую отдачу. Мы все еще проверяем, что у нас есть все данные об этом праве и что оно будет иметь желаемый результат.

На данный момент я не могу обещать вам, когда технология CoreRT будет поставляться как часть поддерживаемого продукта .NET Core. Я знаю, что у него есть уникальные сильные стороны, и я уверен, что мы собираемся выпустить подобное поддерживаемое решение для сегмента важных пользователей .NET, которые в конечном итоге выиграют от него.

Распространение одним файлом имеет смысл, если:

  • Это не влияет на время запуска (иначе его смогут использовать только самые маленькие приложения)
  • Он действует как VFS (виртуальная файловая система). Позволяет вам получать доступ к сборкам и ресурсам, как если бы они были с диска, из папки приложения).
  • Не влияет на возможность исправления приложения. IE: Microsoft должна иметь возможность исправлять критические сборки, даже если они встроены, предоставляя переопределения где-то еще, на системном уровне.

Сборки как встроенные ресурсы, извлеченные и скопированные во временную папку, не являются необходимым решением от Microsoft. Он может быть легко реализован любым заказчиком, который в этом нуждается.

Необходимо «настоящее» решение для одного файла, и оно принесет большую пользу.

@jkotas, ваши комментарии звучат правдоподобно для меня. Мне было бы трудно убедить разработчиков .NET моей компании (LOB/бэк-офис/интеграции) перейти на CoreRT, потому что для них это было бы слишком большим скачком (особенно с учетом метки Experimental), но они могут увидеть ценность в относительно простое (в использовании) решение для Core, как обсуждается в этой теме. Спасибо

@ popcatalin81 На самом деле я бы категорически не согласился с вашим мнением.

Время запуска не имеет значения для многих приложений. Я с радостью пожертвую увеличением времени запуска любого долго работающего сервиса на 50–100 % ради снижения эксплуатационной сложности его развертывания.

Даже если мы добавим 30 секунд ко времени запуска службы, в долгосрочной перспективе это не имеет большого значения для служб.
Для приложений, ориентированных на пользователя, это, вероятно, будет убийцей, но до тех пор, пока не выйдет версия 3.0, почти все приложения CoreCLR являются либо консольными, либо сервисными.

Дело не в том, что в CoreCLR уже есть режим, в котором вы можете связать фреймворк с вашим приложением (автономное развертывание).
В нашем случае (RavenDB) мы _полагаемся_ на это по нескольким причинам. Во-первых, возможность выбирать собственный фреймворк независимо от того, что используют наши пользователи. Это _большое_ преимущество для нас, поскольку это означает, что нам не нужно использовать глобально установленный фреймворк и, таким образом, мы не привязаны к тому, что администратор решил использовать в качестве фреймворка (раньше мы учитывали, что будем работать на .NET 4.0 иногда, даже спустя годы после выхода 4.5, например, и это было мучительно).
Другим важным аспектом является то, что мы можем работать с _нашей собственной_ вилкой фреймворка. Это очень полезно, если мы сталкиваемся с вещами, которые мы должны изменить.

В рамках этого мы берем на себя ответственность за циклы исправлений и не хотим, чтобы кто-то еще вмешивался в это.

Я не против VFS, но не думаю, что это потребуется. И я совершенно согласен с тем, что мне нужно пройти через выделенный API/перепрыгнуть через некоторые обручи, чтобы добраться до сборок/собственных dll/ресурсов, которые связаны таким образом.

@briacht указывал мне на эту проблему в течение двух дней, поэтому я ДЕЙСТВИТЕЛЬНО опоздал в обсуждении.
Просто хочу добавить свои 2 цента!

Сначала мои ответы на вопросы @morganbr :

  1. Приложение для Windows, смешивающее WPF и WinForms.
  2. В данный момент нет
  3. Да, используя Assembly.Load в разных вариациях
  4. да
  5. Это зависит от того, является ли это штрафом, который есть при каждом запуске. Да, если это несколько миллисекунд, но 5 секунд: нет. Если это один раз, 5 секунд не проблема.
  6. 50 МБ уже довольно много по сравнению с <2 МБ ... но если это будет означать, что среда выполнения dotnet включена ... ОК. Может быть, я могу обеспечить загрузку с и без.
  7. Время выпуска не имеет прямого значения, но оно не должно расстраивать поставщика CI, используя много ресурсов ЦП в течение длительного периода времени.
  8. ДА!

Приложение, о котором я говорю Greenshot, текущая выпущенная версия в значительной степени по-прежнему нацелена на .NET Framework 2.0 (да, действительно), но работает без проблем в новейшей версии (хорошая обратная совместимость)! Загрузка, включая установщик, но без .NET Framework, занимает около 1,7 МБ. Каталог, из которого это запускается, содержит 1 .exe и 4 .dll, а также 11 надстроек в подкаталоге.

Я читал предыдущие комментарии, и многие из них звучат так, будто вы хотите что-то с функциональностью, для которой я бы использовал установщик. Это имеет определенный смысл, поскольку в настоящее время не существует решения, независимого от платформы.

Я обсуждал текущую тему с некоторыми людьми в Microsoft еще в августе, мое основное внимание было сосредоточено на том, чтобы связать все вместе, чтобы уменьшить размер и сложность приложения для развертывания, а также уменьшить загрузку сборки, которая занимает МНОГО времени во время запуска. моего приложения.

Со следующей версией Greenshot, ориентированной на .NET Framework 4.7.1 и dotnet core 3.0 параллельно, итоговая загрузка для dotnet core 3.0 в настоящее время содержит около 103 dll (!!!), один исполняемый файл и 15 надстроек. . Общий размер составляет около 37 МБ, а самый большой файл — MahApps.Metro.IconPacks.dll (12 МБ!!), который содержит большинство используемых нами значков, что, вероятно, составляет около 4% файла. То же самое со многими другими dll, я бы предположил, что в целом 50% использования кода - это много!

Если пользователь не хочет устанавливать приложение, просто загрузите .zip и найдите исполняемый файл среди примерно 118 файлов... не очень приятно! Размер примерно на 35 МБ (в 17 раз) больше, так в чем польза для пользователя?

За несколько месяцев до появления dotnet core 3.0 я использовал Fody.Costura, чтобы делать то, что здесь описано. Упаковка при сборке и распаковка при запуске! Он даже сделал один исполняемый файл без извлечения файлов, взломав но. Но это также вызвало довольно много проблем, поэтому это не мое предпочтительное решение.

Я надеюсь на более-менее стандартное решение, о котором могу сказать: оно просто работает ™
Может быть, имеет смысл определить стандартную структуру папок, чтобы мы могли поместить исполняемый файл, readme, файлы лицензии и т. д. в корень и иметь разные «известные» каталоги для разных файлов (ядро dotnet, зависимости и т. д.). Это может упростить работу с инструментами и предложить функциональные возможности, в которых каждый может решить, что использовать, а что нет. Иногда даже простой запуск zip в каталоге решает некоторые проблемы.

Наличие решения, похожего на Fody.Costury, определенно когда-нибудь поможет мне создать образ для упрощения развертывания Greenshot, но это не уменьшит размер и время загрузки напрямую. Так что я надеюсь, что здесь тоже будет время, проведенное здесь!

@ayende Позвольте мне тоже не согласиться с вами :)

Хотя это настоящие сервисы, веб-приложения и в целом серверные долгоиграющие приложения не подвержены влиянию единовременных затрат на запуск, в то же время эти приложения не являются теми приложениями, которые получают наибольшую выгоду от модели распространения с одним файлом. (Рэйвен - исключение, а не норма ;))

На мой взгляд, однофайловое распространение в первую очередь нацелено на приложения и утилиты, предназначенные для пользователей. Пользователи, которые будут скачивать, копировать, запускать такие приложения. А в ближайшем будущем, когда .Net Core 3.0 предложит поддержку UI-библиотек, эта модель распространения станет довольно распространенной. Однако я должен подчеркнуть, что эта модель не подойдет ни для каких приложений. Основные приложения по-прежнему будут использовать установщик.

Теперь вопрос: эта модель встроенных сборок, скопированных во временные папки, будет ли она хорошо работать , если станет очень популярной?

На мой взгляд, это некоторые потенциальные проблемы для текущей модели:

  • Десятки приложений создают тысячи временных файлов с повторяющимися сборками. Здесь есть возможность создать беспорядок. (Незаметно для пользователей, но все равно беспорядок)
  • Без сжатия, без компоновщика. Это может создавать неудобства для небольших служебных приложений по сравнению с FDD или архивированием событий.
  • На самом деле это может затруднить развертывание сервера, а не упростить его, по причине: конфигурация после развертывания с заменой токенов. (Где вы идете, чтобы найти временную папку для перезаписи файлов конфигурации? Предоставляете ли вы сервису доступ на запись в свою собственную папку для создания там файла конфигурации? Это безопасность нет-нет)

Я не хочу сказать, что эта модель неоптимальна для всех видов приложений. Я успешно реализовал его и сам использовал в прошлом для полной версии .Net Framework, и он хорошо подходит для определенных приложений.

Я просто думаю, что оптимальной реализацией является версия, в которой компоновщик объединяет все сборки в один файл.

@popcatalin81 Мир с одной точкой зрения — плохой. И я не настолько самонадеян, чтобы думать, что моя модель развертывания единственная.

Дело в том, что я имею в виду, это сценарий загрузки и двойного щелчка.
Прямо сейчас нам нужно разархивировать и щелкнуть сценарий оболочки для запуска, потому что войти в каталог с сотнями файлов и найти нужный — это рутинная работа.

О конфигах во временных файлах. Я был бы очень против этого. Файлы конфигурации — это другие видимые пользователю вещи, которые _должны_ находиться рядом с фактически используемым файлом, а не где-то спрятаны.
Мы уже видели, насколько плохо это было с файлами IsolatedStorage , когда они были нужны пользователям.

В предыдущих версиях RavenDB мы объединили много вещей, чтобы упростить расположение каталогов и уменьшить количество видимых файлов, и это серьезно повлияло на удобство использования нашего программного обеспечения.

Будет ли эта функция использовать ILMerge? Если нет, то почему? Я хотел бы обучить себя, если есть ловушка.

Мне не нравится предложенный подход «упаковать и извлечь», особенно часть, где если бы извлекались файлы на диск. Это просто, но слишком много проблем. Все должно работать "из памяти" без распаковки на диск.

Я думаю, что это должно быть что-то вроде нативного компилятора corert или Costura.Fody .

При желании он также должен попытаться уменьшить размер двоичного файла (удалить неиспользуемые ссылки, мертвый IL).

ре

За несколько месяцев до появления dotnet core 3.0 я использовал Fody.Costura, чтобы делать то, что здесь описано. Упаковка при сборке и распаковка при запуске!

обратите внимание, что costura (по умолчанию) не «распаковывает на диск». он извлекает (в память) встроенные сборки из ресурсов и загружает их через байты

Спасибо за контекст @SimonCropp , мы изучаем как варианты распаковки на диск, так и загрузки из потока. Покрытие загрузки из потока для чистого IL может быть возможно в нашей первой итерации.

@jeffschwMSFT, кстати, набор функций плавного слияния сборок (и необязательное встряхивание дерева) - это то, что я хотел бы видеть как первоклассный гражданин. costura — один из моих самых популярных проектов, но на его поддержку уходит много времени. поэтому, если / когда MS выпустит альтернативу (даже в виде бета-версии), дайте мне знать, и я потрачу некоторое время на ее рассмотрение и добавлю немного «есть альтернатива MS» в ридми Costura и описание nuget

хотя маловероятно, если вам нужно, чтобы я выпустил какой-либо код в Costura под лицензией diff, просто дайте мне знать.

Спасибо @SimonCropp , поскольку мы начинаем интегрировать mono/illinker в цепочку инструментов .NET Core, мы примем ваше предложение о рецензировании.

обратите внимание, что costura (по умолчанию) не «распаковывает на диск». он извлекает (в память) встроенные сборки из ресурсов и загружает их через байты

Более того, я полагаю, что он загружается по запросу с использованием события AppDomain.AssemblyResolve , поэтому запуск не должен сильно влиять на запуск, поскольку он будет загружать сборки (в память) только тогда, когда это необходимо.

Поздно для разговора здесь. Извиняюсь, если это уже было освещено.

Можем ли мы предположить, что артефакт здесь будет детерминированным? Следовательно, одна и та же сборка всегда будет создавать один и тот же двоичный файл? Байт за байтом. Также была бы полезна возможность распространять двоичный файл с канонической контрольной суммой.

@morganbr Здесь нужно много читать. Можно ли протоколировать решения, принятые до сих пор?

@edblackburn мы собираем обновленный дизайн на основе отзывов. @swaroop-sridhar сейчас занимается дизайном.

Будет ли эта функция использовать ILMerge? Если нет, то почему? Я хотел бы обучить себя, если есть ловушка.

@simplejackcoder ILMerge объединяет IL из многих сборок в одну, но при этом теряет исходную идентичность объединенных сборок. Таким образом, такие вещи, как использование отражения на основе исходных имен сборок, не сработают.

Цель этих усилий — не объединить сборки, а упаковать их вместе, сохраняя при этом идентичность сборки. Кроме того, нам нужно упаковать не только сборки, но и собственные двоичные файлы, файлы конфигурации, возможно, среду выполнения и любые другие зависимости, требуемые приложением.

Слияние IL — полезная функция для приложений, которые могут адаптироваться к ней — это просто функция, отличная от этой проблемы.

Обзор дизайна размещен по адресу https://github.com/dotnet/designs/pull/52 .
Продолжим дискуссию о PR в дальнейшем.

У меня есть несколько вопросов к людям, которые хотели бы использовать один файл. Ваши ответы помогут нам сузить наши возможности:

  1. С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)
  2. Включает ли ваше приложение (не .NET) C++/собственный код?
  3. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?
  4. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?
  5. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?
  6. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?
  7. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?
  8. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?
  1. Наш вариант использования dotnet/coreclr №1 — это консольные приложения, которые являются утилитами. Мы хотели бы сделать публикацию для Windows или Linux и указать --single-file , чтобы получить один исполняемый файл. Для Windows мы ожидаем, что это закончится на .exe , для Linux это будет исполняемый двоичный файл.
  2. Обычно нет, но может быть через пакет NuGet без нашего ведома.
  3. Изначально нет, но это было бы отличной функцией в будущем
  4. да
  5. да
  6. Что бы ни работало
  7. Да, если он оптимизировал результирующий размер исполняемого файла. В идеале может быть флаг для установки уровня оптимизации с использованием --optimizing-level=5
  8. Да, до определенного момента

Спасибо @BlitzkriegSoftware.
Я думаю, что предложенный здесь дизайн охватывает ваш вариант использования. Пожалуйста, взгляните на дизайн — мы будем рады вашим отзывам.

У меня есть несколько вопросов к людям, которые хотели бы использовать один файл. Ваши ответы помогут нам сузить наши возможности:

  1. С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)
  2. Включает ли ваше приложение (не .NET) C++/собственный код?
  3. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?
  4. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?
  5. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?
  6. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?
  7. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?
  8. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?
  1. Приложение WPF .Core 3.0
  2. Может быть, в пакете nuget
  3. Нет
  4. да
  5. Да для 200-500 мс максимум
  6. Не важно, если он не в 2 или 3 раза больше исходного размера папки для публикации.
  7. Это для производства, так что не очень важно
  8. Да, но есть возможность не делать этого, это может быть полезно, если работа касается сторонней библиотеки.

Отзывы, которые вы получили, в основном касались разработки до 2019 года, то есть веб-сервисов, консольных приложений и других сервисов, запущенных в фоновом режиме. Но теперь с .net core 3.0 нам нужны решения для приложений WPF и пользовательского интерфейса. .Net Framework 4.8 не будет поддерживать .Net Standard 2.1, и нам нужно решение для замены ILMerge, которое мы использовали до сих пор для приложений WPF, поскольку нам нужно обновить наши приложения с .net framework (мертвый фреймворк) до .net core.

Самораспаковывающийся пакет явно не является хорошим решением, как объяснялось в других комментариях ранее для такого рода программ.

  1. В основном приложения CLI. Небольшие службы Windows и случайное приложение WPF тоже интересны. Для веб-материалов распространение одного файла кажется в основном неуместным. По этой причине остальная часть в основном ориентирована на Windows; наш интерес к Linux .NET Core связан с Интернетом.
  2. Иногда. Когда это происходит, это почти всегда для библиотек сжатия. Если бы местные вещи не были упакованы, это не был бы конец света. Хорошее решение для чисто управляемых вещей, требующих развертывания собственной зависимости в виде отдельной dll, все равно будет иметь ценность.
  3. Нет, не в тех случаях, когда нас интересует один файл.
  4. да.
  5. 200 мс - это примерно предел, прежде чем что-то начнет раздражать для запуска CLI. > 1 секунды, и мы почти наверняка остановились бы на .NET Framework (ILMerge + ngen) или посмотрели бы на другие языки, которые компилируются в собственный двоичный файл с любой необходимой средой выполнения, статически связанной. Во многих случаях мы говорим о вещах, которые был реализован на C#, потому что объединенное приложение C# с ngen-ed фактически запускается достаточно быстро. Некоторые из этих вещей, с точки зрения сложности, разумно реализовать на языке сценариев, но они, как правило, требуют значительных начальных затрат, особенно если вам нужно подключить кучу модулей.
  6. Зависит от. Более 10 МБ для приветствия, мир, будет сложно продать. Огромные исполняемые файлы, как правило, имеют нетривиальные затраты на запуск. Даже если ОС теоретически способна начать выполнение без чтения всего, по крайней мере, в Windows, почти всегда есть что- то , что сначала хочет получить хэш для какой-то цели безопасности. Говоря об этом, эта распаковка кучи двоичных файлов во временную вещь сведет с ума AV (включая Защитника) с точки зрения использования ресурсов, лихорадочно сканирующего, если ничего другого.
  7. Конечно. Я был бы рад добавить минуту или больше к сборке релиза, если бы это означало получение чего-то разумного размера и быстрого запуска выполнения.
  8. Определенно.

Прочитав предложение, я понимаю, что оно не касается ни одного сценария, который у нас есть и который мы бы не использовали. Может быть кто-то, для кого это решает проблему, но это не мы.

Кажется, что есть много важных вещей для таких сценариев, над которыми работает наш, которые просто не объединились в цепочку инструментов, которая на самом деле пригодна для использования / вероятно, продолжит работать. Может это просто неосведомленность с моей стороны, но я стараюсь обращать внимание и мне непонятно. Между ILLink, Microsoft.Packaging.Tools.Trimming, CoreRT, .NET Native и тем, что происходит в этой проблеме, кажется, что должен быть какой-то способ получить единый древовидный, быстрый запуск (возможно, AoT?), двоичный файл разумного размера. из .NET Core (а не для UWP).

  1. Распространение одного файла было бы очень полезно для приложений https://github.com/AvaloniaUI/Avalonia (Windows, Linux, MacOS) и WPF (Windows). Например, наличие одного исполняемого файла упрощает автообновление, и в целом более удобно иметь один файл по сравнению с сотней dll.
  2. Да (в том смысле, что он ссылается на предварительно созданные нативные библиотеки, такие как sqlite и skia)
  3. Нет
  4. да
  5. 200 мс, наверное, нормально. Иметь время запуска 5 с для приложения с графическим интерфейсом — это нехорошо.
  6. Не имеет значения
  7. Не имеет значения. Мы могли создать один файл только для производственных сценариев.
  8. да

Пожалуйста, не используйте метод упаковки и извлечения. Мы уже могли добиться этого, используя архивные инструменты.

Пожалуйста, не используйте метод упаковки и извлечения. Мы уже могли добиться этого, используя архивные инструменты.

Не могу не согласиться. Уже есть несколько инструментов, которые делают это.

Спасибо за отзывы @Safirion , @mattpwhite , @x2bool , @thegreatco.
Из них я вижу ряд сценариев использования (консольные приложения, WPF, приложения с графическим интерфейсом и т. д.), но общие требования кажутся схожими:

  • Сосредоточьтесь на времени выполнения/запуска, а не на времени сборки.
  • Возможность перестраивать приложения для дальнейших выпусков/исправлений
  • Возможность запуска непосредственно из пакета (особенно для полностью управляемых компонентов).

Я считаю, что это те требования, которые мы пытались отразить в проектной документации .

Пожалуйста, не используйте метод упаковки и извлечения

Да, как объясняется в этом промежуточном документе , цель состоит в том, чтобы постепенно свести к минимуму зависимость от извлечения файлов.

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

@mattpwhite , хотел уточнить, считаете ли вы, что это решение не работает для вас, основываясь на:

  • Подход, основанный на самоизвлечении, предложенный ранее в этом рабочем элементе, или
  • Дизайн, отмеченный в этом документе
    Я считаю, что более поздний документ пытается рассмотреть сценарий, который вы подробно описали. Спасибо.

Кажется, что есть много важных вещей для таких сценариев, над которыми работает наш, которые просто не объединились в цепочку инструментов, которая на самом деле пригодна для использования / вероятно, продолжит работать.

@mattpwhite , продолжается работа по интеграции ILLink (сотрясение дерева), crossgen (генерация готового к запуску нативного кода) и аспектов объединения отдельных файлов в интерфейс командной строки msbuild/dotnet упрощенным способом для .net core 3. Однажды это сделано, с помощью этих инструментов можно легко выполнить (например, установить определенные свойства msbuild).

Все эти инструменты имеют компромиссы. Например, crossgen заранее генерирует нативный код, помогая запуску, но имеет тенденцию к увеличению размера двоичных файлов. Используя вариант с одним файлом, приложения можно публиковать в один файл, но это может замедлить запуск, потому что нативные бинарники проливаются на диск и т. д.

@swaroop-sridhar, спасибо, что нашли время ответить.

хотел уточнить, считаете ли вы, что это решение не работает для вас на основе

Казалось, что извлечение все еще актуально для чего-то автономного, а статус кроссгена (или чего-то еще, что нужно сократить в JIT-времени при запуске) мне не был ясен. Чтение промежуточного документа, на который ссылается текущий дизайн, выглядело так, как будто материал, который сделает это более интересным для нас, был дальше. Учитывая это, я думал, что мы еще какое-то время будем использовать .NET Framework для этих ниш. Я, возможно, неправильно понял.

Все эти инструменты имеют компромиссы. Например, crossgen заранее генерирует нативный код, помогая запуску, но имеет тенденцию к увеличению размера двоичных файлов.

Да, я понял, что некоторые из них — палки о двух концах. Благодаря тому, как традиционно работал JIT, ngen всегда был выигрышным для приложений CLI/GUI. Возможно, что некоторая комбинация многоуровневой компиляции и тот факт, что загрузка самой среды выполнения не обязательно амортизируется множеством других процессов .NET Framework, работающих на том же компьютере, делает это менее очевидным для Core.

@swaroop-sridhar меня больше всего беспокоит принятое в настоящее время предложение, связанное с этим шагом.

Остальные 216 файлов будут извлечены на диск при запуске.

Помимо того факта, что для запуска «Hello World» требуется 216 файлов, извлечение их на диск в каком-либо месте затрудняет удаление простого приложения командной строки. Когда люди удаляют инструмент, который не был установлен через установщик, они не ожидают, что им придется искать другие файлы, чтобы полностью удалить его.

ИМХО, мы должны ориентироваться на опыт публикации, аналогичный тому, что используется в golang. Хотя для полного соответствия опыту golang потребуется наличие crossgen (и можно утверждать, что совпадение 1:1 — это нехорошо, поскольку мы проигрываем JIT и многоуровневую компиляцию), хорошая часть может быть достигнута без него. На протяжении многих лет я использовал множество инструментов для достижения аналогичного результата, и наиболее эффективными были встроенные ресурсы с привязкой к загрузчику сборки (ILMerge был привередливым, а Costura.Fody еще не существовало). То, что описано в предложении, даже не полностью воспроизводит эту функциональность. У .NET Core действительно сильное будущее, но его использование для разработки инструментов командной строки ограничено, пока нам нужно таскать около 100 зависимостей или выплевывать их куда-то на диск с каким-то ручным кодом начальной загрузки.

Мой вариант использования dotnet/coreclr#1 — это утилиты командной строки, один файл, я бы предпочел не извлекать. Но я хотел бы отметить, что предоставление выбора как часть переключателей команды для «все в одном» против «все в одном самораспаковывающемся». В случае самораспаковывающегося архива он должен содержать undo , очищающий распакованные файлы. В первом случае удаление утилиты означает удаление одного файла, что делает его пригодным для размещения в папке общих утилит, где, как и во втором случае, установка должна иметь свою собственную папку, чтобы упростить очистку и избежать сценарии, в которых при удалении удаляются общие файлы. Просто некоторые мысли. Как я уже сказал, утилита с одним файлом (установка не требуется) является моим основным вариантом использования, поскольку я часто создаю утилиты для проектов (как инструментальный мастер). Но я вижу вариант использования для обоих сценариев. Но они разные .

У меня есть несколько вопросов к людям, которые хотели бы использовать один файл. Ваши ответы помогут нам сузить наши возможности:

  1. С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)
  2. Включает ли ваше приложение (не .NET) C++/собственный код?
  3. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?
  4. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?
  5. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?
  6. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?
  7. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?
  8. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?
  1. CLI (Windows, Linux, MacOS), WPF и WinForms.
  2. Иногда.
  3. Да, много раз, и я думаю, что сценарий, когда плагин может повторно использовать общую библиотеку из основного приложения, должен быть рассмотрен!
  4. да.
  5. 200-500мс нормально!
  6. Для простого приложения CLI без множества зависимостей достаточно 10 МБ (в сжатом виде)!
  7. Да однозначно! Время сборки (особенно для релизных сборок!) не имеет значения! Размер сжатия и/или переключение на публикацию одного файла не обязательны!
  8. Да например CoreRT!

ИМХО, мы должны ориентироваться на опыт публикации, аналогичный тому, что используется в golang.

@thegreatco : Да, полная компиляция в собственный код — хороший вариант для создания однофайловых приложений. Такие языки, как GO, построены с опережающей компиляцией (AOT) в качестве основной модели, что связано с определенными ограничениями динамических языковых функций, достигаемых с помощью JIT-компиляции.

CoreRT — это решение .Net Core для скомпилированных приложений AOT. Однако, пока CoreRT не будет доступен, мы пытаемся реализовать однофайловые приложения с помощью других средств в этом выпуске.

Помимо того факта, что для запуска "Hello World" требуется 216 файлов,

Есть несколько способов уменьшить количество файлов, необходимых для HelloWorld.

  • Создайте зависимое от фреймворка приложение, для которого нужно всего 3-4 файла.
  • Если нам нужно создавать автономные приложения, используйте ILLinker , чтобы уменьшить количество зависимостей файлов.

извлечение их на диск в каком-либо месте затрудняет удаление простого приложения командной строки.

  • По мере того как разработка функции работы с одним файлом переходит на следующие этапы , количество файлов, перенесенных на диск, будет уменьшаться и в идеале будет равно нулю для большинства приложений. Но на начальных этапах придется пролить несколько файлов (тех, что содержат нативный код).
  • Расположение файлов, перенесенных на диск, всегда детерминировано и настраивается. Таким образом, пролитые файлы можно очистить с помощью простого скрипта. Но я согласен, что это не идеально.

Спасибо за разъяснение @mattpwhite.

Да, до более поздних этапов разработки функции автономные приложения будут видеть файлы, извлеченные на диск. Возможно, вы сможете использовать некоторые из методов, которые я написал в комментарии выше, чтобы улучшить ситуацию для ваших приложений.

Спасибо за ваш ответ @BlitzkriegSoftware.

Но я хотел бы указать, что предоставление выбора как часть переключателей команд для «все в одном» против «все в одном» самораспаковывающемся

Требуется ли извлечение приложения, опубликованного в виде одного файла, зависит от содержимого приложения (например, содержит ли оно собственные файлы). Дизайн упаковщика предоставляет некоторые конфигурации , чтобы решить, следует ли извлекать все файлы. Мы можем добавить свойство, чтобы сказать, что приложение не должно использовать извлечение файлов во время выполнения.

<propertygroup>
    <SingleFileExtract> Never | Always | AsNeeded </SingleFileExtract>
</propertygroup>

Понимание здесь такое: при компиляции SingleFileExtract=Never, если приложение содержит файлы, которые могут быть обработаны только посредством извлечения (собственные двоичные файлы), то публикация в один файл завершится ошибкой.

В случае самораспаковывающегося архива он должен включать отмену, которая очищает распакованные файлы.

Звучит разумно. Точное место извлечения (если есть) является детерминированным и настраиваемым. Итак, у нас может быть сценарий для удаления приложения и всех его извлеченных зависимостей.

Спасибо за ваш ответ @DoCode. Ваш сценарий интересен тем, что в нем используются плагины.
Если сами плагины имеют некоторые зависимости (которые не используются совместно с основным приложением), нужно ли/предпочтительно ли опубликовать плагин в виде одного файла (со встроенными зависимостями)? Спасибо.

Да @swaroop-sridhar, это цель. Мы думаем, что в этом случае плагин должен встраивать свои зависимости. Только общие зависимости должны были оставаться снаружи от основного приложения с одним файлом.

Сегодня @madskristensen поделился хорошим разъяснением относительно Visual Studio и популярного пакета NuGet Newtonsoft.Json.

Мы же ситуации в подобной ситуации иногда!

Спасибо @DoCode. Мы планируем реализовать функцию однофайловых плагинов, как только однофайловые приложения будут реализованы и станут стабильными. В дизайн-документе рассказывается о плагинах здесь .

@swaroop-sridhar спасибо за постоянное участие в этой функции, это очень ценно. Наличие команды отмены будет особенно полезно для исходных этапов.

  1. С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)
    -- Утилиты командной строки (консольные приложения)
  2. Включает ли ваше приложение (не .NET) C++/собственный код?
    -- Нет
  3. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?
    -- Как правило, не
  4. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?
    -- Да
  5. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?
    -- < 1 секунды было бы моим предпочтением
  6. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?
    -- Размер не важен
  7. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?
    -- 30 секунд
  8. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?
    -- Конечно, если это можно заскриптовать или настроить

1 - С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)

  • Игры
  • Инструменты командной строки

2. Включает ли ваше приложение (не .NET) C++/собственный код?

да

3. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?

Да, но с уже известными символами я не полагаюсь на отражение, так как оно медленное

4. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?

да

5. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?

Нет, это уже немного медленно

6. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?

Зависит от проекта, но для простого инструмента командной строки я не ожидаю, что он будет больше, чем однозначное число mbs

7. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?

Пока это не влияет на время разработки/итерации, меня устраивает более длительное время сборки релиза.
Но помните, приложения .net core уже строятся дольше, чем традиционные приложения .net framework.

Эта тенденция к более медленному программному обеспечению с каждым годом НЕ приемлема, у нас есть лучшее оборудование, и нет причин для такой медлительности.

8. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?

ДА!

Я действительно надеюсь, что компиляция AOT с CoreRT когда-нибудь заработает, чтобы мы могли компилировать приложения, такие как golang и rust, и другие языки, скомпилированные с помощью AOT. Аналогично тому, как это делает Unity3D с IL2CPP.

@morganbr Вот некоторые комментарии от меня и людей, с которыми я работаю. Я использую много языков, но в основном C#, Go и Python.

С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)

Программы ASP.NET Core и Console, в основном для Linux, потенциально некоторые рабочие нагрузки Windows, в зависимости от того, соответствует ли ML.NET нашим потребностям.

Включает ли ваше приложение (не .NET) C++/собственный код?

На данный момент маловероятно.

Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?

Это зависит. В настоящее время мы можем получить все наши зависимости в виде пакетов, но я могу представить себе ситуацию, когда мы платим за коммерческую библиотеку, что может означать использование внешних DLL.

Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?

Абсолютно. Это является для нас главным приоритетом.

Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?

Я бы сказал, что все, что меньше 10 секунд, меня более чем устраивает. Время запуска обычно не имеет значения, если оно идемпотентно и предсказуемо — т. е. библиотеки загружаются в том же порядке, переменные инициализируются в том же порядке и т. д.

Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?

Чем меньше, тем лучше, в основном для целей распространения. Распространением могут быть загруженные пользователем двоичные файлы, образы контейнеров с двоичными файлами и т. д.

Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска?

Конечно, пока он быстрее, чем C/C++ и Java, он должен быть приемлемым.

Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?

Вероятно, 30-90 секунд были бы идеальными, но все, что меньше 3 минут, вероятно, приемлемо. Более 3 минут для малых/средних проектов (от 1 до 500 тысяч строк) — это слишком много. 5 минут для очень больших проектов (1M LOC) могут быть приемлемыми.

Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?

Это зависит. Если дополнительная работа заключается в добавлении стандартного кода, который можно использовать в качестве шаблона, это, вероятно, нормально. Если это неясная, не прямая работа, потенциально нет.

Спасибо за ответ @mxplusb , @dark2201 , @RUSshy , @BlitzkriegSoftware

Я считаю, что текущий дизайн наилучшим образом соответствует вашим сценариям при отсутствии чистой компиляции AOT. Если у вас есть какие-либо сомнения относительно дизайна, пожалуйста, не стесняйтесь поднимать их.

Что касается меньшего времени запуска и времени компиляции:
Приложения, зависящие от платформы, будут иметь значительно меньшее время запуска (по крайней мере, на начальных этапах запуска функции). Время компиляции также меньше (потому что нужно встроить меньше файлов).
Я сообщу вам время запуска, производительность компиляции и размер файла, как только будет завершена первая итерация разработки функции.

@swaroop-sridhar Каковы сроки для этого?

@ayende Первая итерация находится в активной разработке, я думаю, мы получим результаты через несколько недель.

@swaroop-sridhar

Я считаю, что текущий дизайн наилучшим образом соответствует вашим сценариям при отсутствии чистой компиляции AOT. Если у вас есть какие-либо сомнения относительно дизайна, пожалуйста, не стесняйтесь поднимать их.

Выполнить: HelloWorld.exe

Связанное приложение и файлы конфигурации обрабатываются непосредственно из пакета.
Остальные 216 файлов будут извлечены на диск при запуске.

Что делать, если мне нужно запустить из fs только для чтения, это обычно для IoT, или если exe выполняется внутри контейнера ro? почему нет возможности запустить его прямо из exe?

@etherealjoy Пример, показанный в этом разделе , является ожидаемым результатом для автономного HelloWorld на этапе 2 разработки этой функции (как упоминалось в этом разделе ). На данном этапе единственными приложениями, которые могут запускаться непосредственно из EXE, являются полностью управляемые приложения, зависящие от платформы.

Если мы находимся на этапе 4 или этапе 5 , вышеприведенное автономное приложение может выполняться непосредственно из пакета.

С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)

В основном все вышеперечисленное. Консольные утилиты, WPF, asp.net, игры

Включает ли ваше приложение (не .NET) C++/собственный код?

да. Sqlite — хороший пример.

Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?

Вероятно, не.

Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?

да.

Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?

net.core уже слишком медленный. Но увеличение на пару секунд допустимо. 5 секунд - определенно нет.

Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?

Не имеет значения в наши дни

Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?

До 5 минут чувствует себя приемлемым. 15-20-минутные сборки релизов для UWP сводят всех с ума.

Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?

Конечно.

Спасибо @mjr27

Реализация этапа 1 завершена и доступна с версии 3.0.100-preview5-011568 .

Приложения можно публиковать в один файл, задав для свойства PublishSingleFile значение true , как описано здесь .

В этой версии все встроенные файлы извлекаются на диск при первом запуске и повторно используются при последующих запусках, как описано здесь .

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

Размер файла и запуск
В следующей таблице показана производительность для нескольких приложений, созданных как один файл.

  • Консоль: приложение «Hello World». Сообщаемое время — это время запуска приложения, измеренное с помощью тактов часов.
  • Приложение WPF: приложение msix-catalog . Сообщаемое время — это время запуска до начального экрана, измеренное с помощью секундомера.
  • Fw: сборки, зависящие от фреймворка
  • Self: Автономные сборки.
    Все запуски проводились при отключенных антивирусных проверках, чтобы свести к минимуму влияние внешних факторов.

Измерение | ПО консоли | Консоль Самостоятельная | ПО WPF | WPF самостоятельно
-- | -- | -- | -- | --
Размер файла (МБ) | 0,32 | 66,5 | 20,69 | 118,9
Нормальный запуск (сек) | 0,123 | 0,127 | 3.32 | 3,24
Первый запуск одного исполняемого файла (сек) | 0,127 | 0,565 | 3,67 | 4.14
Последующие запуски одного исполняемого файла (сек) | 0,124 | 0,128 | 3.30 | 3,29

Я буду обновлять цифры по мере перехода к последующим этапам разработки.

Отличные новости. Спасибо

Будут ли завершены все этапы, упомянутые в документации по подготовке, для RTM 3.0? Или нам придется ждать пост 3.0, чтобы они были реализованы?

Как упоминалось здесь , ожидается, что .net core 3.0 будет реализовывать этап 2 , так что зависимые от платформы чистые приложения msil могут запускаться непосредственно из пакета. Остальные этапы будут рассмотрены для дальнейших релизов.

Как упоминалось здесь , ожидается, что .net core 3.0 будет реализовывать этап 2 , так что зависимые от платформы чистые приложения msil могут запускаться непосредственно из пакета. Остальные этапы будут рассмотрены для дальнейших релизов.

:( надеялся, что он сможет добраться до RTM.

@cup Я думал, ты сможешь сделать это с помощью dotnet publish -o out /p:PublishSingleFile=true /p:RuntimeIdentifier=win-x64 . Я только что проверил, создав ванильное консольное приложение и выполнив эту команду. Это сработало успешно.

Вы можете пойти еще дальше, объединив файл .pdb с dotnet publish -o out /p:PublishSingleFile=true /p:RuntimeIdentifier=win-x64 /p:IncludeSymbolsInSingleFile=true

Спасибо @seesharprun за подробные заметки. Да @cup , рекомендуемый метод публикации одного файла из командной строки — установить свойство PublishSingleFile из командной строки.

@etherealjoy репозитории среды выполнения coreclr будут в основном заблокированы из-за работы функций примерно через месяц. Не думаю, что на все этапы хватит времени. Я надеюсь, что последующие этапы появятся в следующем выпуске.

У меня это работает сегодня, но похоже, что изменение базового каталога извлечения не работает. Согласно этому разделу . Я должен иметь возможность добавить переключатель приложения в runtimeconfig с именем ExtractBaseDir, чтобы изменить местоположение, в которое извлекается приложение.

У меня есть runtimeconfig.template.json, который выглядит так

{
    "configProperties" : {
        "ExtractBaseDir": "C:\\"
    },
    "ExtractBaseDir": "C:\\"   
}

Созданный app.runtimeconfig.json выглядит следующим образом:

{
  "runtimeOptions": {
    "configProperties": {
      "ExtractBaseDir": "C:\\"
    },
    "ExtractBaseDir": "C:\\"
  }
}

При запуске созданного исполняемого файла он по-прежнему загружается в папку tmp.

Я предполагаю, что эта функция просто не готова в Preview5, но я хотел убедиться, поскольку неясно, куда должен идти «ExtractBaseDir» в runtimeconfig.json, и нет примеров.

@igloo15 Спасибо, что подняли эту тему.

В текущей предварительной версии включена только переменная среды DOTNET_BUNDLE_EXTRACT_BASE_DIR . Это связано с тем, что на текущем этапе реализации все файлы, включая runtimeconfig.json , перед обработкой извлекаются на диск.

Я работаю над добавлением поддержки ExtractBaseDir в следующей предварительной версии.

Есть ли какое-то руководство о том, как заставить это работать с проектами ASP.NET Core? Будет ли рекомендуемый подход использовать отражение, чтобы найти, откуда загружаются мои системные типы, и установить мои IHostingEnvironment ContentRootPath и WebRootPath относительно этого каталога?

@keithwill Вы можете использовать AppContext.BaseDirectory , чтобы получить место, где app.dll и все другие файлы извлекаются на диск. Итак, вы можете использовать это как ContentRootPath .

@ igloo15 : Мне любопытно, не могли бы вы поделиться своим сценарием с использованием этой опции.

  • Вы пытаетесь использовать его для сценария отладки или производственного развертывания?
  • Будет ли в этом случае достаточно переменной окружения или вам потребуется параметр runtimeconfig.json ?

Мне также интересно услышать от других разработчиков, есть ли конкретные варианты использования этого параметра.

@swaroop-sridhar

У меня довольно странная ситуация. Мое программное обеспечение хранится в сетевом ресурсе, а затем сетевой ресурс связывается со случайной виртуальной машиной Windows и запускается непосредственно из сетевого ресурса. Windows vm, запущенная для запуска программного обеспечения из сетевой папки, не может быть изменена или изменена. Журналы, файлы конфигурации и т. д. должны быть созданы на сетевом ресурсе.

Как ни странно, эта настройка позволяет всей системе размещать несколько частей программного обеспечения в папке, а затем клонировать структуру этой папки для разных конфигураций/версий. Затем, когда необходимо запустить определенную версию, управляющее программное обеспечение запускает виртуальную машину и сопоставляет диски на виртуальной машине с сетевым ресурсом определенной версии и запускает программное обеспечение.

1.) Это сценарий производственного развертывания.
2.) Переменные среды будут сложными, поскольку компьютер, на котором работает программное обеспечение, постоянно меняется и уничтожается/переделывается.

@cup Я действительно не согласен, что эта тема посвящена реализации документации по дизайну , и в документации по дизайну конкретно говорится, что ExtractBaseDir должен работать для этой функции.

Если эта проблема не связана с реализацией этого проектного документа, то о чем эта проблема?

Спасибо за объяснение @igloo15.

Я спрашиваю о параметре конфигурации, потому что анализ файлов конфигурации в начале кода AppHost требует затрат. В настоящее время AppHost не связывается с кодом для анализа файлов json (вместо этого они используются hostfxr/hostpolicy). Добавление этой функции в настоящее время сделало бы AppHost немного больше/сложнее. Однако, как только реализация переходит к дальнейшим этапам (где весь код хостинга и среды выполнения связаны вместе), это больше не проблема.

@ igloo15 документация по дизайну является важной частью, но суть этой проблемы заключается в самой функции. ExtractBaseDir является необязательным параметром, и я бы предпочел, чтобы основная функция была передана в «текущий» выпуск, а не увязала в необязательных параметрах.

@cup , я задал вопрос здесь, потому что привлек внимание заинтересованных разработчиков в этой теме.
Хотя я не думаю, что вопрос не по теме, я понимаю ваше беспокойство по поводу длины этой ветки. В следующий раз создам связанную задачу. Спасибо.

@cup @swaroop-sridhar

Пара вещей, которые я хотел бы сказать в первую очередь, это то, что эта функция имеет значение только для стадии 1 документа стадии . Все остальные этапы 2–5 связаны с запуском dll из пакета, а не с его извлечением. Таким образом, настройка для определения местоположения базового каталога извлечения не очень полезна для этапов 2-5. Поскольку NetCore 3.0 намеревается разработать этап 1, я ожидаю, что эта функция будет там, поскольку это единственный раз, когда она будет полезна.

Во-вторых, как мы отличаем этот метод от других методов, таких как dotnet-wrap. Для меня главные преимущества этого метода в том, что мы встраиваем этот процесс в цепочку сборки ближе к моменту компиляции кода. Кроме того, эта функция ориентирована на .NET и, таким образом, понимает нюансы приложений .NET Core, такие как их конфигурации, процесс сборки и т. д. Поэтому я надеюсь, что мы сосредоточимся на функциях, которые отличают этот инструмент от других инструментов, которые не предназначен специально для ядра сети. Это будут такие функции, как настройка места извлечения, которые dotnet-wrap не может сделать.

Что касается того, как это реализовано, я не уверен, но я думаю, что вместо чтения ExtractBaseDir из конфигурации во время выполнения мы не могли бы внедрить это в исполняемый файл пакета во время сборки? Я не видел кода, который заставляет этот пакетный процесс работать, но, на мой взгляд, он генерирует/создает собственный исполняемый файл со всеми DLL и т. Д. Внутри него. Разве мы не могли во время создания/сборки исполняемого файла прочитать файл runtimeconfig связанных приложений, вытащить ExtractBaseDir и установить его как свойство в собственном исполняемом файле пакета.

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

@ igloo15 : извлечение содержимого пакета на диск может быть полезно для некоторых приложений после этапа 2.
Например, если в пакете приложения есть собственные собственные двоичные файлы, их необходимо извлечь до этапа 5. Приложение может захотеть объединить файлы содержимого неизвестного типа, которые будут извлечены в файлы во время выполнения.

Я согласен с тем, что полезность этой настройки уменьшается по мере того, как мы переходим к дальнейшим этапам разработки. Однако, как только мы добавим эту опцию, нам, вероятно, придется сохранить ее во всех последующих версиях для совместимости. Поэтому сейчас он требует тщательного рассмотрения.

Я согласен с тем, что сделать место извлечения параметром времени сборки (например, msbuild-property), а не параметром runtimeconfig, проще и эффективнее с точки зрения реализации. Спасибо.

Привет, у меня есть пара вопросов по этой теме:

Я хотел бы использовать функцию распространения по одному файлу для упаковки приложений .NET Framework 4.7.2 (например) в один исполняемый файл. Такова цель этой функции или она предназначена только для поддержки приложений .NET Core?

Мой второй вопрос связан с тем, как сделана упаковка. Когда исполняемый файл будет создан, будет ли среда выполнения целевых фреймворков включена в исполняемый файл? Или он должен быть предварительно установлен на целевой машине, на которой будет запущено приложение?

@gaviriar Я не думаю, что он поддерживает приложения .NET Framework. И да, он может объединять среду выполнения .NET Core в исполняемый файл (так называемая «автономная» публикация).

@tomrus88 спасибо за ответ. Это настоящий позор для приложений .NET Framework. Есть ли какой-либо метод, который вы бы порекомендовали для объединения среды выполнения .NET Framework в исполняемый файл?

Я вижу список инструментов в соответствующем разделе документа. Есть ли что-то конкретное, что можно было бы порекомендовать для моего варианта использования, предложенного выше?

@gaviriar .NET Framework является частью ОС Windows. Нет поддерживаемого способа связать его в исполняемый файл.

@gaviriar Необходимость связать среду выполнения — одна из основных причин перехода на .NET Core.

@jnm2 и @jkotas спасибо за разъяснение, новичок в мире .NET. Я согласен, что хотел бы перейти на .NET Core. Однако я сталкиваюсь со случаем, когда мне приходится взаимодействовать с устаревшей библиотекой, предназначенной для .NET Framework. Насколько я понимаю, в таком случае я не могу переключить свое приложение на .NET Core, если мне нужно взаимодействовать с этой библиотекой. Или есть альтернативный подход, при котором мое приложение является .NET Core, но при этом может взаимодействовать с устаревшей библиотекой .NET Framework?

Это зависит от библиотеки. Многие библиотеки, ориентированные на .NET Framework, прекрасно работают и с .NET Core. Вы пытались использовать библиотеку в .NET Core? Если вы убедились, что он не работает, вы не можете переключиться, пока не найдете для него решение.

Я действительно пробовал это, но это не работает, поскольку мы говорим о библиотеках, специфичных для Windows. Думаю, у меня нет другого выбора, кроме как придерживаться таргетинга на .NET Framework и упустить удовольствие от .NET Core, как вы говорите:/

@gaviriar Это не по теме, но пробовали ли вы пакет NuGet для совместимости с Windows, который предоставляет Windows API для .NET Core именно для той цели, которую вы описываете Microsoft.Windows.Compatibility

@gaviriar Еще несколько уточнений:

Когда исполняемый файл будет создан, будет ли среда выполнения целевых фреймворков включена в исполняемый файл? Или он должен быть предварительно установлен на целевой машине, на которой будет запущено приложение?

Это зависит от сборки. Как зависящие от платформы (среда выполнения устанавливается на целевом объекте), так и автономные (среда выполнения упаковывается вместе с приложением) приложения могут быть опубликованы в виде одного файла, но только приложения .net core 3.0.

Я вижу список инструментов в соответствующем разделе документа. Есть ли что-то конкретное, что можно было бы порекомендовать для моего варианта использования, предложенного выше?

Для .net framework лучшее решение, которое я могу предложить, — это чтобы приложение само извлекало файлы. Например: внедрите зависимости как управляемые ресурсы в двоичный файл приложения, а затем явно извлеките ресурсы при запуске. Вы также можете использовать пакетную библиотеку для объединения и извлечения (поскольку библиотека построена по сетевому стандарту), но использование управляемых ресурсов является лучшим решением.

@igloo15 и @swaroop-sridhar Я ценю эти комментарии, учитывая, что они не по теме. Хотя я надеюсь, что кто-то еще найдет это обсуждение полезным при чтении когда-нибудь.

Я оценю варианты, которыми вы поделились со мной, и сообщу, какой подход окажется лучшим для моего варианта использования.

Спасибо!

Быстрое обновление!

Я протестировал это простое приложение Hello World . Я могу успешно создать один исполняемый файл. Однако, как видно из конфигурации проекта, он должен быть автономным. Но когда я пытаюсь запустить этот исполняемый файл на новой установке Windows 7 без установленной среды выполнения ядра .NET, я вижу следующую ошибку:

Failed to load the DLL from [C:\Users\vagrant\AppData\Local\Temp\.net\HelloWorld
\muasjfkf.kyn\hostfxr.dll], HRESULT: 0x80070057
The library hostfxr.dll was found, but loading it from C:\Users\vagrant\AppData\
Local\Temp\.net\HelloWorld\muasjfkf.kyn\hostfxr.dll failed
  - Installing .NET Core prerequisites might help resolve this problem.
     https://go.microsoft.com/fwlink/?linkid=798306

Я вижу, что создание публикации приложения как dotnet publish /p:PublishSingleFile=true или /p:PublishSingleFile=false не меняет размер исполняемого файла. Это ожидаемое поведение?

Действия по воспроизведению

  1. Опубликуйте проект, чтобы сгенерировать HelloWorld.exe

  2. Скопируйте исполняемый файл в установку Windows 7 без установленной среды выполнения .NET Core.

  3. Запустите HelloWorld.exe

@gaviriar Я опробовал опубликованный вами пример, и он у меня отлично сработал.
То есть он создал автономный одиночный исполняемый файл для HelloWorld, который работает нормально.

Я вижу, что создание публикации приложения как dotnet publish /p:PublishSingleFile=true или /p:PublishSingleFile=false не меняет размер исполняемого файла. Это ожидаемое поведение?

Это точно не ожидается. Однофайловое приложение должно занимать около 70 МБ (для отладочной сборки, указанной на вашей странице gitlab). В противном случае это обычный хост приложения, который, как вы отметили выше, должен потерпеть неудачу. Вы публикуете из чистого каталога?

Еще одно замечание о вашем файле проекта: одно из свойств неправильно записано как IncludeSymbolsInFile вместо IncludeSymbolsInSingleFile . Но это не имеет никакого отношения к проблеме, о которой вы сообщили.

@gaviriar , каковы ваши целевые идентификаторы среды выполнения. Если вы не установите его правильно, он не будет связывать правильную hostfxr.dll. Возможно, для hostfxr.dll требуется специальный распространяемый файл vc++, которого нет на вашем компьютере с Windows 7. Вы можете проверить, что dll по заданному пути существует, и если он попытается загрузить его в инструмент обхода зависимостей, чтобы увидеть, существует ли dll, от которого он зависит.

Слияние IL: такие инструменты, как ILMerge, объединяют IL из многих сборок в одну, но при этом теряют идентичность сборки. Это не цель для однофайловой функции.

потерять идентичность сборки

это не проблема.
Я всегда против использования zip/unzip или других пакетных решений для автономной функции Single exe.
потому что это вызовет следующие проблемы.
Как уменьшить размер файла Single exe!?? или почему exe-файл такой большой, но это всего лишь привет, мир!??

Всегда есть проблема, и ее нужно решать, почему бы не заняться основательно.
На самом деле с самого начала следует использовать IL-Merge аналогичными способами.

На самом деле, люди не настолько одержимы одним EXE.
exe (1) + dll (1-2) также в порядке, но не 400 библиотек монтирования.
ppl не хотел бы переносить код, который никогда не будет выполняться, на диск сервера и запускать его, занимая память сервера.
люди просто хотят снизить стоимость развертывания (диск, память, пропускная способность и т. д.)

Я удалил веху 3.0, чтобы в этом выпуске реализация однофайловой функции отслеживалась по этапам, описанным в этом документе , что выходит за рамки выпуска 3.0.

@sgf , я согласен, что нужно поработать, чтобы уменьшить размер файла. Возможности по уменьшению размера бывают двух видов, они конкретно не привязаны к single-exe:
1) Уменьшите количество контента, который необходимо опубликовать. Например:
* Используйте ILLinker как инструменты для обрезки ненужных двоичных файлов, частей сборок и т. д.
Эта работа отдельно отслеживается по таким проблемам, как dotnet/coreclr#24092 и mono/linker#607.
* Мы можем рассмотреть другие меры, такие как режим «уменьшенных возможностей», когда JITting не поддерживается, чтобы уменьшить
2) Добавить функцию сжатия в публикацию одного файла.

Вышеупомянутые функции могут работать вместе, чтобы уменьшить размер однофайловых (и не однофайловых) приложений:
Например, для консольного приложения HelloWorld:
Обычный размер публикации = 67,4 МБ.
Обрезанный размер = 27 МБ
Обрезанный, один файл, сжатый (через прототип) = 12 МБ

@swaroop-sridhar Есть ли способ получить путь к вашему одному файлу exe в вашем приложении?
Использование Assembly.GetExecutingAssembly().Location приведет к выводу каталога извлечения в \AppData\Local\Temp.net.

@ chris3713 chris3713 В настоящее время лучший способ получить доступ к местоположению exe — это PInvoke для собственных API. Например: GetModuleFileNameW (Null, <buffer>, <len>)

@ chris3713 chris3713 В настоящее время лучший способ получить доступ к местоположению exe — это PInvoke для собственных API. Например: GetModuleFileNameW (Null, <buffer>, <len>)

Спасибо, в итоге я использовал Process.GetCurrentProcess().MainModule.FileName .

Отлично работает с asp .net core worker/web API, так как служба Windows опубликована с PublishSingleFile=true.

Когда я регистрирую службу и запускаю ее через sc create testwk binPath="[...]/MyAspNetCoreWorker.exe" , затем sc start testwk , я получаю сообщение об успешном завершении:

[...]\bin\publish\x64>sc start testwk

SERVICE_NAME: testwk
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 5060
        FLAGS              :

[...]\bin\publish\x64>sc stop testwk

SERVICE_NAME: testwk
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 3  STOP_PENDING
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

Жду не дождусь, когда увижу этап 2 с бегом в комплекте😀
Кстати, планируется ли, что Stage 2 будет частью .Net Core 3.0?

Спасибо за вашу работу, сервис публикации в .net core теперь очень прост 👍

CoreRT: ( 2,5 МБ )

image

image

Без взлома zip , без скрытых затрат , движок содержит только то, что необходимо, а неиспользуемые функции отключаются с помощью конфигурации csproj (отражение)

Это то, что нужно dotnet, он конкурирует с GO и даже превосходит его как по размеру, так и по производительности.

Кому интересно, проверьте репозиторий:

https://github.com/dotnet/corert

Есть образцы для MonoGame:

https://github.com/dotnet/corert/tree/master/samples/MonoGame

Ни одно из предложенных решений не может достичь такого результата, CoreRT действительно лучший, MS совершает огромную ошибку, не фокусируясь на нем

Я протестировал эту функцию на macOS с dotnet-sdk-3.0.100-preview8-013656-osx-x64.tar.gz . Если мы переключим конфигурацию с Debug на Release или наоборот и снова соберем, это добавит 10 МБ к размеру исполняемого файла. Перекомпиляция со старой конфигурацией не восстановит это увеличение размера, если мы не удалим каталог bin .

mkdir /tmp/dotnet-preview8
curl -s https://download.visualstudio.microsoft.com/download/pr/a974d0a6-d03a-41c1-9dfd-f5884655fd33/cf9d659401cca08c3c55374b3cb8b629/dotnet-sdk-3.0.100-preview8-013656-osx-x64.tar.gz | tar -xvz -C /tmp/dotnet-preview8
export PATH=/tmp/dotnet-preview8:$PATH

dotnet new console -o /tmp/myApp
pushd /tmp/myApp

# publish with Debug
dotnet publish /p:PublishSingleFile=true,RuntimeIdentifier=osx-x64,Configuration=Debug -o bin/a/b/c/d

bin/a/b/c/d/myApp
# outputs: Hello World!

du -sh bin/a/b/c/d
# outputs  70M  bin/a/b/c/d

# publish with Release
dotnet publish /p:PublishSingleFile=true,RuntimeIdentifier=osx-x64,Configuration=Release -o bin/a/b/c/d

du -sh bin/a/b/c/d
# outputs:  80M bin/a/b/c/d

# publish with Debug again
dotnet publish /p:PublishSingleFile=true,RuntimeIdentifier=osx-x64,Configuration=Debug -o bin/a/b/c/d
# still outputs:  80M   bin/a/b/c/d

Даже без изменения конфигурации сборки, если мы вызовем Rebuild target впоследствии ( /t:Rebuild ) после первоначальной сборки, размер вывода увеличится.

Спасибо @am11 за внимание. Публикация с сохранением старых двоичных файлов — известная проблема (cc @nguerrera).

Начиная с .Net Core 3 preview 8, я не могу запустить опубликованное приложение с одним файлом.
В средстве просмотра событий у меня есть эта ошибка:

image

Я на Windows Server 2019

Изменить. Эта ошибка возникла после обновления .Net Core SDK Preview 7 до .Net Core SDK Preview 8. После перезагрузки сервера я снова могу правильно запустить свое приложение.

@Safirion мы внесли изменения в базовый внутренний формат этих предварительных просмотров. Возможно, вы объединили вывод одного предварительного просмотра и построили его с помощью другого. Между Preview 8 и 9 нет перерывов.

В Linux путь извлечения по умолчанию выглядит как /var/tmp/.net . В AWS lambda путь /var недоступен для записи, поэтому создать эту папку не удается. Чтобы получить возможность запуска без установки DOTNET_BUNDLE_EXTRACT_BASE_DIR, я предлагаю изменить это на /tmp/.net . Или, возможно, должно быть несколько попыток в общих местах (/var/tmp, /tmp, тот же каталог, что и двоичный файл и т. д.)

@ stevemk14ebr спасибо, что сообщили об этой проблеме. Можете ли вы создать новую проблему, чтобы отслеживать эту работу? https://github.com/dotnet/core-setup

@jeffschwMSFT Та же ошибка возникла при переходе с .Net Core P9 на RC1.

Description: A .NET Core application failed.
Application: Setup.exe
Path: C:\Users\Administrateur\Desktop\Setup.exe
Message: Failure processing application bundle.
Failed to determine location for extracting embedded files
A fatal error was encountered. Could not extract contents of the bundle

@Safirion спасибо, что сообщили об этой проблеме. Можете ли вы создать отдельную проблему, чтобы воспроизвести это? https://github.com/dotnet/core-setup
копия @swaroop-sridhar

@Safirion , не могли бы вы прислать инструкции по воспроизведению? Является ли эта неудача детерминированной?
Пожалуйста, отправьте сообщение о проблеме в репозиторий основных настроек, как предложил @jeffschwMSFT выше.

Я посмотрел на это, и это произойдет только в том случае, если приложение работает в среде, где временный каталог недоступен. Например, если я сделаю это:

set "TMP=wrong_path"
myapp.exe

Это терпит неудачу с

Failure processing application bundle.
Failed to determine location for extracting embedded files
A fatal error was encountered. Could not extract contents of the bundle

Обратите внимание, что пакет ищет временный каталог, используя API GetTempPath win32. Который использует env. переменная TMP , затем TEMP и так далее. Если первый со значением содержит недопустимый путь, это приведет к ошибке.

Вы можете исправить это, либо убедившись, что временный путь установлен правильно, либо вы можете явно указать DOTNET_BUNDLE_EXTRACT_BASE_DIR в место, где вы хотите, чтобы произошло извлечение.

@Safirion , не могли бы вы прислать инструкции по воспроизведению? Является ли эта неудача детерминированной?
Пожалуйста, отправьте сообщение о проблеме в репозиторий основных настроек, как предложил @jeffschwMSFT выше.

Я не могу воспроизвести эту проблему после обновления .Net Core до RC1 и перезапуска сервера. (Я попытался удалить RC1 и снова установить Preview 9, чтобы снова обновиться до RC1, но на этот раз мое приложение запускается хорошо)

Эта ошибка произошла при переходе с SDK 3.0 P7 на SDK 3.0 P8 и SDK 3.0 P9 на SDK 3.0 RC1.
И в обоих случаях проблема решается простым перезапуском сервера.

Я использую службу Windows .Net Core (рабочий процесс использует папку C:\Windows\Temp\.net для извлечения с момента ее запуска системой) и приложение .Net Core WPF (запуск с помощью сценария сеанса запуска пользователя), когда я обновился до RC1. Возможно, эта ошибка вызвана тем, что во время установки .Net Core SDK работает основной рабочий .Net, я не знаю...

Обратите внимание, что я устанавливаю SDK, а не среду выполнения, потому что мне нужно одновременно развернуть 3 среды выполнения .Core (ядро asp.net, ядро ​​и ядро ​​.net для настольных компьютеров), а https://dot.net не дает нам «полную среду выполнения». installer" (я даже не нашел установщика рабочего стола, так что выбора нет)...

Обновление: неважно, нашел документацию .

Привет, спасибо за твой труд!

Как должны распространяться файлы конфигурации (например, App.config)? Я только что создал консольное приложение на RHEL 7.6 с точной последовательностью команд:

dotnet restore -r win-x64 --configfile Nuget.config
dotnet build Solution.sln --no-restore -c Release -r win-x64
dotnet publish --no-build --self-contained -c Release -r win-x64 /p:PublishSingleFile=true -o ./publish ./SomeDir/SomeProj.csproj

где SomeProj.csproj включает <PublishTrimmed>true</PublishTrimmed> и в результате получил 2 файла: SomeProj.exe и SomeProj.pdb , но не SomeProj.config

@catlion , чтобы иметь поведение по умолчанию для файлов *.config, их следует исключить из пакета. По умолчанию все файлы, отличные от pdb, включены в пакет.
Следующее исключит конфигурацию из одного файла:

<ItemGroup>
    <Content Update="*.config">
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
    </Content>
  </ItemGroup>

https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#build-системный-интерфейс

@morganbr

С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)

Безголовые и WPF-приложения для Windows

Включает ли ваше приложение (не .NET) C++/собственный код?

Да, мы P/Invoke к множеству нативных dll, некоторым сторонним элементам, над которыми мы не имеем никакого контроля, некоторым внутренним от других команд.

Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?

Да, но мы используем CompilerServices для их компиляции из исходного кода.

Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?

да

Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?

Да, наше приложение обычно остается открытым в течение длительного периода времени.

Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?

Да, мы можем подождать несколько минут.

Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?

да

Спасибо @john-cullen

Связывание нескольких PR с веткой single-exe для реализации прототипа запуска однофайловых приложений без извлечения ( этап 4 ).

https://github.com/dotnet/coreclr/pull/26197
https://github.com/dotnet/coreclr/pull/26504
https://github.com/dotnet/coreclr/pull/26697
https://github.com/dotnet/coreclr/pull/26904

Позвольте мне также дать несколько ответов для @morganbr :) Не знаю, читаете ли вы их еще :)

  1. С каким приложением вы, вероятно, будете его использовать? (например, WPF в Windows? ASP.NET в контейнере Linux Docker? Что-то еще?)

Текстовые приключения (консольные приложения) для запуска на разных платформах (Linux, MacOS, Windows)

  1. Включает ли ваше приложение (не .NET) C++/собственный код?

Нет.

  1. Будет ли ваше приложение загружать плагины или другие внешние библиотеки DLL, которые вы изначально не включили в сборку приложения?

В настоящее время нет, но в долгосрочной перспективе было бы здорово поддерживать определенные сценарии.

  1. Готовы ли вы перестроить и распространить свое приложение, чтобы включить исправления безопасности?

да.

  1. Вы бы использовали его, если бы ваше приложение запускалось на 200-500 мс медленнее? А 5 секунд?

да.
(Было бы здорово предоставить текстовый вывод или окно сообщения, чтобы уведомить пользователя о том, что что-то происходит)

  1. Какой максимальный размер вы считаете приемлемым для своего приложения? 5 МБ? 10? 20? 50? 75? 100?

10-20 Мб.

  1. Согласны ли вы с более длительным временем сборки релиза, чтобы оптимизировать размер и/или время запуска? Какой самый длинный вы бы согласились? 15 секунд? 30 секунд? 1 минута? 5 минут?

1+ минут нормально.

  1. Готовы ли вы выполнять дополнительную работу, если это сократит размер вашего приложения вдвое?

Возможно.

Спасибо за ответ, @lenardg.

Эта проблема отслеживает ход выполнения функции распространения одного файла .NET Core 3.0.
Вот дизайн-документ и план создания этой функции.

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

  1. Условно можно ли сжать при упаковке одного исполняемого файла?
    т.е. добавить Wrap как логику, поэтому нам не нужны другие инструменты интеграции.
    Сжатый будет производить еще меньший exe.

  2. При запуске exe он расширяет свое содержимое во временную папку. Для нашего продукта на некоторых пользовательских сайтах клиентские машины строго контролируются и не позволяют запускать исполняемые файлы из временной папки или даже из расположений %userprofile%.

Можно ли указать / контролировать, где извлекать или может быть «извлечение на месте» в «.\extract» или в такой подпапке?
Это обеспечивает соответствие групповым политикам, а также возможность использовать функцию одного исполняемого файла.

  1. Перед запаковкой можно ли подписать папку и потом она выбирает файлы для упаковки?
    Мы можем подписать один исполняемый файл, но файлы извлечения не подписаны, и, следовательно, в некоторых других местах клиента он не разрешает выполнение, если двоичные файлы не подписаны.

Просто хотел сообщить вам, что сегодня я видел ту же проблему, что и @Safirion . У меня есть приложение dotnetcore 3.0, ориентированное на Ubuntu, и я решил запустить его на своем сервере Synology. Он не извлекался - продолжал сбой с ошибкой «Обнаружена фатальная ошибка. Не удалось извлечь содержимое пакета». Несколько раз переделывал, но одно и то же. После перезагрузки хоста он снова работал нормально.

Было бы полезно понять, есть ли здесь блокировка файла или что-то в этом роде, и есть ли время, как его отлаживать.

@RajeshAKumar dotnet/core-setup#7940

Я не уверен, как эта ссылка поможет.
Это просто говорит о временном извлечении, я перечислил 3 пункта выше.

И я дал вам решение для одного из них. про остальные 2 понятия не имею

И я дал вам решение для одного из них. про остальные 2 понятия не имею

Временное извлечение не работает для нас, следовательно, это не решение. Мой запрос заключался в возможности контролировать, где он извлекается или может быть извлечен на месте во вложенную папку.
ИТ-администраторы на многих наших клиентских компьютерах не разрешают запускать исполняемые файлы из временных папок или из профиля пользователя.
Пожалуйста, перечитайте сообщение https://github.com/dotnet/coreclr/issues/20287#issuecomment -542497711

@RajeshAKumar : вы можете установить DOTNET_BUNDLE_EXTRACT_BASE_DIR для управления базовым путем, по которому хост извлекает содержимое пакета.
Подробнее см. здесь: https://github.com/dotnet/designs/blob/master/accepted/single-file/extract.md#extraction -location

@RajeshAKumar : сжатие связанного одиночного исполняемого файла является рассматриваемой функцией для .net 5: https://github.com/dotnet/designs/blob/master/accepted/single-file/design.md#compression

На данный момент вам нужно будет использовать другие утилиты для сжатия сгенерированного файла single-exe.

@RajeshAKumar , что касается подписи, вы можете подписать все файлы / двоичные файлы, которые публикуются и объединяются в единый exe-файл. Когда хост извлекает встроенные компоненты на диск, отдельные файлы сами будут подписаны. Вы также можете подписать сам построенный одиночный файл, как вы упомянули.

Это соответствует вашим требованиям?

@Webreaper Если вы можете воспроизвести проблему, не могли бы вы запустить приложение с включенным COREHOST_TRACE (установите для переменной среды COREHOST_TRACE значение 1 ) и поделитесь сгенерированным журналом? Спасибо.

@swaroop-sridhar
Это очень классная функция. У вас есть ссылка на то, когда будут доступны разные этапы, в каком выпуске dotnet?

@RajeshAKumar : вы можете установить DOTNET_BUNDLE_EXTRACT_BASE_DIR для управления базовым путем, по которому хост извлекает содержимое пакета.
Подробнее см. здесь: https://github.com/dotnet/designs/blob/master/accepted/single-file/extract.md#extraction -location

Спасибо, сваруп-шридхар.

@RajeshAKumar , что касается подписи, вы можете подписать все файлы / двоичные файлы, которые публикуются и объединяются в единый exe-файл. Когда хост извлекает встроенные компоненты на диск, отдельные файлы сами будут подписаны. Вы также можете подписать сам построенный одиночный файл, как вы упомянули.

Это соответствует вашим требованиям?

Я пытаюсь понять, как сломать «компилировать» и опубликовать части.
В настоящее время я использую следующую команду, поэтому она не дает мне возможности подписывать.
Установить publishargs=-c Release /p:PublishSingleFile=True /p:PublishTrimmed=True /p:PublishReadyToRun=false
публикация в dotnet -r win-x64 -o bin\Output\Win64 %publishargs%

Поскольку вышеперечисленное компилируется так же, как и обрезки и пакеты, не знаю, как их сломать.
В идеале, чтобы использовать ваш подход, мне придется скомпилировать, затем подписать и, наконец, опубликовать.

@Webreaper Если вы можете воспроизвести проблему, не могли бы вы запустить приложение с включенным COREHOST_TRACE (установите для переменной среды COREHOST_TRACE значение 1 ) и поделитесь сгенерированным журналом? Спасибо.

Спасибо. Теперь это исчезло, потому что я перезагрузился, но полезно отметить это, если это произойдет снова!

@RajeshAKumar вам нужно пометить подпись для цели, которая запускается непосредственно перед объединением.
Поскольку вы используете PublishReadyToRun и PublishTrimmed , вы не можете использовать стандартные цели Afterbuild или BeforePublish .

Вы можете добавить цель, которая запускается непосредственно перед BundlePublishDirectory и выполняет подписание.

@swaroop-sridhar
Это очень классная функция. У вас есть ссылка на то, когда будут доступны разные этапы, в каком выпуске dotnet?

Спасибо @etherealjoy. Работа над отдельными файлами, запускаемыми непосредственно из пакета, продолжается, и, насколько я понимаю, нацелена на выпуск .net 5.

@RajeshAKumar вам нужно пометить подпись для цели, которая запускается непосредственно перед объединением.
Поскольку вы используете PublishReadyToRun и PublishTrimmed , вы не можете использовать стандартные цели Afterbuild или BeforePublish .

Вы можете добавить цель, которая запускается непосредственно перед BundlePublishDirectory и выполняет подписание.

Спасибо.
Ссылка, которую вы дали, выглядит как задачи MS Build.
Как создать обработчик для «BundlePublishDirectory»? Это в Studio/Project props/Build Events или мне нужно создать что-то с нуля.

@RajeshAKumar в этом случае вам понадобится что-то более детальное, чем события после сборки перед сборкой.
Итак, я думаю, вам следует отредактировать файл проекта и добавить что-то вроде:

<Target Name="Sign" BeforeTargets="BundlePublishDirectory">
    ... 
</Target>

Каково ожидаемое поведение команды dotnet pack при этом? Допустим, у нас есть артефакт с одним исполняемым файлом, отправленный в локальный репозиторий nuget. Если я попытаюсь установить его с помощью шоколада, он попытается восстановить все nuget-депозиты, перечисленные в файле проекта. Что и ожидалось ранее, но я сомневаюсь, что такое поведение правильно для SFD.

Можно ли добавить индикатор выполнения или индикатор загрузки во время извлечения однофайлового автономного приложения WPF, это может занять некоторое время, когда ничего не происходит.
Базовое автономное приложение WPF занимает более 80 миллионов минут, а извлечение может занять более 5 секунд. Это не очень удобно для пользователя, и я получил жалобы от моих конечных пользователей.

Редактировать: Есть ли способ автоматически очистить старую версию при запуске?

@Safirion Я не понимаю, как это может относиться к этой функции. Если вам нужно, чтобы вам лучше всего служило создание собственного крошечного приложения, которое показывает заставку и запускает реальное приложение, а затем реальное приложение останавливает программу-заставку при ее запуске.

@ProfessionalNihilist Я думаю, вы не понимаете мою точку зрения.
Самодостаточное пустое приложение WPF при компиляции использует 80 мес дискового пространства. У вас не может быть более крошечного приложения WPF, чем 80mo, без компиляции его как приложения, зависящего от фреймворка 😉
Проблема заключается во времени извлечения включенного фреймворка до запуска приложения. Так что это должно быть сделано ядром .Net, и это полностью связано с этой функцией.

Может быть, добавить возможность иметь png , который будет отображаться, пока приложение распаковывается?

@Safirion @ayende отсутствие «обратной связи с пользовательским интерфейсом» во время запуска отслеживается здесь: https://github.com/dotnet/core-setup/issues/7250

Каково ожидаемое поведение команды dotnet pack при этом? Допустим, у нас есть артефакт с одним исполняемым файлом, отправленный в локальный репозиторий nuget. Если я попытаюсь установить его с помощью шоколада, он попытается восстановить все nuget-депозиты, перечисленные в файле проекта. Что и ожидалось ранее, но я сомневаюсь, что такое поведение правильно для SFD.

@catlion свойство PublishSingleFile поддерживается только командой dotnet publish . Таким образом, это не влияет на dotnet pack . Есть ли мотивация использовать и однофайловость, и упаковку?

Редактировать: Есть ли способ автоматически очистить старую версию при запуске?

@Safirion в текущем выпуске очистка выполняется вручную, хост не пытается удалить извлеченные файлы, поскольку они потенциально могут быть повторно использованы в будущих запусках.

Хорошо, я сделаю свой собственный очиститель 😉
Спасибо за ваш ответ.

@cup , в котором нет ничего особенного в моно, это просто стандартная компиляция, теперь добавьте ссылку на nuget, и это решение больше не будет одним файлом. Mono имеет mkbundle , хотя для достижения одного файла

@Сучиман , ты уверен? В моем примере выше создается один файл размером 3 КБ. Хотя минимальный размер dotnet составляет 27 МБ:

https://github.com/dotnet/coreclr/issues/24397#issuecomment-502217519

@чашка да

C:\Users\Robin> type .\Program.cs
using System;
class Program {
   static void Main() {
      Console.WriteLine("sunday monday");
   }
}
C:\Users\Robin> C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe .\Program.cs
Microsoft (R) Visual C# Compiler version 4.8.3752.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.

This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240

C:\Users\Robin> .\Program.exe
sunday monday
C:\Users\Robin> dir .\Program.exe


    Verzeichnis: C:\Users\Robin


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       10.11.2019     18:36           3584 Program.exe

@Сучиман , ты уверен? В моем примере выше создается один файл размером 3 КБ. Хотя минимальный размер dotnet составляет 27 МБ:

#24397 (комментарий)

Ваш файл 3k работает только потому, что моно уже установлено. Весь смысл однофайлового распространения dotnetcore заключается в том, что вам не нужно устанавливать clr, это отдельный отдельный исполняемый файл, включающий среду выполнения.

@Webreaper на самом деле, я считаю, что он использовал только mcs из моно для компиляции, поскольку он не писал mono sun-mon.exe , он, вероятно, работал на .NET Framework.

Но .NET Core также поддерживает сценарий предустановленной среды выполнения, то есть развертывание, зависящее от платформы. В этом случае это все еще не совсем однофайловое развертывание, поскольку есть несколько дополнительных файлов для .NET Core, таких как .deps.json и .runtimeconfig.json

@ chris3713 chris3713 В настоящее время лучший способ получить доступ к местоположению exe — это PInvoke для собственных API. Например: GetModuleFileNameW (Null, <buffer>, <len>)

Кажется, Environment.CurrentDirectory — лучшее решение, хотя я еще не пробовал оба подхода на чем-то другом, кроме Windows.

РЕДАКТИРОВАТЬ: Нет. Этот путь может быть изменен в разных точках входа в приложение. Не хорошо.

Немного связанная с этим заметка: я обнаружил эту регрессию в однофайловой публикации приложений Blazor в последнем предварительном просмотре VS для Mac: https://github.com/aspnet/AspNetCore/issues/17079 — я сообщил об этом в разделе AspNeCore/Blazor, но может быть, это более актуально для группы coreclr - не уверен. Оставлю это для вас, ребята, чтобы передвигаться!

@Suchiman осторожно, у этого компилятора есть проблемы:

https://github.com/dotnet/roslyn/issues/39856

@cup , за исключением того, что, используя путь к файлу, который я назвал, вы используете старый компилятор C # 5, написанный на C ++, который не является roslyn, и по этой причине они, вероятно, закроют эту проблему. Но Рослин может сделать то же самое, только другим путем...

Немного связанная с этим заметка: я обнаружил эту регрессию в однофайловой публикации приложений Blazor в последнем предварительном просмотре VS для Mac: aspnet/AspNetCore#17079 — я сообщал об этом в AspNeCore/Blazor, но, возможно, это более актуален для группы coreclr - не уверен. Оставлю это для вас, ребята, чтобы передвигаться!

@Webreaper Спасибо за сообщение о проблеме, которая выглядит как проблема ASP.net в отношении статических ресурсов. Итак, это правильное место, чтобы подать его.

* Перенос поста из другого выпуска сюда.

@swaroop-sridhar ,

Время запуска однофайловых WPF-приложений DotNet Core намного медленнее, чем исходное приложение ILMerge-ed WPF, построенное на .net 4.7. Этого следует ожидать или ситуация улучшится в будущем?

Сборки взяты из моего ImageOptimizer: https://github.com/devedse/DeveImageOptimizerWPF/releases.

| Тип | Расчетное время первого запуска | Расчетное время второго запуска | Размер | Ссылка для скачивания |
| -- | -- | -- | -- | -- |
| .NET 4.7.0 + ILMerge | ~3 сек | ~1 сек | 39,3 Мб | ССЫЛКА |
| dotnet publish -r win-x64 -c Release --self-contained=false /p:PublishSingleFile=true | ~10 сек | ~3 сек | 49мб | |
| dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true | ~19 сек | ~2 сек | 201 мб | |
| dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true | ~15 сек | ~3 сек | 136мб | ССЫЛКА |
| dotnet publish -r win-x64 -c Выпуск | ~2,5 сек | ~1,5 сек | 223кб для exe (+400мб для dll) | |

@devedse , чтобы убедиться, является ли «второй запуск» средним значением нескольких запусков (кроме первого)?
Мне любопытно, но у меня нет никакого объяснения, почему запуск /p:PublishSingleFile=true /p:PublishTrimmed=true должен быть медленнее, чем запуск ` /p:PublishSingleFile=true .

Итак, прежде чем исследовать, я хочу убедиться, что числа во «втором запуске» являются стабильными числами и что разница в запуске воспроизводима,

Кроме того, эта проблема касается однофайловых подключаемых модулей. Не могли бы вы перенести обсуждение производительности в новую проблему или в dotnet/coreclr#20287? Спасибо.

@swaroop-sridhar, в ответ на ваш вопрос о среднем:
Мне немного сложно очень точно определить время, поэтому время было определено путем подсчета во время запуска приложения, а затем несколько раз, чтобы увидеть, есть ли значительная разница во времени запуска. Если вам известен лучший метод, вы можете легко воспроизвести его, создав мое решение: https://github.com/devedse/DeveImageOptimizerWPF.

Мой главный вопрос касается того, почему для запуска связанного (однофайлового) приложения требуется больше времени по сравнению с несвязанным файлом .exe.

Я могу ошибаться здесь, но для меня это имеет смысл, поскольку с одним файлом возникают накладные расходы. По сути, у вас есть приложение, которое запускает другое приложение. Пока ILMerge запускается напрямую. ILMerge только объединил ссылочные dll в exe, он не обернул все это в другой слой, что в настоящее время делается с PublishSingleFile.

@devedse Один файл, по сути, извлекается, проверяет контрольные суммы и т. Д. Перед запуском dotnet.
Думаю, именно поэтому это заняло это время.
Экстракт «кэшируется», поэтому при следующем запуске нет накладных расходов на ввод-вывод.

@RajeshAKumar , хм, действительно ли извлечение нужно в этом сценарии? Не лучше ли пойти по пути ILMerge и объединить библиотеки DLL в один пакет?

Особенно для больших файлов .exe вы также увеличиваете стоимость дискового пространства для хранения всех файлов дважды.

@devedse Мы все ждем следующих этапов этой функции (Запуск из пакета), но пока это единственное решение. 😉

https://github.com/dotnet/designs/blob/master/accepted/single-file/staging.md

это то, что вы получаете за использование JIT на рабочем столе, медленный запуск, похоже, только Apple это поняла

(В основном повторяю уже изложенное):
Ожидается, что первый запуск будет намного медленнее — приложение извлекается на диск — так много операций ввода-вывода. Второй и последующие запуски должны быть практически идентичны неоднофайловой версии приложения. В наших внутренних измерениях мы не увидели разницы.

Как измерить: мы использовали трассировку (ETW в Windows) — есть события, когда процесс запускается, а есть события времени выполнения, которые можно использовать для этого — хотя это не совсем просто.

Как уже упоминалось @Safirion , мы работаем над следующим улучшением для одного файла, который должен запускать большую часть управляемого кода из .exe напрямую (без извлечения на диск). Пока не могу обещать выпуск поезда.

JIT: весь фреймворк должен быть предварительно скомпилирован с помощью Ready2Run (CoreFX, WPF), поэтому при запуске JIT-компилировать следует только код приложения. Это не идеально, но это должно иметь большое значение. Учитывая время запуска ~ 1-2 секунды, я думаю, что это уже используется во всех тестах.

Спасибо всем, я не знал о следующих запланированных шагах. Это проясняет это.

Ожидается, что первый запуск будет намного медленнее — приложение извлекается на диск — так много операций ввода-вывода.

Этого никогда не должно было случиться, вы делаете пользовательский опыт ужасным ПО ДИЗАЙНУ, ужасным выбором, вот как вы заставляете пользователей ненавидеть технологию, которую разработчик использует для них.

Как уже упоминалось @Safirion , мы работаем над следующим улучшением для одного файла, который должен запускать большую часть управляемого кода из .exe напрямую (без извлечения на диск). Пока не могу обещать выпуск поезда.

Зачем выпускать это официально сейчас, если это скоро изменится? должен быть помечен как предварительный/экспериментальный

на мой взгляд, это пустая трата времени и ресурсов, сосредоточьтесь на компиляции AOT и древотрясении, поместите туда все свои ресурсы, перестаньте заниматься хаками

@RUSshy Откуда столько ненависти? Если вы не хотите задержки запуска при первом запуске, не используйте однофайловое развертывание.

Я считаю, что запуск занимает значительно меньше 10 секунд, и, поскольку это только первый раз, когда вы запускаете, это вообще не проблема. Я развертываю веб-приложение на стороне сервера, что означает, что в большинстве случаев оно будет запускаться один раз, а затем работать в течение нескольких дней/недель, поэтому начальное извлечение незначительно в схеме вещей, поэтому я бы предпочел это как временной заменой до тех пор, пока не будет скомпилирован один образ, потому что это просто делает развертывание намного проще, чем копирование сотен DLL повсюду.

+1 в моем случае у нас есть докер сборки, генерирующий один exe-файл, и отдельный докер для запуска приложения (с использованием обычного образа докера Alpine без dotnet). После шага bulid мы один раз загружаем исполняемый контейнер и docker-commit слой. Впоследствии мы не наблюдали снижения производительности по сравнению с развертыванием, зависящим от платформы. Как только механизм загрузки файлов из комплекта будет реализован и отправлен, мы удалим промежуточный этап горячей загрузки.

@vitek-karas, есть ли проблема с отслеживанием функции «загрузить ресурсы среды выполнения из пакета»? интересно понять, какие препятствия существуют. :)

@am11 Сейчас мы составляем подробный план. Вы можете посмотреть на прототип, который был сделан в https://github.com/dotnet/coreclr/tree/single-exe. Реальная реализация, вероятно, не будет сильно отличаться (очевидно, лучше факторинг и т. д., но основная идея кажется здравой).

@Webreaper Для веб-приложений это вообще не проблема, но, возможно, потому, что .Net Core 3 сейчас рекомендуется для разработки WPF/WinForm, и что совместное использование настольного приложения .exe, потерянного в сотнях .dll, не вариант, тогда я полностью понять разочарование, связанное с первым этапом этой функции.
;)

И ни один пользователь не ждет 10 секунд (или более 3 секунд), прежде чем повторно щелкнуть исполняемый файл сегодня. Тот факт, что нет индикатора загрузки, является второй большой проблемой этой функции. К сожалению, кажется, что индикатор загрузки не будет частью .Net Core 3.1, поэтому пользователям придется набраться терпения...

Разработчики десктопов очень ждут этапа 2, и я ожидаю, что он станет частью .Net 5, потому что на самом деле разработка десктопов в .Net Core — это очень плохой опыт для конечных пользователей.

@RUSshy Откуда столько ненависти? Если вы не хотите задержки запуска при первом запуске, не используйте однофайловое развертывание.

это не ненависть, это конструктивный и честный отзыв, я забочусь о C# и .net, я использую оба каждый день, я не хочу, чтобы его заменили на GO или что-то еще

недавно:
https://old.reddit.com/r/golang/comments/e1xri3/choosing_go_at_american_express/
https://old.reddit.com/r/golang/comments/ds2z51/the_stripe_cli_is_now_available_and_its_writing/

отрицательный отзыв так же полезен, как и положительный, но если вы воспринимаете его как «ненависть», то я не могу вам помочь.

Сообщество .net ведет к молчанию, пассивности и предвзятости, разрушение — единственный выход

На сегодняшний день .NET объективно является лучшей платформой для большинства приложений. Я хочу, чтобы больше людей поняли это.

Истории о войне, которые я слышу от других платформ, таких как Java, Go, Rust, Node, ... откровенно тревожат. Эти платформы убивают производительность.

на мой взгляд, это пустая трата времени и ресурсов, сосредоточьтесь на компиляции AOT и древотрясении, поместите туда все свои ресурсы, перестаньте заниматься хаками

Я согласен. В .Net отличная система типов. Слишком много раз его обходят с помощью отражения. Инструменты должны быть сосредоточены на AOT, а также на минимизации размышлений. https://github.com/dotnet/corert/issues/7835#issuecomment -545087715 было бы очень хорошим началом. Сейчас устраняется ошибка нулей на миллиард долларов; то же самое следует сделать с отражением с настройкой или маркером для кода без отражения (или, иначе, код, совместимый с компоновщиком или корертом).

Устранение отражения было бы здорово. Таких страданий можно было бы избежать, если бы рефлексия была запрещена. Моя самая последняя ужасная история заключалась в том, что я обнаружил, что не могу перемещать код, потому что используемая структура (SDK сервисной фабрики) сочла разумным связать сериализованные байты с именем сборки реализации сериализатора без возможности переопределения.

Любой прогресс в направлении обескураживающего размышления будет прогрессом.

Кстати, искал способ объединить сборки, чтобы уменьшить размер пакета и время загрузки, а также оптимизировать всю программу. Я понимаю, что эта проблема на самом деле не нацелена на это.

Редактировать: поскольку этот пост собрал некоторые реакции, просто чтобы уточнить. Я считаю, что метапрограммирование должно происходить во время разработки, когда код — это данные, и они находятся под моим контролем.

Типы, которые мне нравится использовать для обеспечения инвариантов, которым я могу доверять. Отражения во время выполнения разрушают это доверие.

Следовательно, я бы хотел, чтобы отражение во время выполнения было заменено метапрограммированием во время разработки. Там, где он также может быть более мощным, перекрывающимся с такими вариантами использования, как анализаторы, быстрые исправления и рефакторинг.

Отметка подписчиков в этой области: @swaroop-sridhar
Сообщите danmosemsft, если хотите подписаться.

Дизайн функции в одном файле описан в этом документе: https://github.com/dotnet/designs/blob/master/accepted/2020/single-file/design.md .
Отслеживание хода однофайловых приложений в этом выпуске: https://github.com/dotnet/runtime/issues/36590.
Спасибо всем за ваши отзывы и предложения в этом выпуске.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

EgorBo picture EgorBo  ·  3Комментарии

chunseoklee picture chunseoklee  ·  3Комментарии

v0l picture v0l  ·  3Комментарии

Timovzl picture Timovzl  ·  3Комментарии

btecu picture btecu  ·  3Комментарии