Размещение .NET 6 WebAPI на Heroku с PostgreSQL, без контейнера

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

Вступление

В интернете не так много информации о том, как можно разместить приложение .NET на облачном сервисе Heroku, в том числе немного сказано о приложениях с БД. Как без мороки и элегантно разместить ваш .NET - проект? Узнаете в этой статье.

В этом руководстве я продемонстрирую на своём примере, как вы можете безболезненно разместить ваш проект. Надеюсь, кому-то пригодится. Обязательно просмотрите блок с дополнительной информацией.

Технологии

  • .NET 6 WebAPI

  • Heroku

  • Entity Framework Core 6

  • PostgreSQL

Heroku

Регистрируемся на сервисе Heroku. Трудностей быть не должно.

Регистрация в Heroku
Регистрация в Heroku
Создаём новое приложение и указываем его название.
Создаём новое приложение и указываем его название.
Выбираем метод расположения через Github
Выбираем метод расположения через Github

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

Устанавливаем соединение с github
Устанавливаем соединение с github
Выбираем ветвь репозитория
Выбираем ветвь репозитория

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

Переходим во вкладку Settings и в пункте Buildpacks добавляем ссылку на "сборочный пакет" .NET 6.

Buildpacks
Buildpacks

https://github.com/jincod/dotnetcore-buildpack

Осталось следующее: установить аддон Heroku Postgres с помощью Configure Add-ons во вкладке Overview:

Postgres add-on
Postgres add-on

Кликаем по аддону и переходим во вкладку Settings >> View Credentials, где находятся данные о нашей БД. Они нам понадобятся.

Database Credentials
Database Credentials

Конфигурационные файлы

Переходим во вкладку Settings >> Config Vars и добавим конфигурационный файл под именем "ASPNETCORE_ENVIRONMENT". Это файл ключ-значение в котором будет удобно конфигурировать нашу рабочую среду между Development / Production значениями.

Config Vars
Config Vars

Также здесь можно заметить такой файл как "DATABASE_URL". Это строка подключения к БД, предоставленная аддоном Heroku. Мы её будем использовать

Наш проект практически готов к публикации. Осталось его настроить.

Настройка проекта

Сразу скажу, что структура проекта, безусловно, может у каждого отличаться, но алгоритм действий будет одинаков при любом раскладе. Я продемонстрирую CRUD-проект. Условимся на том, что у вас объявлены соответствующие классы и сущности и осталось только настроить слой базы данных. Кратко ознакомимся.

Тема проекта: книжный магазин.

Приложение разделено на слои:

  • Domain (сущности)

  • Application (бизнес-логика)

  • Persistence (слой доступа к данным)

  • Presentation (web api)

Структура проекта
Структура проекта

 Убедимся, что в сборке со слоем БД установлены все необходимые NuGet пакеты:

Пакеты NuGet
Пакеты NuGet

Если вы все делаете в одной сборке WebApi, этих пакетов будет достаточно.

Настройка контекста базы данных

Создадим интерфейс, который будет реализован контекстом BookStoreDbContext:

public interface IBookStoreDbContext
    {
        DbSet<Book> Books { get; set; }
        Task<int> SaveChangesAsync(CancellationToken cancellationToken);
    }

Объявим необходимые таблицы и вызываем базовый конструктор. В этом же классе можно переопределить protected метод OnModelCreating(), чтобы добавить начальные данные в таблицу, но это уже за рамками статьи.

    public class BookStoreDbContext : DbContext, IBookStoreDbContext
    {
        public DbSet<Book> Books { get; set; }
        public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options)
            : base(options) { }
    }

Создадим класс DbInitializer, который будет использоваться при старте приложения и будет проверять, создана ли наша БД, и если нет, то создаст на основе нашего контекста. Также важно вызвать метод Migrate() нашей БД, чтобы миграция накатывалась програмным способом и сервер Heroku смог её вызвать:

    public class DbInitializer
    {
        public static void Initialize(BookStoreDbContext context)
        {
            context.Database.EnsureCreated();
            context.Database.Migrate();
        }
    }

Переходим в файл конфигурации приложения appsettings.json, где укажем строку подключения DbConnectionнашей локальной БД.

Вместо # - укажите ваши данные:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "DbConnection": "Host=localhost;Database=#;Username=#;"
  },
  "AllowedHosts": "*"
}

Внедрение зависимостей

Добавим класс DependencyInjection для нашего контекста. В нем мы внедрим наш контекст базы данных.

Создадим метод GetConnectionString(), который получит данные о строке подключения из конфигурационного файла Heroku "DATABASE_URL".

Если в конфигурационном файле указана среда "Development" (разработка), то мы используем нашу локальную строку подключения к БД в файле asppsettings.json с её строкой подключения.

Подключим PostgreSql.

    public static class DependencyInjection
    {
        public static IServiceCollection AddPersistence(
            this IServiceCollection services,
            IConfiguration configuration)
        {
            var connectionString = string.Empty;
          /* Проверим, в какой мы среде*/
            if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
            {
                connectionString = configuration["DbConnection"];
            }
            else
            {
                connectionString = GetConnectionString();
            }

            services.AddDbContext<BookStoreDbContext>(options =>
            {
              /* Подключаем PostgreSQL */
                options.UseNpgsql(connectionString);
            });
            services.AddScoped<IBookStoreDbContext>(provider =>
                provider.GetService<BookStoreDbContext>());

            return services;
        }

        public static string GetConnectionString()
        {
             /* Используем строку подключения из конфигурацинного файла, обеспеченного Heroku*/
            var connectionUrl = Environment.GetEnvironmentVariable("DATABASE_URL");

            connectionUrl = connectionUrl.Replace("postgres://", string.Empty);
            var userPassSide = connectionUrl.Split("@")[0];
            var hostSide = connectionUrl.Split("@")[1];

            var user = userPassSide.Split(":")[0];
            var password = userPassSide.Split(":")[1];
            var host = hostSide.Split("/")[0];
            var database = hostSide.Split("/")[1].Split("?")[0];

            return $"Host={host};Database={database};Username={user};Password={password};SSL Mode=Require;Trust Server Certificate=true";
        }

В файле Program.cs нашего WebAPI внедрим контекст БД и вызовем необходимый метод Initialize():

using (var scope = app.Services.CreateScope())
{
    try
    {
        var context = scope.ServiceProvider.GetRequiredService<BookStoreDbContext>();
        DbInitializer.Initialize(context);
    }
    catch (Exception)
    {
    }
}

Добавим миграцию в проект с помощью команды add-migration Init:

Package Manager Console
Package Manager Console

Деплоим проект!

Вернёмся в Heroku и нажмём заветную кнопку Deploy Branch:

Manual Deploy
Manual Deploy

Заключение

Поздравляю! Можно переходить на сайт. Вы можете наблюдать за состоянием сборки вашего приложения во вкладке Activity.

В моём случае это получение информации о книгах.

API response
API response

Я надеюсь, что изложил максимально просто и понятно. Если исключить БД, то всего лишь необходимо подключить .NET buildpack и деплоить проект. Проблем быть не должно.

Всех благ!

Дополнительная информация

Heroku:

https://dashboard.heroku.com/

Ролик, который вдохновил меня на написание статьи:

https://www.youtube.com/watch?v=BqI1hu0gIb0&ab_channel=CoderFoundry

Аналогичная статья с размещением API вместе с Docker:

https://www.c-sharpcorner.com/article/deploy-a-net-api-to-heroku-through-github-actions/

Создание контекста БД и подключение PostgreSQL с помощью Entity Framework Core:

https://www.npgsql.org/efcore/

На всякий случай добавлю .NET Buildpack для размещения вашего приложения:

https://github.com/jincod/dotnetcore-buildpack

Более подробное описание добавления Entity Framework Core в проект:

https://www.youtube.com/watch?v=wkF3csnu2hE&list=PLEtg-LdqEKXbpq4RtUp1hxZ6ByGjnvQs4&index=3&ab_channel=PlatinumDEV

Источник: https://habr.com/ru/post/695234/


Интересные статьи

Интересные статьи

Проблемы с производительностью, такие как аномально низкая скорость работы и высокое потребление памяти, могут быть обнаружены самыми разными способами. Такие недостатки ...
Релиз .NET Core 3.1 — хороший повод мигрировать свой проект с Framework на Core. Во-первых, это отполированная версия с долгосрочной поддержкой (LTS), т.е. её можно смело использовать в продакш...
Возможность интеграции с «1С» — это ключевое преимущество «1С-Битрикс» для всех, кто профессионально занимается продажами в интернете, особенно для масштабных интернет-магазинов.
Пользовательские интерфейсы современных прикладных приложений, как правило, сложны — зачастую необходимо реализовывать поддержку постраничной навигации, обрабатывать разного рода поля ввода, ...
С версии 12.0 в Bitrix Framework доступно создание резервных копий в автоматическом режиме. Задание параметров автоматического резервного копирования производится в Административной части на странице ...