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

Хостинг dotnet и mono. Провайдеры

  1. Heroku - иностранный сервис с GitOps подходом. Достаточно запушить ваше NET приложение в репозиторий, и сервис развернет его автоматически. Но нужна иностранная карта и готовность платить от 5-7$ в месяц.

  1. Amvera Cloud - Российский сервис, можно оплачивать российской картой. По функционалу похож на Heroku, то есть поддерживает развертывание и обновление через push в привязанный Git-репозиторий. Есть нативная поддержка как C#, так и других окружений, достаточно в интерфейсе выбрать нужную конфигурацию. Стоимость начинается от 170 руб. в месяц и есть стартовый баланс для бесплатного начала использования.

  2. Clever Cloud - Французский аналог Heroku. Есть поддержка дотнет окружения.

Как развернуть на сервере .NET приложение на примере Телеграм-бота на C# c SQLite

В статье мы рассмотрим, как развернуть в облаке приложение на dotnet, на примере Telegram-бота со встраиваемой базой данных SQLite.

Код проекта под катом

Код приложения
using System;
using System.Data.SQLite;
using System.Threading;
using Telegram.Bot;
using Telegram.Bot.Args;
using Telegram.Bot.Types;


namespace TelegramBot
{
   class Program
   {
       private static SQLiteConnection sqliteConnection;
       private static TelegramBotClient botClient;


       static void Main(string[] args)
       {


           sqliteConnection = new SQLiteConnection("Data Source=/data/botdb.db;Version=3;");
           sqliteConnection.Open();


           string createTableQuery = @"CREATE TABLE IF NOT EXISTS Users (
                                           Id INTEGER PRIMARY KEY AUTOINCREMENT,
                                           Username TEXT NOT NULL UNIQUE,
                                           FirstName TEXT,
                                           LastName TEXT
                                       );";
           SQLiteCommand createTableCommand = new SQLiteCommand(createTableQuery, sqliteConnection);
           createTableCommand.ExecuteNonQuery();




           botClient = new TelegramBotClient("6495562833:AAEVRpqnrRPSA6pR85ghNsEyI_cta1D-RKk");
          
           botClient.OnMessage += Bot_OnMessage;
           botClient.StartReceiving();




           Console.WriteLine("Bot started, press CTRL+C to exit...");


           while (true)
           {
               Thread.Sleep(1000);
           }
       }


       private static async void Bot_OnMessage(object sender, Update update)
       {
           var message = update.Message;


           if (message.Text != null)
           {
               // Обработка команды /start
               if (message.Text.StartsWith("/start"))
               {
                   string[] userInfo = { message.Chat.Username, message.Chat.FirstName, message.Chat.LastName };
                   AddUserToDatabase(userInfo);
                   await botClient.SendTextMessageAsync(message.Chat.Id, "Привет! Я телеграм-бот на C#.");
               }
           }
       }


       private static void AddUserToDatabase(string[] userInfo)
       {
           string insertQuery = @"INSERT INTO Users (Username, FirstName, LastName) VALUES (@Username, @FirstName, @LastName);";
           SQLiteCommand insertCommand = new SQLiteCommand(insertQuery, sqliteConnection);
           insertCommand.Parameters.AddWithValue("@Username", userInfo[0]);
           insertCommand.Parameters.AddWithValue("@FirstName", userInfo[1]);
           insertCommand.Parameters.AddWithValue("@LastName", userInfo[2]);
           try
           {
               insertCommand.ExecuteNonQuery();
               Console.WriteLine("User added to database.");
           }
           catch (SQLiteException e)
           {
               Console.WriteLine("Error adding user to database: " + e.Message);
           }
       }
   }
}


Для начала нам понадобятся следующие инструменты:

·   Visual Studio: Интегрированная среда разработки (IDE) для языка C#, которая облегчит создание и отладку нашего бота.

·   Telegram.Bot Package: Библиотека для работы с Telegram API в среде .NET.

·   System.Data.SQLite Package: Библиотека для работы с базой данных SQLite в C Sharp.

Создаем новый проект в сервисе Amvera

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

Находясь на главной странице, нажимаем «Создать».

Вводим название проекта, выбираем тип сервиса "Приложение" и выбираем тариф.

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

Как выбрать тариф

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

Загрузка данных

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

  • Загрузка файлов через систему Git

Для этого перейдем в Visual Studio (или другой удобный для вас IDE) и зайдем в папку проекта, далее пишем в терминале.

Инициализируем репозиторий git:

git init

Добавим созданные нами файлы в индекс:

git add .

Зафиксируем изменения:

git commit “Описание сделанных вами изменений"

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

  • git remote add amvera {ваш url} - команду можно скопировать из интерфейса

Где {url} - это ваш url, по которому можно попасть в репозиторий.

И далее запушим наш проект в репозиторий Amvera, для этого в терминале пишем:

  • git push amvera master (необходимо выполнить после задания конфигурации).

Если вы выполнили все правильно, то в репозитории на сайте вы увидите ваши файлы проекта. Если вы перед этим создали конфигурацию в интерфейсе, выполните git push, так как создание конфигурации создает коммит в репозитории.

Загрузка через интерфейс

Для этого выбираем вкладку "Через интерфейс" и перетаскиваем файлы в зону.

Также добавим коммит, к примеру, "add files".

Задаем конфигурацию

Выбираем окружение csharp.

  • Как выбрать инструмент?

Если ваше приложение написано с использованием .NET Core или .NET 5+ и предназначено для платформ, поддерживаемых официальной реализацией .NET от Microsoft, то рекомендуется использовать dotnet для деплоя. Если же ваше приложение написано на .NET Framework и требует запуска на платформах, не поддерживаемых официальной реализацией .NET от Microsoft, то, возможно, будет разумно воспользоваться mono.

Для нашего случая нам больше подойдет dotnet.

После выбора инструмента мы видим несколько полей.

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

meta

Принимает только одно значение version .

Это версия .NET, который нужно использовать для сборки. Технически значение version подставляется в имя образа Docker, который будет использован.

build

Также принимает только одно значение image

Параметр image позволяет использовать другой образ для сборки, а не тот, который предлагается Amvera. Чтобы изменить образ, нужно, чтобы исходный код для сборки находился в папке /app (или образу без разницы, где будет находиться исходный код).

run

В секции могут быть использованы следующие параметры:

  • image

  • buildFileName

  • persistenceMount

  • containerPort

Параметр image позволяет использовать другой образ для сборки, а не тот, который предлагается Amvera. Образ должен удовлетворять следующим требованиям:

  • результат сборки ожидается в папке /app (или образу без разницы, где будет находиться результат сборки);

Параметр buildFileName - это название файла вашего проекта.

Если вы не знаете, откуда взять параметр buildFileName, введите у себя на компьютере следующую команду в папке с проектом: dotnet build. У вас появится папка bin/Debug/net*.0/${buildFileName}. Вам необходимо взять название файла .exe без расширения. Пример можно найти в минимальном файле amvera.yml

Параметр persistenceMount позволяет указать, в какую директорию будет примонтирована папка с постоянным хранилищем. По умолчанию имеет значение /data.

Параметр containerPort позволяет указать, какой порт слушает приложение. По умолчанию имеет значение 80.

Все значения, кроме buildFileName, мы оставим по умолчанию. В данное поле впишем название главного файла, в нашем случае это main.cs.

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

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

Или написать его вручную. Наш файл amvera.yml выглядит так:

meta:
 version: "8.0"
 environment: csharp
 toolchain: dotnet
build: {}
run:
 persistenceMount: /data
 containerPort: "80"
 buildFileName: program.cs

Если вы работаете через Git, скачайте получившийся файл конфигурации и выполните git push. Если вы создали его в интерфейсе, не забудьте сделать git pull, чтобы yaml файл оказался в вашем проекте. Если вы загружали все файлы через интерфейс, достаточно просто нажать кнопку “Завершить”.

Подключаем SQLite

Для этого перейдем в наше IDE и зайдем в файл проекта.

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

Изменим значение Data Source на /data/example.bd

После этого база данных будет сохраняться в /data. Сохранять SQLite необходимо именно в постоянное хранилище, так как в нем файлы не будут “обнуляться” до состояния коммита при пересборке.

После нам остается только собрать проект и запустить его.

Итог

Мы осуществили деплой .NET Telegram-бота с базой данных SQLite с использованием конфигурационного YAML-файла в облаке Amvera Cloud. Подключили SQLite и выполнили миграции. При регистрации в Amvera Cloud будет зачислено 111 руб, которых хватит на эксперименты и первое время работы проекта.

Комментарии (7)


  1. kirillkosolapov
    22.04.2024 10:27

    А если использовать PostgreSQL, то понадобится создавать отдельный проект, помимо проекта для .NET приложения?


    1. VadimMichaylov Автор
      22.04.2024 10:27

      В данном случае да. Если нужно захостить сервис с постгресом, понадобится еще один проект. Но обычно, если это как в примере бот, может хватить и SQLite. Это встраиваемая БД, для нее отдельный проект не нужен


  1. kirillkosolapov
    22.04.2024 10:27

    Тогда еще вопрос - эту же механику нельзя применить для деплоя на обычной VPS?


    1. VadimMichaylov Автор
      22.04.2024 10:27

      Нет, для обычной VPS не получится, только для GitOps сервисов типа Heroku. Но для VPS в интернете и так море инструкций на любой вкус


  1. GennPen
    22.04.2024 10:27
    +1

    и готовность платить от 5-7$ в месяц

    Стоимость начинается от 170 руб

    И это все с мизерными ресурсами по сравнению с VPS/VDS за ту же цену. Стоит ли это этих денег?


    1. VadimMichaylov Автор
      22.04.2024 10:27

      Но в VDS на вашем ресурсе еще ОС крутится. А тут это чисто под ваше приложение, поэтому реальная разница не такая большая. Плюс тут оплата идет именно за удобство обновлений. И по факту вопрос в том, сколько стоит ваше время и как часто вам нужно обновлять проект, если времени не очень жалко или вы накатываете обновления раз в год, можно сэкономить с VPS, если жалко, проще заплатить чуть дороже и обновлять одной командой в терминале


      1. GennPen
        22.04.2024 10:27
        +1

        Не буду спорить, но разница большая, даже если брать самые дешевые тарифы типа 1Гб оперативки и 10Гб диска. Основной упор это удобство деплоя, которым можно пренебречь если разворачиваете свои приложения "на попробовать".