開始使用 .NET 中的轉送混合式連線ions WebSocket

在本快速入門中,您會使用 Azure 轉送中的混合式 連線ions WebSocket 建立 .NET 傳送者和接收者應用程式,以傳送和接收訊息。 若要瞭解 Azure 轉寄一般,請參閱 Azure 轉寄

在本快速入門中,您會採取下列步驟:

  1. 使用 Azure 入口網站 建立轉寄命名空間。
  2. 使用 Azure 入口網站,在該命名空間中建立混合式連線。
  3. 撰寫伺服器(接聽程式)主控台應用程式以接收訊息。
  4. 撰寫用戶端 (sender) 主控台應用程式以傳送訊息。
  5. 執行應用程式。

必要條件

若要完成本教學課程,您需要下列必要條件:

  • Visual Studio 2015 或更新版本。 本教學課程中的範例使用 Visual Studio 2017。
  • Azure 訂用帳戶。 如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶

建立命名空間

  1. 登入 Azure 入口網站

  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] 下 ,選取 [主要連線ion String 旁的 [複製 ] 按鈕。 此動作會將連接字串複製到剪貼簿以供稍後使用。 將此值貼到記事本或其他一些暫存位置。

  4. 重複上述步驟,將 [主要金鑰 ] 的值 複製並貼到暫存位置,以供日後使用。

    Screenshot showing the connection info for Relay namespace.

建立混合式連線

在命名空間的 [ 轉送 ] 頁面上,遵循下列步驟來建立混合式連線。

  1. 在左側功能表上的 [實體 ] 下 ,選取 [混合式連線] ,然後選取 [+ 混合式連線]。

    Screenshot showing the Hybrid Connections page.

  2. 在 [ 建立混合式連線ion ] 頁面上,輸入混合式連線的名稱,然後選取 [ 建立 ]。

    Screenshot showing the Create Hybrid Connection page.

建立伺服器應用程式 (接聽程式)

在 Visual Studio 中,撰寫 C# 主控台應用程式以接聽和接收來自轉播的訊息。

建立主控台應用程式

在 Visual Studio 中,建立新的 主控台應用程式 (.NET Framework) 專案。

新增轉寄 NuGet 套件

  1. 以滑鼠右鍵按一下新建立的專案,然後選取 [ 管理 NuGet 套件 ]。
  2. 選取 [ 流覽 ],然後搜尋 Microsoft.Azure.Relay 。 在搜尋結果中,選取 [Microsoft Azure 轉寄 ]。
  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. 將下列程式程式碼新增至 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 套件

  1. 以滑鼠右鍵按一下新建立的專案,然後選取 [ 管理 NuGet 套件 ]。
  2. 選取 [ 流覽 ],然後搜尋 Microsoft.Azure.Relay 。 在搜尋結果中,選取 [Microsoft Azure 轉寄 ]。
  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. 將下列程式程式碼新增至 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);
            }
        }
    }
    

執行應用程式

  1. 執行伺服器應用程式。

  2. 執行用戶端應用程式並輸入一些文字。

  3. 確定伺服器應用程式主控台會顯示在用戶端應用程式中輸入的文字。

    Console windows testing both the server and client applications.

恭喜您,您已建立完整的混合式連線ions 應用程式!

下一步

在本快速入門中,您已建立使用 WebSocket 來傳送和接收訊息的 .NET 用戶端和伺服器應用程式。 Azure 轉送的混合式連線功能也支援使用 HTTP 來傳送和接收訊息。 若要瞭解如何搭配 Azure 轉送混合式連線使用 HTTP,請參閱 HTTP 快速入門

在本快速入門中,您已使用 .NET Framework 來建立用戶端和伺服器應用程式。 若要瞭解如何使用 Node.js 撰寫用戶端和伺服器應用程式,請參閱 Node.js WebSockets 快速入門 Node.js HTTP 快速入門