- PVSM.RU - https://www.pvsm.ru -
В мире кроссплатформенной разработки WPF (Windows Presentation Foundation) долгое время оставался эксклюзивной технологией Microsoft, доступной только на Windows. Однако с развитием контейнеризации и инструментов совместимости, таких как Wine, появляется возможность запускать WPF-приложения в изолированных средах Linux. Эта статья рассказывает о моем опыте запуска WPF-приложений внутри Docker-контейнеров с использованием Wine — решения.
Важное предупреждение: WPF официально не поддерживается на Linux. Данное решение является экспериментальным и рекомендуется в первую очередь для тестирования, образовательных целей или специфических сценариев. Простые приложения могут работать, но сложные интерфейсы со сложной графикой, скорее всего, столкнутся с ограничениями.
Почему вообще стоит задумываться о запуске WPF в Docker, когда существуют современные кроссплатформенные фреймворки вроде Avalonia [1]? Честно не знаю, но вы же читаете эту статью? Значит вам оно нужно, мне оно тоже было нужно в качестве дополнительного задания, которое мне выдали в моем техникуме по дисциплине Docker. И мне было принципиально сделать его.
Просто написав запрос в поисковик: "Как запустить WPF в Docker" я столкнулся с тем, что многие источники категорично утверждали: «You cannot run a WPF application in docker [2]». StackOverflow пестрел ответами о невозможности такой задачи, YouTube-ролики [3] не предлагали рабочих решений, а попытки поиска на разных языках не приносили результата.
В своих поисках я наткнулся на образ dockur/windows [4], но требования к KVM и огромный размер образа делали это решение непрактичным. Прорыв произошел благодаря образу docker-wine [5] от Scotty Hardy. После многочисленных попыток, перезапусков контейнеров и анализа ошибок удалось добиться работоспособности как для .NET Framework (версии 4.7.2 и 4.8), так и для .NET Core.
Для воспроизведения этого эксперимента вам понадобится:
Docker Desktop — демон Docker для управления контейнерами
X-сервер (например, Xming [6]) — для отображения графического интерфейса приложения
Скомпилированное WPF-приложение с исполняемым .exe файлом
Dotnet - установленный dotnet на хост машине нужной версии (той же что и ваше приложение). Этот пункт нужен только если вы запускаете .NET Core.
Убедитесь, что ваше WPF-приложение скомпилировано и содержит исполняемый файл (например, WpfApp.exe)
Можете перейти в мой репозиторий [7]на GitHub, чтобы взять оттуда тестовые WPF приложения на Core и Framework.
Разместите ваше приложение в корневой директории проекта рядом с Dockerfile
Запустите Docker Desktop и X-сервер (Xming)
В зависимости от типа вашего приложения (.NET Framework или .NET Core) используйте соответствующие инструкции.
Начнем с .NET Framework'а, так как он проще. Я смог запустить двумя разными способами через образ scottyhardy/docker-wine [5] и через Alpine.
Начнем с образа scottyhardy/docker-wine [5]. Скачать Dockerfile и тестовое приложение Biorhythms можно в репозитории [7].
FROM scottyhardy/docker-wine
# Настраиваем переменную окружения DISPLAY для подключения к X-серверу хоста
ENV DISPLAY=host.docker.internal:0
# Копируем скомпилированное WPF-приложение из локальной директории в корень контейнера
#! Мое приложение - NET Framework 4.8
# Убедитесь, что вы указали правильный путь к вашему .exe файлу
COPY /Biorhythms/bin/Debug/Biorhythms.exe .
# Запускаем приложение через Wine при старте контейнера
CMD ["wine", "Biorhythms.exe"]
После этого можно сбилдить контейнер.
docker build -f Dockerfile.docker-wine -t wpf-app .
После этого через настроенный X-сервер, появится окно с Wine. Просто подождем.
После ожидания окно закроется и откроется новое, уже с нашим WPF приложением.
Рассмотрим второй способ через Alpine. Преимущество этого способа перед первым, в том, что он меньше по размеру. Скачать Dockerfile и тестовое приложение Biorhythms можно все так же в репозитории [7].
# Используем образ ориентированный на легковесность и нетребовательность к ресурсам
FROM alpine:latest
# Устанавливаем Wine
RUN apk add --no-cache wine
# Копируем скомпилированное WPF-приложение из локальной директории в папку /app
#! Мое приложение - NET Framework 4.8
# Убедитесь, что вы указали правильный путь к вашему .exe файлу
COPY /Biorhythms/bin/Debug/Biorhythms.exe ./app/Biorhythms.exe
# Настраиваем переменную окружения DISPLAY для подключения к X-серверу хоста
ENV DISPLAY=host.docker.internal:0
CMD ["wine", "/app/Biorhythms.exe"]
После этого можно сбилдить контейнер.
docker build -f Dockerfile.alpine -t wpf-app .
После запуска видим то же окно с Wine, которое обновляет конфигурацию. Отличие в том, что в данном образе по умолчанию не установлен Wine Mono, который нужен для запуска WPF. Следовательно соглашаемся на просьбу его установить и нажимаем кнопку Install.
Дожидаемся установки.
После этого окно закроется и откроется новое с нашим WPF приложением. Попробуем ввести дату моего рождения, чтобы проверить работоспособность.
Программа работает, можно идти дальше.
Перейдем к .NET Core, его запустить сложнее, потому что нам понадобится dotnet, при установке dotnet внутри контейнера в Linux скачивается версия именно для Linux, а нам нужна версия для Windows, поэтому мы будем копировать dotnet с хост машины, в контейнер в wine.
Скачать Dockerfile и тестовое приложение WPFCore можно в репозитории [7].
FROM alpine:latest
# Устанавливаем Wine
RUN apk add --no-cache wine
# Копируем скомпилированное WPF-приложение из локальной директории в папку /app
#! Мое приложение - NET Core 8
# Убедитесь, что вы указали правильный путь к вашему .exe файлу
COPY /WPFCore/bin/Debug/net8.0-windows ./app/
# Настраиваем переменную окружения DISPLAY для подключения к X-серверу хоста
ENV DISPLAY=host.docker.internal:0
Перейдем к запуску, тут он сложнее, чем в .NET Framework'е.
# Сначала сбилдим проект
docker build -f Dockerfile.alpine-core -t core-alpine .
# Запускаем контейнер в интерактивном режиме
docker run -it --rm --name core-alpine-container core-alpine /bin/sh
# Внутри контейнера инициализируем Wine в sh, который открылся у вас в терминале
winecfg
После этого запустится знакомое окно с установкой Wine Mono. Просто устанавливаем.
Откроем отдельный терминал и скопируем dotnet с хоста в контейнер.
#! Моя версия dotnet на хост машине - NET Core 8
docker cp "C:Program Filesdotnet" core-alpine-container:"/root/.wine/drive_c/Program Files/dotnet"
Откроется окно с Wine configuration, просто жмем OK и идем дальше.
Теперь ожидаем, когда появится надпись, что наш dotnet был успешно скопирован в контейнер.
Возвращаемся в терминал с контейнером и в sh запускаем следующую команду:
wine /app/WPFCore.exe
После этого у вас должен запустится WPF на .NET Core.
При работе с WPF в Wine через Docker следует учитывать следующие особенности:
Графический интерфейс может отображаться с задержками или некорректно
Ввод с клавиатуры и мыши может быть нестабильным. Рекомендуется использовать клавиши Tab и Enter для навигации по элементам интерфейса
Ограниченная поддержка функций — Wine не реализует все возможности WPF. Приложения с:
Сложной анимацией
Тяжелой 2D/3D графикой
Сторонними UI-библиотеками
Специфическими Windows API
скорее всего, не запустятся или будут работать с ошибками
Если ваше приложение не запускается или работает некорректно:
Используйте winetricks для установки дополнительных компонентов Windows, которые могут потребоваться вашему приложению
Проверяйте логи Wine для выявления отсутствующих DLL или COM-компонентов
Начинайте с простейшего WPF-приложения (одно окно с кнопкой) и постепенно усложняйте
Для .NET Core убедитесь, что версия .NET на хосте точно совпадает с требуемой версией приложения
Хотя эксперимент с Wine и Docker может быть интересен с технической точки зрения, для реальных проектов рекомендуется рассмотреть современные кроссплатформенные альтернативы:
Avalonia UI — мощный фреймворк для создания .NET-приложений с нативным интерфейсом на Windows, Linux и macOS
.NET MAUI — официальное решение Microsoft для кроссплатформенной разработки мобильных и десктоп-приложений
Как показала практика запуск WPF-приложений в Docker возможен, в этом нам помог Wine. Я же доволен, что смог противостоять фразам "это не возможно" и все же запустить в контейнере приложение. Однако не для учебных целей, кроме отдельных случаев такой подход вряд ли подойдет из-за множества ограничений и нестабильности.
Этот материал создан в первую очередь для образовательных целей, чтобы показать границы возможного и помочь разработчикам, столкнувшимся с похожими задачами. Если вам действительно нужно кроссплатформенное решение — обратите внимание на современные альтернативы. Надеюсь эта статья помогла вам в вашей проблеме или хотя бы была интересна. Буду рад почитать ваши комментарии.
Автор: Merrcurys
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/438635
Ссылки в тексте:
[1] Avalonia: https://avaloniaui.net
[2] You cannot run a WPF application in docker: https://stackoverflow.com/questions/44502886/dockerize-a-wpf-application-and-use-it
[3] YouTube-ролики: https://youtu.be/sK1bOnVpngM?si=Kv99GKn0fYIm_cWG&t=68
[4] dockur/windows: https://github.com/dockur/windows
[5] docker-wine: https://github.com/scottyhardy/docker-wine
[6] Xming: https://sourceforge.net/projects/xming
[7] репозиторий : https://github.com/Merrcurys/WPF-Docker-Example
[8] Источник: https://habr.com/ru/articles/975138/?utm_source=habrahabr&utm_medium=rss&utm_campaign=975138
Нажмите здесь для печати.