.NET での Relay ハイブリッド接続 WebSocket の概要

このクイック スタートでは、Azure Relay のハイブリッド接続 WebSocket を使用してメッセージを送受信する .NET のセンダー アプリケーションとレシーバー アプリケーションを作成します。 Azure Relay 全般については、Azure Relay に関するページを参照してください。

このクイック スタートでは、以下の手順を実行します。

  1. Azure Portal を使用した Relay 名前空間の作成
  2. Azure Portal を使用した、その名前空間内のハイブリッド接続の作成
  3. メッセージを受信するサーバー (リスナー) コンソール アプリケーションの作成
  4. メッセージを送信するクライアント (送信側) コンソール アプリケーションの作成
  5. アプリケーションの実行

前提条件

このチュートリアルを完了するには、次の前提条件を用意しておく必要があります。

名前空間の作成

  1. Azure portal にサインインします。

  2. 左側のメニューから、 [すべてのサービス] を選択します。 [統合] を選択し、[リレー] を検索し、[リレー] の上にマウス ポインターを移動して、[作成] を選択します。

    Screenshot showing the selection of Relays -> Create button.

  3. [名前空間の作成] ページで、これらの手順を実行します。

    1. 名前空間を作成する Azure サブスクリプションを選択します。

    2. [リソース グループ] で、名前空間を追加する既存のリソース グループを選択するか、新しいリソース グループを作成します。

    3. リレー名前空間の名前を入力します。

    4. 名前空間をホストするリージョンを選択します。

    5. ページ下部にある [確認と作成] を選択します。

      Screenshot showing the Create namespace page.

    6. [確認および作成] ページで、 [作成] を選択します。

    7. 数分後に、名前空間の [リレー] ページを確認します。

      Screenshot showing the home page for Relay namespace.

管理資格情報を取得する

  1. [リレー] ページで、左側のメニューの [共有アクセス ポリシー] を選択します。 `

  2. [共有アクセス ポリシー] ページで、 [RootManageSharedAccessKey] を選択します。

  3. [SAS ポリシー:RootManageSharedAccessKey] の下で、 [プライマリ接続文字列] の横の [コピー] ボタンを選択します。 これで、後で使用できるように接続文字列がクリップボードにコピーされます。 この値をメモ帳などに一時的に貼り付けます。

  4. 前の手順を繰り返し、 [主キー] の値をコピーして、後で使用するために一時的な場所に貼り付けます。

    Screenshot showing the connection info for Relay namespace.

ハイブリッド接続の追加

名前空間の [リレー] ページで、次の手順に従ってハイブリッド接続を作成します。

  1. 左側のメニューの [エンティティ] の下で、[ハイブリッド接続] を選択し、[+ ハイブリッド接続] を選択します。

    Screenshot showing the Hybrid Connections page.

  2. [ハイブリッド接続の作成] ページで、ハイブリッド接続の名前を入力し、[作成] を選択します。

    Screenshot showing the Create Hybrid Connection page.

サーバー アプリケーション (リスナー) の作成

Visual Studio で C# コンソール アプリケーションを作成して、Relay からのメッセージをリッスンおよび受信します。

コンソール アプリケーションを作成する

Visual Studio で、新しいコンソール アプリ (.NET Framework) プロジェクトを作成します。

Relay NuGet パッケージを追加する

  1. 新しく作成したプロジェクトを右クリックしてから、[NuGet パッケージの管理] を選択します。
  2. [参照] を選択し、Microsoft.Azure.Relay を検索します。 検索結果から、"Microsoft Azure Relay" を選択します。
  3. [インストール] を選択してインストールを完了します。 ダイアログ ボックスを閉じる

メッセージを受信するコードを記述する

  1. Program.cs ファイルの先頭にある既存の using ステートメントを、次の using ステートメントに置き換えます。

    using System;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Net;
    using Microsoft.Azure.Relay;
    
  2. ハイブリッド接続の詳細に関する定数を 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";
    
  3. 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);
    }
    
  4. 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);
    }
    
  5. Program クラスの Main メソッドに次のコード行を追加します。

    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# コンソール アプリケーションを作成して、Relay にメッセージを送信します。

コンソール アプリケーションを作成する

Visual Studio で、新しいコンソール アプリ (.NET Framework) プロジェクトを作成します。

Relay NuGet パッケージを追加する

  1. 新しく作成したプロジェクトを右クリックしてから、[NuGet パッケージの管理] を選択します。
  2. [参照] を選択し、Microsoft.Azure.Relay を検索します。 検索結果から、"Microsoft Azure Relay" を選択します。
  3. [インストール] を選択してインストールを完了します。 ダイアログ ボックスを閉じる

メッセージを送信するコードを記述する

  1. Program.cs ファイルの先頭にある既存の using ステートメントを、次の using ステートメントに置き換えます。

    using System;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.Relay;
    
  2. ハイブリッド接続の詳細に関する定数を 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";
    
  3. 次のメソッドを 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);
    }
    
  4. Program クラスの Main メソッドに次のコード行を追加します。

    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);
            }
        }
    }
    

アプリケーションの実行

  1. サーバー アプリケーションを実行します。

  2. クライアント アプリケーションを実行し、何かテキストを入力します。

  3. サーバー アプリケーション コンソールに、クライアント アプリケーションで入力したテキストが表示されることを確認します。

    Console windows testing both the server and client applications.

これで、完全なハイブリッド接続のアプリケーションが作成されました。

次のステップ

このクイック スタートでは、WebSocket を使用してメッセージを送受信する .NET のクライアント アプリケーションとサーバー アプリケーションを作成しました。 Azure Relay のハイブリッド接続機能は、HTTP を使用したメッセージの送受信もサポートしています。 Azure Relay のハイブリッド接続で HTTP を使用する方法については、HTTP のクイック スタートを参照してください。

このクイック スタートでは、.NET Framework を使用してクライアント アプリケーションとサーバー アプリケーションを作成しました。 Node.js を使用してクライアント アプリケーションとサーバー アプリケーションを作成する方法については、Node.js WebSocket のクイック スタートまたは Node.js HTTP のクイック スタートを参照してください。