الشروع في العمل باستخدام Relay Hybrid Connections WebSockets في .NET

في هذا التشغيل السريع، يمكنك إنشاء تطبيقات .NET المرسل والمتلقي التي ترسل الرسائل وتستقبلها باستخدام اتصالات مختلطة WebSockets في Azure Relay. للتعرف على Azure Relay بشكل عام، راجع Azure Relay.

في هذا التشغيل السريع، يمكنك اتخاذ الخطوات التالية:

  1. إنشاء مساحة اسم Relay باستخدام مدخل Microsoft Azure.
  2. إنشاء اتصال مختلط في مساحة الاسم هذه باستخدام مدخل Microsoft Azure.
  3. اكتب تطبيق وحدة تحكم خادم (وحدة استماع) لتلقي الرسائل.
  4. اكتب تطبيق وحدة تحكم العميل (المرسل) لإرسال الرسائل.
  5. تشغيل التطبيقات.

المتطلبات الأساسية

لإكمال هذا البرنامج التعليمي، تحتاج إلى المتطلبات الأساسية التالية:

إنشاء مساحة اسم

  1. قم بتسجيل الدخول إلى بوابة Azure.

  2. حدد كل الخدمات في القائمة اليسرى. حدد Integration، وابحث عن Relays، وحرك الماوس فوق Relays، ثم حدد Create.

    لقطة شاشة تعرض تحديد Relays -> الزر Create.

  3. في صفحة Create namespace ، اتبع الخطوات التالية:

    1. بالنسبة إلى Subscription، اختر اشتراك Azure لإنشاءnamespace.

    2. بالنسبة لـ "مجموعة الموارد"، اختر مجموعة موارد موجودة حيث توجد namespace، أو إنشاء مجموعة موارد جديدة.

    3. أدخل اسما لمساحة اسم الترحيل.

    4. حدد المنطقة التي يجب استضافة مساحة الاسم فيها.

    5. حدد مراجعة + إنشاء عند أسفل الصفحة.

      لقطة شاشة تعرض صفحة إنشاء مساحة الاسم.

    6. في صفحة مراجعة+ إنشاء حدد إنشاء.

    7. بعد بضع دقائق، سترى صفحة Relay لمساحة الاسم.

      لقطة شاشة تعرض الصفحة الرئيسية لمساحة اسم Relay.

الحصول على بيانات اعتماد الإدارة

  1. في صفحة Relay ، حدد Shared access policies في القائمة اليمنى. `

  2. في إطارShared access policies، حدد RootManageSharedAccessKey.

  3. في إطار سياسةSAS: RootManageSharedAccessKey، حدد زر نسخ سلسلة الاتصال الأساسية. يقوم هذا الإجراء بنسخ سلسلة الاتصال إلى الحافظة لاستخدامها لاحقاً. وقم بلصق هذه القيمة في المفكرة أو بعض المواقع المؤقتة الأخرى.

  4. كرر الخطوة السابقة، وهي نسخ قيمة المفتاح الأساسي ولصقها إلى موقع مؤقت للاستخدام لاحقاً.

    لقطة شاشة تعرض معلومات الاتصال لمساحة اسم Relay.

إنشاء اتصال مختلط

في صفحة Relay لمساحة الاسم، اتبع هذه الخطوات لإنشاء اتصال مختلط.

  1. في القائمة اليسرى، ضمن Entities، حدد Hybrid Connections، ثم حدد + Hybrid Connection.

    لقطة شاشة تعرض صفحة الاتصالات المختلطة.

  2. في صفحة إنشاء اتصال مختلط، أدخل اسما للاتصال المختلط، وحدد إنشاء.

    لقطة شاشة تعرض صفحة إنشاء اتصال مختلط.

إنشاء تطبيق خادم (وحدة استماع)

في Visual Studio، اكتب تطبيق وحدة تحكم C# للاستماع إلى الرسائل وتلقيها من المرحل.

قم بإنشاء تطبيق وحدة تحكم

في 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. أضف السطر التالي من التعليمات البرمجية 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) جديد.

إضافة حزمة 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. أضف السطر التالي من التعليمات البرمجية 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 Relay للحفاظ على البرنامج التعليمي بسيطا. نوصي باستخدام مصادقة معرف Microsoft Entra في بيئات الإنتاج، بدلا من استخدام سلسلة الاتصال أو توقيعات الوصول المشترك، والتي يمكن اختراقها بسهولة أكبر. للحصول على معلومات مفصلة ونموذج التعليمات البرمجية لاستخدام مصادقة معرف Microsoft Entra، راجع مصادقة وتخويل تطبيق باستخدام معرف Microsoft Entra للوصول إلى كيانات Azure Relay ومصادقة هوية مدارة باستخدام معرف Microsoft Entra للوصول إلى موارد Azure Relay.

تشغيل التطبيقات

  1. تشغيل تطبيق الخادم.

  2. قم بتشغيل تطبيق العميل وأدخل بعض النص.

  3. تأكد من أن وحدة تحكم تطبيق الخادم تعرض النص الذي تم إدخاله في تطبيق العميل.

    تقوم نوافذ وحدة التحكم باختبار كل من تطبيقات الخادم والعميل.

تهانينا، لقد قمت بإنشاء تطبيق اتصالات مختلطة كامل!

الخطوات التالية

في هذا التشغيل السريع، قمت بإنشاء تطبيقات عميل وخادم .NET التي استخدمت WebSockets لإرسال الرسائل وتلقيها. تدعم ميزة الاتصالات المختلطة في Azure Relay أيضا استخدام HTTP لإرسال الرسائل وتلقيها. لمعرفة كيفية استخدام HTTP مع اتصالات Azure Relay المختلطة، راجع التشغيل السريع ل HTTP.

في هذا التشغيل السريع، استخدمت .NET Framework لإنشاء تطبيقات العميل والخادم. لمعرفة كيفية كتابة تطبيقات العميل والخادم باستخدام Node.js، راجع التشغيل السريع Node.js WebSockets أو التشغيل السريع Node.js HTTP.