Начало работы с гибридными подключениями Azure Relay с использованием WebSocket и .NET
В этом кратком руководстве описано, как создать приложения .NET, которые отправляют и получают сообщения с использованием гибридных подключений по протоколу WebSocket в Azure Relay. См. дополнительные сведения о службе Azure Relay.
При работе с этим кратким руководством вы выполните следующие задачи:
- Создайте пространство имен ретранслятора с помощью портала Azure.
- Создайте гибридное подключение в этом пространстве имен с помощью портала Azure.
- Создайте серверное консольное приложение (прослушиватель) для получения сообщений.
- Создайте клиентское консольное приложение (отправитель) для отправки сообщений.
- Запустите приложения.
Необходимые компоненты
Для работы с данным руководством вам потребуется:
- Visual Studio 2015 или более поздней версии. В описанных в этом руководстве примерах используется Visual Studio 2017.
- Подписка Azure. Если у вас еще нет подписки Azure, создайте бесплатную учетную запись, прежде чем начать работу.
Создание пространства имен
Войдите на портал Azure.
В меню слева выберите Все службы. Выберите "Интеграция", найдите ретрансляторы, переместите указатель мыши на ретрансляторы и нажмите кнопку "Создать".
На странице "Создание пространства имен" выполните следующие действия.
Выберите подписку Azure, в которой будет создано пространство имен.
Выберите существующую группу ресурсов, в которую будет размещено это пространство имен, или создайте новую.
Введите имя пространства имен Ретранслятора.
Выберите регион, в котором должно размещаться пространство имен.
В нижней части страницы выберите Review + create (Проверить и создать).
На странице Отзыв и создание выберите Создать.
Через несколько минут вы увидите страницу Ретранслятора для пространства имен.
Получение учетных данных управления
На странице "Ретранслятор" выберите политики общего доступа в меню слева. `
На странице Политики общего доступа щелкните RootManageSharedAccessKey.
В разделе SAS Policy: RootManageSharedAccessKey (Политика SAS: RootManageSharedAccessKey) нажмите кнопку Копировать рядом с элементом Первичная строка подключения. Строка подключения будет скопирована в буфер обмена для дальнейшего использования. Вставьте на время эти значения в Блокноте или любом другом месте.
Повторите предыдущий шаг, скопировав и вставив значение первичного ключа во временное расположение для последующего использования.
Создание гибридного подключения
На странице Ретранслятора для пространства имен выполните следующие действия, чтобы создать гибридное подключение.
В меню слева выберите "Гибридные подключения" и выберите "Гибридные подключения".
На странице "Создание гибридного подключения" введите имя гибридного подключения и нажмите кнопку "Создать".
Создание серверного приложения (прослушивателя)
Создайте в Visual Studio консольное приложение C# для прослушивания и получения сообщений, отправленных ретранслятором.
Создание консольного приложение
В Visual Studio создайте проект Консольное приложение (.NET Framework).
Добавление пакета ретранслятора NuGet
- Щелкните созданный проект правой кнопкой мыши и выберите Управление пакетами NuGet.
- Выберите Обзор и выполните поиск по ключевой фразе Microsoft.Azure.Relay. В результатах поиска выберите Ретранслятор Microsoft Azure.
- Выберите Установить для завершения установки. Закройте диалоговое окно.
Написание кода для получения сообщений
В начале файла Program.cs замените существующие операторы
using
следующими операторамиusing
:using System; using System.IO; using System.Threading; using System.Threading.Tasks; using System.Net; using Microsoft.Azure.Relay;
Добавьте константы в класс
Program
, чтобы получить сведения о гибридном подключении. Замените заполнители значениями, полученными при создании гибридного подключения. Необходимо использовать полное имя пространства имен.// replace {RelayNamespace} with the name of your namespace private const string RelayNamespace = "YOUR-RELAY-NAMESPACE-NAME.servicebus.windows.net"; // replace {HybridConnectionName} with the name of your hybrid connection private const string ConnectionName = "HYBRID-CONNECTION-NAME"; // replace {SAKKeyName} with the name of your Shared Access Policies key, which is RootManageSharedAccessKey by default private const string KeyName = "SAS-KEY-NAME"; // replace {SASKey} with the primary key of the namespace you saved earlier private const string Key = "SAS-KEY-VALUE";
Добавьте метод
ProcessMessagesOnConnection
в классProgram
:// The method initiates the connection. private static async void ProcessMessagesOnConnection(HybridConnectionStream relayConnection, CancellationTokenSource cts) { Console.WriteLine("New session"); // The connection is a fully bidrectional stream. // Put a stream reader and a stream writer over it. // This allows you to read UTF-8 text that comes from // the sender, and to write text replies back. var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; while (!cts.IsCancellationRequested) { try { // Read a line of input until a newline is encountered. var line = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(line)) { // If there's no input data, signal that // you will no longer send data on this connection, // and then break out of the processing loop. await relayConnection.ShutdownAsync(cts.Token); break; } // Write the line on the console. Console.WriteLine(line); // Write the line back to the client, prepended with "Echo:" await writer.WriteLineAsync($"Echo: {line}"); } catch (IOException) { // Catch an I/O exception. This likely occurred when // the client disconnected. Console.WriteLine("Client closed connection"); break; } } Console.WriteLine("End session"); // Close the connection. await relayConnection.CloseAsync(cts.Token); }
Добавьте метод
RunAsync
в классProgram
:private static async Task RunAsync() { var cts = new CancellationTokenSource(); var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key); var listener = new HybridConnectionListener(new Uri(string.Format("sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider); // Subscribe to the status events. listener.Connecting += (o, e) => { Console.WriteLine("Connecting"); }; listener.Offline += (o, e) => { Console.WriteLine("Offline"); }; listener.Online += (o, e) => { Console.WriteLine("Online"); }; // Opening the listener establishes the control channel to // the Azure Relay service. The control channel is continuously // maintained, and is reestablished when connectivity is disrupted. await listener.OpenAsync(cts.Token); Console.WriteLine("Server listening"); // Provide callback for the cancellation token that will close the listener. cts.Token.Register(() => listener.CloseAsync(CancellationToken.None)); // Start a new thread that will continuously read the console. new Task(() => Console.In.ReadLineAsync().ContinueWith((s) => { cts.Cancel(); })).Start(); // Accept the next available, pending connection request. // Shutting down the listener allows a clean exit. // This method returns null. while (true) { var relayConnection = await listener.AcceptConnectionAsync(); if (relayConnection == null) { break; } ProcessMessagesOnConnection(relayConnection, cts); } // Close the listener after you exit the processing loop. await listener.CloseAsync(cts.Token); }
В метод
Main
в классеProgram
добавьте следующую строку кода:RunAsync().GetAwaiter().GetResult();
Готовый файл Program.cs будет выглядеть так:
namespace Server { using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Relay; public class Program { private const string RelayNamespace = "{RelayNamespace}.servicebus.windows.net"; private const string ConnectionName = "{HybridConnectionName}"; private const string KeyName = "{SASKeyName}"; private const string Key = "{SASKey}"; public static void Main(string[] args) { RunAsync().GetAwaiter().GetResult(); } private static async Task RunAsync() { var cts = new CancellationTokenSource(); var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key); var listener = new HybridConnectionListener(new Uri(string.Format("sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider); // Subscribe to the status events. listener.Connecting += (o, e) => { Console.WriteLine("Connecting"); }; listener.Offline += (o, e) => { Console.WriteLine("Offline"); }; listener.Online += (o, e) => { Console.WriteLine("Online"); }; // Opening the listener establishes the control channel to // the Azure Relay service. The control channel is continuously // maintained, and is reestablished when connectivity is disrupted. await listener.OpenAsync(cts.Token); Console.WriteLine("Server listening"); // Provide callback for a cancellation token that will close the listener. cts.Token.Register(() => listener.CloseAsync(CancellationToken.None)); // Start a new thread that will continuously read the console. new Task(() => Console.In.ReadLineAsync().ContinueWith((s) => { cts.Cancel(); })).Start(); // Accept the next available, pending connection request. // Shutting down the listener allows a clean exit. // This method returns null. while (true) { var relayConnection = await listener.AcceptConnectionAsync(); if (relayConnection == null) { break; } ProcessMessagesOnConnection(relayConnection, cts); } // Close the listener after you exit the processing loop. await listener.CloseAsync(cts.Token); } private static async void ProcessMessagesOnConnection(HybridConnectionStream relayConnection, CancellationTokenSource cts) { Console.WriteLine("New session"); // The connection is a fully bidrectional stream. // Put a stream reader and a stream writer over it. // This allows you to read UTF-8 text that comes from // the sender, and to write text replies back. var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; while (!cts.IsCancellationRequested) { try { // Read a line of input until a newline is encountered. var line = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(line)) { // If there's no input data, signal that // you will no longer send data on this connection. // Then, break out of the processing loop. await relayConnection.ShutdownAsync(cts.Token); break; } // Write the line on the console. Console.WriteLine(line); // Write the line back to the client, prepended with "Echo:" await writer.WriteLineAsync($"Echo: {line}"); } catch (IOException) { // Catch an I/O exception. This likely occurred when // the client disconnected. Console.WriteLine("Client closed connection"); break; } } Console.WriteLine("End session"); // Close the connection. await relayConnection.CloseAsync(cts.Token); } } }
Создание клиентского приложения (отправителя)
Создайте в Visual Studio консольное приложение C# для отправки сообщений в ретранслятор.
Создание консольного приложение
В Visual Studio создайте проект Консольное приложение (.NET Framework).
Добавление пакета ретранслятора NuGet
- Щелкните созданный проект правой кнопкой мыши и выберите Управление пакетами NuGet.
- Выберите Обзор и выполните поиск по ключевой фразе Microsoft.Azure.Relay. В результатах поиска выберите Ретранслятор Microsoft Azure.
- Выберите Установить для завершения установки. Закройте диалоговое окно.
Написание кода для отправки сообщений
В начале файла Program.cs замените существующие операторы
using
следующими операторамиusing
:using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Relay;
Добавьте константы в класс
Program
, чтобы получить сведения о гибридном подключении. Замените заполнители значениями, полученными при создании гибридного подключения. Необходимо использовать полное имя пространства имен.// replace {RelayNamespace} with the name of your namespace private const string RelayNamespace = "YOUR-RELAY-NAMESPACE-NAME.servicebus.windows.net"; // replace {HybridConnectionName} with the name of your hybrid connection private const string ConnectionName = "HYBRID-CONNECTION-NAME"; // replace {SAKKeyName} with the name of your Shared Access Policies key, which is RootManageSharedAccessKey by default private const string KeyName = "SAS-KEY-NAME"; // replace {SASKey} with the primary key of the namespace you saved earlier private const string Key = "SAS-KEY-VALUE";
Добавьте приведенный ниже метод в класс
Program
:private static async Task RunAsync() { Console.WriteLine("Enter lines of text to send to the server with ENTER"); // Create a new hybrid connection client. var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key); var client = new HybridConnectionClient(new Uri(String.Format("sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider); // Initiate the connection. var relayConnection = await client.CreateConnectionAsync(); // Run two concurrent loops on the connection. One // reads input from the console and writes it to the connection // with a stream writer. The other reads lines of input from the // connection with a stream reader and writes them to the console. // Entering a blank line shuts down the write task after // sending it to the server. The server then cleanly shuts down // the connection, which terminates the read task. var reads = Task.Run(async () => { // Initialize the stream reader over the connection. var reader = new StreamReader(relayConnection); var writer = Console.Out; do { // Read a full line of UTF-8 text up to newline. string line = await reader.ReadLineAsync(); // If the string is empty or null, you are done. if (String.IsNullOrEmpty(line)) break; // Write to the console. await writer.WriteLineAsync(line); } while (true); }); // Read from the console and write to the hybrid connection. var writes = Task.Run(async () => { var reader = Console.In; var writer = new StreamWriter(relayConnection) { AutoFlush = true }; do { // Read a line from the console. string line = await reader.ReadLineAsync(); // Write the line out, also when it's empty. await writer.WriteLineAsync(line); // Quit when the line is empty, if (String.IsNullOrEmpty(line)) break; } while (true); }); // Wait for both tasks to finish. await Task.WhenAll(reads, writes); await relayConnection.CloseAsync(CancellationToken.None); }
В метод
Main
в классеProgram
добавьте следующую строку кода.RunAsync().GetAwaiter().GetResult();
Файл Program.cs должен выглядеть следующим образом:
using System; using System.IO; using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Relay; namespace Client { class Program { private const string RelayNamespace = "{RelayNamespace}.servicebus.windows.net"; private const string ConnectionName = "{HybridConnectionName}"; private const string KeyName = "{SASKeyName}"; private const string Key = "{SASKey}"; static void Main(string[] args) { RunAsync().GetAwaiter().GetResult(); } private static async Task RunAsync() { Console.WriteLine("Enter lines of text to send to the server with ENTER"); // Create a new hybrid connection client. var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(KeyName, Key); var client = new HybridConnectionClient(new Uri(String.Format("sb://{0}/{1}", RelayNamespace, ConnectionName)), tokenProvider); // Initiate the connection. var relayConnection = await client.CreateConnectionAsync(); // Run two concurrent loops on the connection. One // reads input from the console and then writes it to the connection // with a stream writer. The other reads lines of input from the // connection with a stream reader and then writes them to the console. // Entering a blank line shuts down the write task after // sending it to the server. The server then cleanly shuts down // the connection, which terminates the read task. var reads = Task.Run(async () => { // Initialize the stream reader over the connection. var reader = new StreamReader(relayConnection); var writer = Console.Out; do { // Read a full line of UTF-8 text up to newline. string line = await reader.ReadLineAsync(); // If the string is empty or null, you are done. if (String.IsNullOrEmpty(line)) break; // Write to the console. await writer.WriteLineAsync(line); } while (true); }); // Read from the console and write to the hybrid connection. var writes = Task.Run(async () => { var reader = Console.In; var writer = new StreamWriter(relayConnection) { AutoFlush = true }; do { // Read a line from the console. string line = await reader.ReadLineAsync(); // Write the line out, also when it's empty. await writer.WriteLineAsync(line); // Quit when the line is empty. if (String.IsNullOrEmpty(line)) break; } while (true); }); // Wait for both tasks to finish. await Task.WhenAll(reads, writes); await relayConnection.CloseAsync(CancellationToken.None); } } }
Примечание.
Пример кода в этой статье использует строка подключения для проверки подлинности в пространстве имен Ретранслятора Azure, чтобы упростить учебник. Мы рекомендуем использовать проверку подлинности Идентификатора Microsoft Entra в рабочих средах, а не использовать строка подключения или подписанные URL-адреса, что может быть проще скомпрометировано. Подробные сведения и пример кода для использования проверки подлинности идентификатора Microsoft Entra см. в статье "Проверка подлинности и авторизация приложения с помощью идентификатора Microsoft Entra ID" для доступа к сущностям Ретрансляции Azure и аутентификации управляемого удостоверения с помощью идентификатора Microsoft Entra для доступа к ресурсам Ретранслятора Azure.
Запуск приложений
Запустите серверное приложение.
Запустите клиентское приложение и введите любой текст.
Убедитесь, что в серверном консольном приложении отображается текст, введенный в клиентском приложении.
Поздравляем, вы создали готовое приложение для гибридных подключений!
Следующие шаги
В этом кратком руководстве описано, как создать клиентские и серверные приложения .NET, которые отправляют и получают сообщения по протоколу WebSocket. Функция гибридных подключений службы Azure Relay также поддерживает использование протокола HTTP для отправки и получения сообщений. См. дополнительные сведения об использовании протокола HTTP с гибридными подключениями Azure Relay.
В этом кратком руководстве описано, как использовать .NET Framework для создания клиентских и серверных приложений. Сведения о том, как создавать клиентские и серверные приложения с помощью Node.js, см. в руководствах по использованию Node.js и WebSocket или Node.js и HTTP.