Интеграция ngrok в запуск ASP.NET Core и автоматическое обновление URL-адресов веб-крюков

Эта статья была написана для компании Twilio и первоначально опубликована в блоге Twilio.

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

Webhooks — это способ получения уведомления от внешней службы о наступлении события. Вместо того чтобы вы отправляли HTTP-запрос в эту службу, служба отправляет HTTP-запрос в вашу публичную веб-службу.

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

К счастью, вы можете избежать повторяющейся работы, автоматизировав ее! В этом руководстве вы узнаете, как автоматически запускать ngrok при запуске приложения ASP.NET Core. Затем вы узнаете, как получить произвольный URL ngrok и использовать его для автоматической настройки веб-крючков Twilio.

Предварительные условия

Вам понадобятся следующие элементы:

  • ОС с поддержкой .NET (Windows/macOS/Linux)
  • .NET 6 SDK
  • Редактор кода или IDE (рекомендуется VS Code с плагином C#, Visual Studio или JetBrains Rider).
  • Ngrok CLI
  • Бесплатная учетная запись Ngrok (необязательно)
  • Бесплатный аккаунт Twilio (если вы зарегистрируетесь здесь, то получите $10 в кредит Twilio при переходе на платный аккаунт!)

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

Создание веб-проекта ASP.NET Core

Откройте предпочитаемую оболочку и с помощью команд ниже создайте новую папку с именем NgrokAspNet и перейдите в нее:

mkdir NgrokAspNet
cd NgrokAspNet
Войти в полноэкранный режим Выйти из полноэкранного режима

С помощью .NET CLI создайте новый пустой веб-проект:

dotnet new web
Войти в полноэкранный режим Выйти из полноэкранного режима

Ваш новый проект содержит один файл C# с именем Program.cs:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();
Войти в полноэкранный режим Выйти из полноэкранного режима

Программа создает новое веб-приложение с одной конечной точкой, отвечающей на «Hello World». Вернитесь в оболочку и запустите проект с помощью .NET CLI:

dotnet run
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Building...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7121
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5033
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/nswimberghe/NgrokAspNet/
Войти в полноэкранный режим Выход из полноэкранного режима

Обратите внимание на два URL-адреса localhost, которые были выбраны при создании веб-проекта.

Выберите один из URL и откройте его в веб-браузере. В браузере должно появиться сообщение «Hello World!».

Оставьте проект .NET запущенным и откройте новую оболочку, чтобы выполнить следующие команды!

Используйте ngrok для туннелирования локального веб-сервера в Интернет

Вы можете запустить инструмент ngrok CLI на своей машине для туннелирования локального URL в публичный URL, похожий на https://66a605a7ced5.ngrok.io, с другим поддоменом. Каждый раз, когда вы запускаете новый туннель с помощью ngrok, поддомен будет другим.

В новой оболочке выполните следующую команду:

ngrok http [YOUR_HTTP_SERVER_URL]
Войти в полноэкранный режим Выйти из полноэкранного режима

Замените [YOUR_HTTP_SERVER_URL] на URL веб-сервера, начинающийся с http://localhost.

Это запустит новый туннель к новому публичному URL, который вы сможете найти в отображаемом выводе:

Переключитесь обратно на веб-браузер и перейдите к одному из URL Forwarding, перечисленных в вашей оболочке. Некоторые браузеры могут предупредить вас о том, что это обманчивый сайт, на что в данном случае можно не обращать внимания. Браузер должен снова выдать «Hello World», но на этот раз через публичный URL. Это означает, что вы можете поделиться этим URL с кем угодно, и они также смогут общаться с вашим локальным веб-сервером. Это также означает, что веб-крючки смогут связаться с вашим локальным сервером.

Вы также можете туннелировать HTTPS URL, но для этого вам необходимо зарегистрироваться в ngrok (бесплатно) и аутентифицировать ваш инструмент ngrok CLI. После этого вы также можете запустить команду ngrok http с URL, начинающимся с https://localhost.

Помимо URL переадресации, также отображается URL веб-интерфейса. Это место, где вы можете получить доступ к локальной приборной панели и API ngrok. Переключитесь обратно в браузер и перейдите по адресу http://localhost:4040. Здесь вы снова найдете URL переадресации, а также журнал всех HTTP-запросов, проходящих через туннель.

Остановите процесс ngrok, нажав ctrl + c, и закройте этот экземпляр оболочки. Переключитесь на другую оболочку и остановите проект .NET, нажав ctrl + c.

Автоматический запуск ngrok при запуске ASP.NET Core

Вы смогли публично обслужить свое веб-приложение, запустив проект ASP.NET, а затем запустив ngrok в отдельной оболочке. Этот рабочий процесс можно оптимизировать, интегрировав ngrok в процесс запуска вашего проекта ASP.NET.

Чтобы запустить туннель ngrok программно, вам нужно будет выполнить команду ngrok CLI из кода. Вы можете использовать API Process .NET, но существует библиотека с открытым исходным кодом, которая упрощает взаимодействие с инструментами и процессами CLI: CliWrap.

Добавьте пакет CliWrap NuGet с помощью .NET CLI:

dotnet add package CliWrap
Вход в полноэкранный режим Выйти из полноэкранного режима

На момент написания этой статьи пакет CliWrap NuGet имеет версию 3.4.0.

Создайте новый файл C# в каталоге проекта NgrokAspNet с именем TunnelService.cs и добавьте следующий код:

using System.Text.Json.Nodes;
using CliWrap;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;

namespace NgrokAspNet;

public class TunnelService : BackgroundService
{
    private readonly IServer server;
    private readonly IHostApplicationLifetime hostApplicationLifetime;
    private readonly IConfiguration config;
    private readonly ILogger<TunnelService> logger;

    public TunnelService(
        IServer server,
        IHostApplicationLifetime hostApplicationLifetime,
        IConfiguration config,
        ILogger<TunnelService> logger
    )
    {
        this.server = server;
        this.hostApplicationLifetime = hostApplicationLifetime;
        this.config = config;
        this.logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await WaitForApplicationStarted();

        var urls = server.Features.Get<IServerAddressesFeature>()!.Addresses;
        // Use https:// if you authenticated ngrok, otherwise, you can only use http://
        var localUrl = urls.Single(u => u.StartsWith("http://"));

        logger.LogInformation("Starting ngrok tunnel for {LocalUrl}", localUrl);
        var ngrokTask = StartNgrokTunnel(localUrl, stoppingToken);

        var publicUrl = await GetNgrokPublicUrl();
        logger.LogInformation("Public ngrok URL: {NgrokPublicUrl}", publicUrl);

        await ngrokTask;

        logger.LogInformation("Ngrok tunnel stopped");
    }

    private Task WaitForApplicationStarted()
    {
        var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        hostApplicationLifetime.ApplicationStarted.Register(() => completionSource.TrySetResult());
        return completionSource.Task;
    }

    private CommandTask<CommandResult> StartNgrokTunnel(string localUrl, CancellationToken stoppingToken)
    {
        var ngrokTask = Cli.Wrap("ngrok")
            .WithArguments(args => args
                .Add("http")
                .Add(localUrl)
                .Add("--log")
                .Add("stdout"))
            .WithStandardOutputPipe(PipeTarget.ToDelegate(s => logger.LogDebug(s)))
            .WithStandardErrorPipe(PipeTarget.ToDelegate(s => logger.LogError(s)))
            .ExecuteAsync(stoppingToken);
        return ngrokTask;
    }

    private async Task<string> GetNgrokPublicUrl()
    {
        using var httpClient = new HttpClient();
        for (var ngrokRetryCount = 0; ngrokRetryCount < 10; ngrokRetryCount++)
        {
            logger.LogDebug("Get ngrok tunnels attempt: {RetryCount}", ngrokRetryCount + 1);

            try
            {
                var json = await httpClient.GetFromJsonAsync<JsonNode>("http://127.0.0.1:4040/api/tunnels");
                var publicUrl = json["tunnels"].AsArray()
                    .Select(e => e["public_url"].GetValue<string>())
                    .SingleOrDefault(u => u.StartsWith("https://"));
                if (!string.IsNullOrEmpty(publicUrl)) return publicUrl;
            }
            catch
            {
                // ignored
            }

            await Task.Delay(200);
        }

        throw new Exception("Ngrok dashboard did not start in 10 tries");
    }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Класс TunnelService будет отвечать за запуск туннеля с помощью ngrok CLI, а позже он также настроит веб-крючки Twilio.

Это очень много кода, поэтому давайте разберем его по частям.

    public TunnelService(
        IServer server,
        IHostApplicationLifetime hostApplicationLifetime,
        IConfiguration config,
        ILogger<TunnelService> logger
    )
    {
        this.server = server;
        this.hostApplicationLifetime = hostApplicationLifetime;
        this.config = config;
        this.logger = logger;
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Конструктор принимает несколько параметров, которые будут предоставлены контейнером инъекции зависимостей, встроенным в ASP.NET Core. Все параметры хранятся в приватных полях, поэтому они доступны во всем классе.

  • Параметр server содержит информацию о запущенном веб-сервере. После запуска веб-сервера вы можете получить локальные URL из поля server.
  • Параметр hostApplicationLifetime позволяет подключиться к различным событиям жизненного цикла (запущен/остановлен/остановлен). Параметр config будет содержать всю конфигурацию, переданную в приложение .NET через аргументы командной строки, переменные окружения, JSON-файлы, пользовательские секреты и т. д. Сейчас config не используется, но он будет использован в одном из следующих разделов.
  • Параметр logger будет использоваться для записи в журнал любой информации, относящейся к запуску туннеля.
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await WaitForApplicationStarted();

        var urls = server.Features.Get<IServerAddressesFeature>()!.Addresses;
        // Use https:// if you authenticated ngrok, otherwise, you can only use http://
        var localUrl = urls.Single(u => u.StartsWith("http://"));

        logger.LogInformation("Starting ngrok tunnel for {LocalUrl}", localUrl);
        var ngrokTask = StartNgrokTunnel(localUrl, stoppingToken);

        var publicUrl = await GetNgrokPublicUrl();
        logger.LogInformation("Public ngrok URL: {NgrokPublicUrl}", publicUrl);

        await ngrokTask;

        logger.LogInformation("Ngrok tunnel stopped");
    }
Войти в полноэкранный режим Выйти из полноэкранного режима

TunnelService наследуется от абстрактного класса BackgroundService, поэтому вам необходимо реализовать абстрактный метод ExecuteAsync. ExecuteAsync является основным методом этого класса и будет вызываться при запуске веб-приложения. ExecuteAsync будет ждать запуска веб-приложения с помощью WaitForApplicationStarted, а затем возьмет локальные URL. Из локальных URL будет взят один URL. Если вы аутентифицировали ngrok ранее, вы можете использовать HTTPS URL вместо HTTP URL, заменив "http://" на "https://".

Далее будет запущен туннель ngrok, затем будет получен публичный URL ngrok, и, наконец, ожидается Task для запуска ngrok CLI. Когда веб-приложение остановится, процесс ngrok также будет остановлен, что приведет к завершению ngrokTask.

    private Task WaitForApplicationStarted()
    {
        var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
        hostApplicationLifetime.ApplicationStarted.Register(() => completionSource.TrySetResult());
        return completionSource.Task;
    }
Вход в полноэкранный режим Выход из полноэкранного режима

WaitForApplicationStarted создаст ожидающую Task, которая будет завершена при срабатывании события ApplicationStarted. Странно, но события жизненного цикла на IHostApplicationLifetime не используют делегаты или события C#, вместо этого они представляют собой CancellationToken.

Вы можете передать лямбду или делегат в метод CancellationToken.Register, который будет вызван, когда CancellationToken будет отменен. В случае токена отмены, хранящегося в свойстве IHostApplicationLifetime.ApplicationStarted, когда токен отменяется, это означает, что приложение запущено. Как (не)интуитивно, я прав?

Чтобы сделать это более интуитивным в использовании, вы можете создать TaskCompletionSource и установить его результат в обратный вызов hostApplicationLifetime.ApplicationStarted.Register. Это установит Task как завершенную, что в данном случае будет означать запуск приложения.

Если все это немного запутано, важно понять, что await WaitForApplicationStarted() будет ждать запуска веб-приложения.

    private CommandTask<CommandResult> StartNgrokTunnel(string localUrl, CancellationToken stoppingToken)
    {
        var ngrokTask = Cli.Wrap("ngrok")
            .WithArguments(args => args
                .Add("http")
                .Add(localUrl)
                .Add("--log")
                .Add("stdout"))
            .WithStandardOutputPipe(PipeTarget.ToDelegate(s => logger.LogDebug(s)))
            .WithStandardErrorPipe(PipeTarget.ToDelegate(s => logger.LogError(s)))
            .ExecuteAsync(stoppingToken);
        return ngrokTask;
    }
Вход в полноэкранный режим Выход из полноэкранного режима

StartNgrokTunnel будет использовать библиотеку CliWrap для запуска ngrok CLI. Результирующая команда будет выглядеть следующим образом:

ngrok http [YOUR_LOCAL_SERVER_URL] --log stdout
Войти в полноэкранный режим Выйти из полноэкранного режима

Эта команда запустит туннель ngrok, как и раньше, но с добавлением аргумента --log stdout. Этот аргумент log указывает ngrok вести журнал на стандартный вывод, который затем может быть захвачен через WithStandardOutputPipe. Стандартный вывод и вывод ошибок будут переданы в logger.

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

    private async Task<string> GetNgrokPublicUrl()
    {
        using var httpClient = new HttpClient();
        for (var ngrokRetryCount = 0; ngrokRetryCount < 10; ngrokRetryCount++)
        {
            logger.LogDebug("Get ngrok tunnels attempt: {RetryCount}", ngrokRetryCount + 1);

            try
            {
                var json = await httpClient.GetFromJsonAsync<JsonNode>("http://127.0.0.1:4040/api/tunnels");
                var publicUrl = json["tunnels"].AsArray()
                    .Select(e => e["public_url"].GetValue<string>())
                    .SingleOrDefault(u => u.StartsWith("https://"));
                if (!string.IsNullOrEmpty(publicUrl)) return publicUrl;
            }
            catch
            {
                // ignored
            }

            await Task.Delay(200);
        }

        throw new Exception("Ngrok dashboard did not start in 10 tries");
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Функция GetNgrokPublicUrl получает публичный HTTPS URL и возвращает его. Вы можете получить публичный URL туннеля, запросив его из локального API ngrok по адресу http://127.0.0.1:4040/api/tunnels.

К сожалению, когда ngrok CLI запущен, это еще не означает, что туннель готов. Вот почему этот код окружен циклом, который будет пытаться получить публичный URL до 10 раз, каждые 200 миллисекунд. Не стесняйтесь изменять задержку в 200 мс и retryCount так, как вам удобно.

Класс TunnelService завершен, но вам еще нужно настроить веб-приложение для его работы в фоновом режиме. Обновите файл Program.cs, руководствуясь выделенными строками ниже:

var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment()) 
    builder.Services.AddHostedService<NgrokAspNet.TunnelService>();
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Не имеет смысла запускать его в staging или production, и, скорее всего, он вызовет проблемы, если будет запущен. Вместо того чтобы запускать это только в среде разработки, вы также можете добавить более явный элемент конфигурации, но это уже на ваше усмотрение!

Вот и все! Запустите приложение с помощью .NET CLI и посмотрите на результат:

dotnet run
Вход в полноэкранный режим Выход из полноэкранного режима

Публичный ngrok URL будет записан в выходной файл следующим образом: «Публичный ngrok URL: https://6797-72-66-29-154.ngrok.io». Возьмите публичный ngrok URL и перейдите на него в браузере. Вы снова увидите «Hello World!».

Автоматическое обновление Twilio Webhooks с помощью ngrok URLs

Начните работу с Twilio

Если вы еще этого не сделали, вам нужно будет настроить следующие параметры Twilio:

  • Приобретите новый телефонный номер у Twilio. Стоимость телефонного номера будет применена к вашему бесплатному рекламному кредиту. Обязательно запишите ваш новый телефонный номер Twilio. Он понадобится вам позже!
  • Если вы используете пробную учетную запись Twilio, вы можете отправлять текстовые сообщения только на проверенные идентификаторы абонентов. Проверьте свой номер телефона или номер телефона, на который вы хотите отправить SMS, если его нет в списке проверенных идентификаторов абонентов.
  • Наконец, вам нужно найти SID вашего аккаунта Twilio и Auth Token. Перейдите на страницу вашего аккаунта Twilio и обратите внимание на SID вашего аккаунта Twilio и Auth Token, расположенные в левой нижней части страницы.

Обновление веб-крючков Twilio Phone Number Webhooks

Twilio SDK для C# и .NET поможет вам взаимодействовать с API Twilio и отвечать на веб-крючки. Добавьте пакет Twilio NuGet в свой проект:

dotnet add package twilio
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Вернитесь в редактор кода и откройте файл TunnelService.cs. Обновите утверждения using в верхней части файла, чтобы включить эти три новые ссылки Twilio:

using System.Text.Json.Nodes;
using CliWrap;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Twilio.Clients;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
Войти в полноэкранный режим Выход из полноэкранного режима

Обновите метод ExecuteAsync, чтобы вызвать асинхронный метод ConfigureTwilioWebhook после регистрации публичного URL ngrok:

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await WaitForApplicationStarted();

        var urls = server.Features.Get<IServerAddressesFeature>()!.Addresses;
        // Use https:// if you authenticated ngrok, otherwise, you can only use http://
        var localUrl = urls.Single(u => u.StartsWith("http://"));

        logger.LogInformation("Starting ngrok tunnel for {LocalUrl}", localUrl);
        var ngrokTask = StartNgrokTunnel(localUrl, stoppingToken);

        var publicUrl = await GetNgrokPublicUrl();
        logger.LogInformation("Public ngrok URL: {NgrokPublicUrl}", publicUrl);

        await ConfigureTwilioWebhook(publicUrl);

        await ngrokTask;

        logger.LogInformation("Ngrok tunnel stopped");
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Добавьте асинхронный метод ConfigureTwilioWebhook после метода GetNgrokPublicUrl:

    private async Task ConfigureTwilioWebhook(string publicUrl)
    {
        var twilioClient = new TwilioRestClient(config["TwilioAccountSid"], config["TwilioAuthToken"]);
        var phoneNumber = (await IncomingPhoneNumberResource.ReadAsync(
            phoneNumber: new PhoneNumber(config["TwilioPhoneNumber"]),
            limit: 1,
            client: twilioClient
        )).Single();
        phoneNumber = await IncomingPhoneNumberResource.UpdateAsync(
            phoneNumber.Sid,
            voiceUrl: new Uri($"{publicUrl}/voice"), voiceMethod: Twilio.Http.HttpMethod.Post,
            smsUrl: new Uri($"{publicUrl}/message"), smsMethod: Twilio.Http.HttpMethod.Post,
            client: twilioClient
        );
        logger.LogInformation(
            "Twilio Phone Number {TwilioPhoneNumber} Voice URL updated to {TwilioVoiceUrl}",
            phoneNumber.PhoneNumber,
            phoneNumber.VoiceUrl
        );
        logger.LogInformation(
            "Twilio Phone Number {TwilioPhoneNumber} Message URL updated to {TwilioMessageUrl}",
            phoneNumber.PhoneNumber,
            phoneNumber.SmsUrl
        );
    }
Вход в полноэкранный режим Выход из полноэкранного режима

Метод ConfigureTwilioWebhook получает публичный ngrok URL в качестве параметра. SID аккаунта и Auth Token извлекаются из поля config и передаются в конструктор TwilioRestClient.

Вы можете использовать API-ключи для аутентификации вместо использования SID учетной записи и Auth Token. API-ключи имеют меньше прав доступа и могут быть легче отозваны, что делает их более безопасным вариантом.

Данные телефонного номера Twilio запрашиваются с помощью TwilioRestClient, а затем данные телефонного номера используются для обновления URL голосового webhook и URL SMS webhook. URL голосового и SMS вебхуков будут установлены в публичный URL туннеля с приставкой /voice и /message соответственно_._

Теперь проект зависит от конфигурационного элемента TwilioAccountSid, TwilioAuthToken и TwilioPhoneNumber, но они еще не настроены. Вы можете использовать секреты пользователей .NET для настройки этих типов чувствительной конфигурации.

Инициализируйте пользовательские секреты для своего проекта с помощью .NET CLI:

dotnet user-secrets init
Вход в полноэкранный режим Выход из полноэкранного режима

Выполните следующую команду для настройки секретов:

dotnet user-secrets set TwilioAccountSid [YOUR ACCOUNT SID]
dotnet user-secrets set TwilioAuthToken [YOUR AUTH TOKEN]
dotnet user-secrets set TwilioPhoneNumber [YOUR TWILIO PHONE NUMBER]
Войти в полноэкранный режим Выйти из полноэкранного режима

Замените [YOUR ACCOUNT SID] на SID вашего аккаунта Twilio, [YOUR AUTH TOKEN] на ваш Twilio Auth Token, и [YOUR TWILIO PHONE NUMBER] на ваш Twilio Phone Number.

Протестируйте свою работу, запустив приложение:

dotnet run
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Вы должны увидеть дополнительный вывод, который выглядит следующим образом: «Twilio Phone Number +1234567890 Voice URL updated to https://5fb3-72-66-29-154.ngrok.io/voice» и «Twilio Phone Number +1234567890 Message URL updated to https://5fb3-72-66-29-154.ngrok.io/message».

Ответ на веб-крючки Twilio

После установки URL веб-крючков Twilio будет отправлять HTTP-запросы на ваши публичные URL всякий раз, когда на ваш номер телефона Twilio поступает звонок или SMS.

Вам необходимо принять эти HTTP-запросы для /voice и /message, а затем ответить на них инструкциями TwiML. Обновите Program.cs на основе выделенных строк в приведенном ниже коде:

using Twilio.TwiML;

var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment()) 
    builder.Services.AddHostedService<NgrokAspNet.TunnelService>();
var app = builder.Build();

app.MapGet("/", () => "Hello World!");
app.MapPost("/voice", () =>
{
    var response = new VoiceResponse();
    response.Say("Hello World!");
    return Results.Text(response.ToString(), "application/xml");
});
app.MapPost("/message", () =>
{
    var response = new MessagingResponse();
    response.Message("Hello World!");
    return Results.Text(response.ToString(), "application/xml");
});

app.Run();
Вход в полноэкранный режим Выйти из полноэкранного режима

Когда Twilio отправит HTTP POST запрос на /voice, конечная точка ответит следующим TwiML:

<?xml version="1.0" encoding="utf-8"?>
<Response>
  <Say>Hello World!</Say>
</Response>
Вход в полноэкранный режим Выйти из полноэкранного режима

В результате Twilio расшифрует «Hello World!» на аудио и передаст его звонящему.

Когда Twilio отправит HTTP POST запрос на /message, конечная точка ответит следующим TwiML:

<?xml version="1.0" encoding="utf-8"?>
<Response>
  <Message>Hello World!</Message>
</Response>
Войти в полноэкранный режим Выйти из полноэкранного режима

В результате Twilio ответит текстовым сообщением со словами «Hello World!».

Тестирование веб-крючков Twilio

Если все прошло успешно, теперь вы можете разрабатывать и тестировать webhooks, выполнив одну команду dotnet run. Запустите приложение с помощью .NET CLI:

dotnet run
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Дождитесь обновления URL-адресов веб-крючков, а затем позвоните и/или отправьте сообщение на ваш номер телефона Twilio.

Если вы позвоните, вы должны услышать «Hello World!», а если отправите СМС, то получите текстовое сообщение с текстом «Hello World!».

Как интегрировать ngrok в ASP.NET и автоматически обновлять веб-крючки

В этом руководстве вы узнали, как упростить процесс разработки webhook, интегрировав ngrok в стартап ASP.NET Core и автоматически обновляя webhooks, с помощью следующих шагов:

  1. Получите локальные URL-адреса ASP.NET
  2. Используйте BackgroundService для запуска туннеля ngrok
  3. Получите URL пересылки ngrok из локального API ngrok.
  4. Обновляйте URL ваших веб-крюков, используя URL переадресации ngrok.

У Twilio есть много других продуктов, которые вы можете интегрировать в свои приложения. Посмотрите это руководство о том, как совершать телефонные звонки из Blazor WebAssembly с помощью Twilio Voice и Twilio Client.

Дополнительные ресурсы

Ознакомьтесь со следующими ресурсами для получения дополнительной информации по темам и инструментам, представленным в этом руководстве:

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

TwiML для программируемых SMS — Узнайте больше о TwiML и о том, как вы можете использовать TwiML для ответа на текстовые сообщения.

Исходный код этого руководства на GitHub — Используйте этот исходный код, если у вас возникнут какие-либо проблемы, или отправьте проблему на этом репозитории GitHub, если у вас возникнут проблемы.

Нильс Свимберге — бельгийско-американский инженер-программист и создатель технического контента в компании Twilio. Общайтесь с Нильсом в Twitter @RealSwimburger и следите за личным блогом Нильса о .NET, Azure и веб-разработке на сайте swimburger.net.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *