在 .NET 中開始使用轉送混合式連線 WebSocket
在本快速入門中,您將建立 .NET 傳送者與接收者應用程式,以使用 Azure 轉送中的混合式連線 WebSocket 來傳送和接收訊息。 若要對 Azure 轉送有整體上的了解,請參閱 Azure 轉送。
在本快速入門中,您會執行下列步驟:
- 使用 Azure 入口網站建立轉送命名空間。
- 使用 Azure 入口網站,在該命名空間中建立混合式連線。
- 撰寫伺服器 (接聽端) 主控台應用程式來接收訊息。
- 撰寫用戶端 (傳送端) 主控台應用程式來傳送訊息。
- 執行應用程式。
必要條件
若要完成本教學課程,您需要下列必要條件:
- Visual Studio 2015 或更新版本。 本教學課程中的範例使用 Visual Studio 2017。
- Azure 訂用帳戶。 如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶。
建立命名空間
登入 Azure 入口網站。
選取左側功能表上的 [所有服務]。 選取 [整合],並搜尋「轉送」,再將滑鼠移至 [轉送] 上方,然後選取 [建立]。
在 [建立命名空間] 頁面上,遵循下列步驟:
選擇要在其中建立命名空間的 Azure 訂用帳戶。
針對資源群組,選擇將放置命名空間的現有資源群組,或是建立新的資源群組。
輸入轉送命名空間的名稱。
選取要用來裝載命名空間的區域。
選取頁面底部的 [檢閱 + 建立] 。
在 [檢閱 + 建立] 頁面上,選取 [建立]。
幾分鐘後,您會看到命名空間的 [轉送] 頁面。
取得管理認證
在 [轉送] 頁面上,選取左側功能表上的 [共用存取原則]。 `
在 [共用存取原則] 頁面上,選取 [RootManageSharedAccessKey]。
在 [SAS 原則: RootManageSharedAccessKey] 下,選取 [主要連接字串] 旁的 [複製] 按鈕。 此動作會將連接字串複製到剪貼簿以供稍後使用。 將此值貼到記事本或一些其他暫存位置。
重複前一個步驟,複製 [主要金鑰] 的值並貼到暫存位置以供稍後使用。
Create a hybrid connection
在命名空間的 [轉送] 頁面上,遵循下列步驟來建立混合式連線。
在左側功能表的 [實體] 下,選取 [混合式連線],然後選取 [+ 混合式連線]。
在 [建立混合式連線] 頁面上,輸入混合式連線的名稱,然後選取 [建立]。
建立伺服器應用程式 (接聽程式)
在 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); }
將下列程式碼行新增至
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# 主控台應用程式以將訊息傳送至轉送。
建立主控台應用程式
在 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); }
將下列程式碼行新增至
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); } } }
執行應用程式
執行伺服器應用程式。
執行用戶端應用程式並輸入一些文字。
確定伺服器應用程式主控台有顯示用戶端應用程式中所輸入的文字。
恭喜,您已建立完整的混合式連線應用程式!
下一步
在本快速入門中,您已建立 .NET 用戶端和使用 WebSocket 來傳送和接收訊息的伺服器應用程式。 Azure 轉送的混合式連線功能也支援使用 HTTP 來傳送和接收訊息。 若要了解如何搭配使用 HTTP 和 Azure 轉送混合式連線,請參閱 HTTP 快速入門。
在本快速入門中,您已使用 .NET Framework 來建立用戶端和伺服器應用程式。 若要了解如何使用 Node.js 撰寫用戶端和伺服器應用程式,請參閱 Node.js WebSocket 快速入門或 Node.js HTTP 快速入門。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應