التشغيل السريع: إنشاء غرفة دردشة باستخدام SignalR Service

خدمة Azure SignalR هي خدمة تدار بواسطة Azure تساعد المطورين على إنشاء تطبيقات الويب بسهولة باستخدام ميزات الوقت الحقيقي.

يوضح هذا المقال كيفية البدء باستخدام Azure SignalR Service. في هذا التشغيل السريع، ستقوم بإنشاء تطبيق دردشة باستخدام تطبيق ويب ASP.NET Core. سيُجري توصيل هذا التطبيق مع مورد Azure SignalR Service لتمكين تحديثات المحتوى في الوقت الحقيقي. ستستضيف تطبيق الويب محلياً وتتصل بالعديد من عملاء المتصفح. سيتمكن كل عميل من إرسال تحديثات المحتوى إلى جميع العملاء الآخرين.

يمكنك استخدام أي محرر تعليمات برمجية لإكمال الخطوات الواردة في التشغيل السريع. تتمثل أحد الخيارات في Visual Studio Code، والذي يتوفر على الأنظمة الأساسية لـ Windows وmacOS وLinux.

يُعد كود البرنامج التعليمي مُتاح للتحميل في مستودع AzureSignalR-samples GitHub. يمكنك إنشاء موارد Azure المستخدمة في هذا التشغيل السريع باتباع إنشاء برنامج نصي لخدمة SignalR.

في حال لم يكن لديك اشتراك في Azure، قم بإنشاءحساب مجاني قبل البدء.

هل أنت مستعد للبدء؟

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

هل تواجه مشكلات؟ جرب دليل استكشاف الأخطاء وإصلاحها أو أخبرنا.

إنشاء مورد Azure SignalR

في هذا القسم، يمكنك إنشاء مثيل Azure SignalR أساسي لاستخدامه لتطبيقك. تستخدم الخطوات التالية مدخل Microsoft Azure لإنشاء مثيل جديد، ولكن يمكنك أيضا استخدام Azure CLI. لمزيد من المعلومات، راجع الأمر az signalr create في مرجع Azure SignalR Service CLI.

  1. سجل الدخول إلى مدخل Azure.
  2. في الجانب العلوي الأيسر من الصفحة، اختر+ إنشاء مورد.
  3. في صفحة إنشاء مورد، في مربع النص خدمة البحث والسوق، أدخل signalr ثم حدد SignalR Service من القائمة.
  4. في صفحة SignalR Service ، حدد Create.
  5. في علامة التبويب Basics ، يمكنك إدخال المعلومات الأساسية لمثيل SignalR Service الجديد. أدخل القيم التالية:
الحقل القيم المقترحة ‏‏الوصف
الاشتراك اختر اشتراكك حدد الاشتراك الذي تريد استخدامه لإنشاء مثيل خدمة SignalR جديد.
مجموعة الموارد إنشاء مجموعة موارد باسم SignalRTestResources يوصى باختيار أو إنشاء مجموعة موارد لموردك SignalR. من المفيد إنشاء مجموعة موارد جديدة لهذا البرنامج التعليمي بدلا من استخدام مجموعة موارد موجودة. لتحرير الموارد بعد إكمال البرنامج التعليمي، احذف مجموعة الموارد.

يؤدي حذف مجموعة موارد أيضا إلى حذف كافة الموارد التي تنتمي إلى المجموعة. لا يمكن التراجع عن هذا الإجراء. قبل حذف مجموعة موارد، تأكد من أنها لا تحتوي على موارد تريد الاحتفاظ بها.

للمزيد من المعلومات، يُرجى الرجوع إلى استخدام مجموعات الموارد لإدارة موارد Azure.
اسم المورد testsignalr أدخل اسم مورد مميزًا لاستخدامه في مورد SignalR. إذا تم أخذ testignalr بالفعل في منطقتك، أضف رقما أو حرفا حتى يكون الاسم فريدا.

يجب أن يكون الاسم سلسلة مكونة من 1 إلى 63 حرفًا وتتضمن الأرقام والحروف ورمز الواصلة فقط -. لا يمكن أن يبدأ الاسم أو ينتهي بحرف الواصلة، وأحرف الواصلة المتتالية غير صالحة.
المنطقة اختيار منطقتك حدد المنطقة المناسبة لمثيل SignalR Service الجديد.

خدمة Azure SignalR غير متوفرة حاليا في جميع المناطق. لمزيد من المعلومات، راجع توفر منطقة خدمة Azure SignalR
مستوى الأسعار حدد تغيير ثم اختر مجاني (التطوير/الاختبار فقط). اختر تحديد لتأكيد اختيارك لمستوى التسعير. تحتوي خدمة Azure SignalR على ثلاثة مستويات تسعير: Free وStandard وPremium. تستخدم البرامج التعليمية المستوى المجاني ، ما لم يتم ملاحظة خلاف ذلك في المتطلبات الأساسية.

لمزيد من المعلومات حول اختلافات الوظائف بين المستويات والتسعير، راجع تسعير خدمة Azure SignalR
وضع الخدمة اختر وضع الخدمة المناسب استخدم الافتراضي عند استضافة منطق مركز SignalR في تطبيقات الويب واستخدام خدمة SignalR كوكيل. استخدم Serverless عند استخدام تقنيات بلا خادم مثل Azure Functions لاستضافة منطق مركز SignalR.

الوضع الكلاسيكي هو فقط للتوافق مع الإصدارات السابقة ولا يوصى باستخدامه.

لمزيد من المعلومات، راجع وضع الخدمة في خدمة Azure SignalR.

لا تحتاج إلى تغيير الإعدادات في علامات التبويب الشبكات والعلامات لبرامج SignalR التعليمية.

  1. حدد الزر Review + create أسفل علامة التبويب Basics .
  2. في علامة التبويب Review + create ، راجع القيم ثم حدد Create. يستغرق الأمر بضع لحظات حتى يكتمل النشر.
  3. عند اكتمال النشر، حدد الزر Go to resource .
  4. في صفحة مورد SignalR، حدد Keys من القائمة على اليسار، ضمن الإعدادات.
  5. انسخ سلسلة الاتصال ion للمفتاح الأساسي. تحتاج إلى هذا سلسلة الاتصال لتكوين تطبيقك لاحقا في هذا البرنامج التعليمي.

قم بإنشاء تطبيق ويب ASP.NET Core

في هذا القسم، يمكنك استخدام واجهة سطر الأوامر.NET Core (CLI) لإنشاء مشروع تطبيق ويب الخاص بـASP.NET Core MVC. تتفوق ميزة استخدام .NET Core CLI على استخدام Visual Studio في أنه متوفر على منصات Windows وmacOS وLinux.

  1. أنشئ مجلداً جديداً لمشروعك. يستخدم هذا التشغيل السريع مجلد الدردشة.

  2. في المجلد الجديد، شَغّل الأمر التالي لإنشاء المشروع:

    dotnet new web
    

إضافة مدير سري للمشروع

وفقاً لهذا القسم، ستُضيف أداة "المدير السري" إلى مشروعك. تُخزن أداة "المدير السري" البيانات الحساسة لأعمال التطوير خارج شجرة المشروع. يساعد هذا النهج على منع المشاركة العرضية لأسرار التطبيق داخل كود المصدر.

  1. في المجلد ، اينيت UserSecretsId عن طريق تشغيل الأمر التالي:

    dotnet user-secrets init
    
  2. إضافة سراً باسم "Azure:SignalR:ConnectionString" إلى "المدير السري".

    سيحتوي هذا السر على سلسلة الاتصال للوصول إلى مورد خدمة SignalR. يُعد Azure:SignalR:ConnectionString هو مفتاح التكوين الافتراضي الذي يبحث عنه SignalR لتأسيس الاتصال. استبدال القيمة في الأمر التالي باستخدام سلسلة الاتصال لمورد خدمة SignalR.

    يجب تشغيل هذا الأمر في نفس الدليل مثل csproj الملف.

    dotnet user-secrets set Azure:SignalR:ConnectionString "<Your connection string>"
    

    سيتم استخدام "المدير السري" فقط لاختبار تطبيق الويب أثناء استضافته محلياً. في البرنامج التعليمي اللاحق، ستقوم بنشر تطبيق ويب الدردشة على Azure. بعد نشر تطبيق الويب على Azure، ستستخدم إعدادات التطبيق بدلاً من تخزين سلسلة الاتصال باستخدام "إدارة سرية".

    يتم الوصول إلى هذا السر باستخدام تكوين API. تعمل النقطتان (:) في اسم التكوين باستخدام تكوين API على جميع الأنظمة الأساسية المعتمدة. يُرجى الاطلاع على التكوين حسب البيئة.

إضافة Azure SignalR إلى تطبيق الويب

  1. إضافة مرجع إلى Microsoft.Azure.SignalR حزمة NuGet عن طريق تشغيل الأمر التالي:

    dotnet add package Microsoft.Azure.SignalR
    
  2. افتح Program.cs وقم بتحديث التعليمات البرمجية إلى ما يلي، فإنه يستدعي AddSignalR() الأسلوبين و AddAzureSignalR() لاستخدام Azure SignalR Service:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddSignalR().AddAzureSignalR();
    var app = builder.Build();
    
    app.UseDefaultFiles();
    app.UseRouting();
    app.UseStaticFiles();
    app.MapHub<ChatSampleHub>("/chat");
    app.Run();
    

    عدم تمرير معلمة إلى AddAzureSignalR() يعني أنها تستخدم مفتاح التكوين الافتراضي لمورد SignalR Service سلسلة الاتصال. يتمثل مفتاح التكوين الظاهري في Azure:SignalR:ConnectionString. كما أنه يستخدم ChatSampleHub الذي سننشئه في القسم أدناه.

إضافة مركز الفئة

في SignalR، المركز هو مكون أساسي يعرض مجموعة من الأساليب التي يمكن استدعاؤها من قبل العميل. في هذا القسم، يُمكنك تحديد مركز الفئة بأسلوبين:

  • BroadcastMessageيبث هذا الأسلوب رسالة إلى جميع العملاء.
  • Echoيرسل هذا الأسلوب رسالة إلى المتصل.

يستخدم كلا الأسلوبين Clients الواجهة التي يوفرها ASP.NET Core SignalR SDK. تمنحك هذه الواجهة إمكانية الوصول إلى جميع العملاء المتصلين، حتى تتمكن من إرسال المحتوى إلى عملائك.

  1. في دليل مشروعك، إضافة مجلد جديد يُسمى "Hub". أضف ملف رمز مركز جديد يسمى ChatSampleHub.cs إلى المجلد الجديد.

  2. أضف التعليمات البرمجية التالية إلى ChatSampleHub.cs لتعريف فئة المركز وحفظ الملف.

    using Microsoft.AspNetCore.SignalR;
    
    public class ChatSampleHub : Hub
    {
        public Task BroadcastMessage(string name, string message) =>
            Clients.All.SendAsync("broadcastMessage", name, message);
    
        public Task Echo(string name, string message) =>
            Clients.Client(Context.ConnectionId)
                    .SendAsync("echo", name, $"{message} (echo from server)");
    }
    

إضافة واجهة العميل لتطبيق الويب

ستتكون واجهة مستخدم العميل الخاصة بتطبيق غرفة الدردشة من "HTML" وJavaScript في ملف يُسمى index.htm في دليلwwwroot.

نسخ ملف css/site.css من مجلد wwwroot من مستودع النماذج. استبدال css/site الخاص بمشروعك بنسخة قمت بطباعتها.

أنشئ ملفا جديدا في دليل wwwroot المسمى index.html، وانسخ HTML التالي والصقه في الملف الذي تم إنشاؤه حديثا.

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  <meta name="viewport" content="width=device-width">
  <meta http-equiv="Pragma" content="no-cache" />
  <meta http-equiv="Expires" content="0" />
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet" />
  <link href="css/site.css" rel="stylesheet" />
  <title>Azure SignalR Group Chat</title>
</head>
<body>
  <h2 class="text-center" style="margin-top: 0; padding-top: 30px; padding-bottom: 30px;">Azure SignalR Group Chat</h2>
  <div class="container" style="height: calc(100% - 110px);">
    <div id="messages" style="background-color: whitesmoke; "></div>
    <div style="width: 100%; border-left-style: ridge; border-right-style: ridge;">
      <textarea id="message" style="width: 100%; padding: 5px 10px; border-style: hidden;"
        placeholder="Type message and press Enter to send..."></textarea>
    </div>
    <div style="overflow: auto; border-style: ridge; border-top-style: hidden;">
      <button class="btn-warning pull-right" id="echo">Echo</button>
      <button class="btn-success pull-right" id="sendmessage">Send</button>
    </div>
  </div>
  <div class="modal alert alert-danger fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <div>Connection Error...</div>
          <div><strong style="font-size: 1.5em;">Hit Refresh/F5</strong> to rejoin. ;)</div>
        </div>
      </div>
    </div>
  </div>

  <!--Reference the SignalR library. -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>

  <!--Add script to update the page and send messages.-->
  <script type="text/javascript">
    document.addEventListener("DOMContentLoaded", function () {
      function getUserName() {
        function generateRandomName() {
          return Math.random().toString(36).substring(2, 10);
        }

        // Get the user name and store it to prepend to messages.
        var username = generateRandomName();
        var promptMessage = "Enter your name:";
        do {
          username = prompt(promptMessage, username);
          if (!username || username.startsWith("_") || username.indexOf("<") > -1 || username.indexOf(">") > -1) {
            username = "";
            promptMessage = "Invalid input. Enter your name:";
          }
        } while (!username)
        return username;
      }

      username = getUserName();
      // Set initial focus to message input box.
      var messageInput = document.getElementById("message");
      messageInput.focus();

      function createMessageEntry(encodedName, encodedMsg) {
        var entry = document.createElement("div");
        entry.classList.add("message-entry");
        if (encodedName === "_SYSTEM_") {
          entry.innerHTML = encodedMsg;
          entry.classList.add("text-center");
          entry.classList.add("system-message");
        } else if (encodedName === "_BROADCAST_") {
          entry.classList.add("text-center");
          entry.innerHTML = `<div class="text-center broadcast-message">${encodedMsg}</div>`;
        } else if (encodedName === username) {
          entry.innerHTML = `<div class="message-avatar pull-right">${encodedName}</div>` +
            `<div class="message-content pull-right">${encodedMsg}<div>`;
        } else {
          entry.innerHTML = `<div class="message-avatar pull-left">${encodedName}</div>` +
            `<div class="message-content pull-left">${encodedMsg}<div>`;
        }
        return entry;
      }

      function appendMessage(encodedName, encodedMsg) {
        var messageEntry = createMessageEntry(encodedName, encodedMsg);
        var messageBox = document.getElementById("messages");
        messageBox.appendChild(messageEntry);
        messageBox.scrollTop = messageBox.scrollHeight;
      }

      function bindConnectionMessage(connection) {
        var messageCallback = function (name, message) {
          if (!message) return;
          // Html encode display name and message.
          var encodedName = name;
          var encodedMsg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
          appendMessage(encodedName, encodedMsg);
        };
        // Create a function that the hub can call to broadcast messages.
        connection.on("broadcastMessage", messageCallback);
        connection.on("echo", messageCallback);
        connection.onclose(onConnectionError);
      }

      function onConnected(connection) {
        console.log("connection started");
        connection.send("broadcastMessage", "_SYSTEM_", username + " JOINED");
        document.getElementById("sendmessage").addEventListener("click", function (event) {
          // Call the broadcastMessage method on the hub.
          if (messageInput.value) {
            connection.send("broadcastMessage", username, messageInput.value)
              .catch((e) => appendMessage("_BROADCAST_", e.message));
          }

          // Clear text box and reset focus for next comment.
          messageInput.value = "";
          messageInput.focus();
          event.preventDefault();
        });
        document.getElementById("message").addEventListener("keypress", function (event) {
          if (event.keyCode === 13) {
            event.preventDefault();
            document.getElementById("sendmessage").click();
            return false;
          }
        });
        document.getElementById("echo").addEventListener("click", function (event) {
          // Call the echo method on the hub.
          connection.send("echo", username, messageInput.value);

          // Clear text box and reset focus for next comment.
          messageInput.value = "";
          messageInput.focus();
          event.preventDefault();
        });
      }

      function onConnectionError(error) {
        if (error && error.message) {
          console.error(error.message);
        }
        var modal = document.getElementById("myModal");
        modal.classList.add("in");
        modal.style = "display: block;";
      }

      var connection = new signalR.HubConnectionBuilder()
        .withUrl("/chat")
        .build();
      bindConnectionMessage(connection);
      connection.start()
        .then(function () {
          onConnected(connection);
        })
        .catch(function (error) {
          console.error(error.message);
        });
    });
  </script>
</body>
</html>

الكود المُتاح في index.html المكالمات HubConnectionBuilder.build() لتوصيل "HTTP" لمورد SignalR Azure.

إذا تمت عملية الاتصال بنجاح، يتم تمرير هذا الاتصال إلى bindConnectionMessage، الذي يضيف معالجات الأحداث للمحتوى الوارد المُرسل إلى العميل.

HubConnection.start() بدء الاتصال باستخدام المركز. ثم، onConnected() إضافة زر معالجات الأحداث. تستخدم هذه المعالجات الاتصال للسماح لهذا العميل بإرسال تحديثات المحتوى لجميع العملاء المتصلين.

يوصى بإنشاء التطبيق وتشغيله محليًا

  1. قم بتشغيل الأمر التالي لتشغيل تطبيق الويب محليا:

    dotnet run
    

    ستتم استضافة التطبيق محليا مع إخراج يحتوي على عنوان URL المضيف المحلي، على سبيل المثال، كما يلي:

    Building...
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: http://localhost:5000
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info: Microsoft.Hosting.Lifetime[0]
          Hosting environment: Development
    
  2. افتح نافذتين للمتصفح. في كل مستعرض، انتقل إلى عنوان URL المضيف المحلي الموضح في نافذة الإخراج، على سبيل المثال، http://localhost:5000/ كما تظهر نافذة الإخراج أعلاه. تتم مطالبتك بإدخال اسمك. أدخل اسم عميل لكل من العملاء واختبار إرسال محتوى الرسالة بين كلا العميلين باستخدام زر "Send".

    Example of an Azure SignalR group chat

تنظيف الموارد

إذا كنت ستستمر في البرنامج التعليمي التالي، فيمكنك الاحتفاظ بالموارد التي أنشأتها في التشغيل السريع وإعادة استخدامها.

إذا انتهيت من تطبيق نموذج التشغيل السريع، يُمكنك حذف موارد Azure التي تم إنشاؤها في التشغيل السريع لتجنب فرض رسوم.

هام

يُعد حذف مجموعة الموارد أمراً لا رجعة فيه وتتضمن جميع الموارد المُتاحة في تلك المجموعة. يُرجى التأكد من عدم حذف مجموعة الموارد أو الموارد غير الصحيحة عن طريق الخطأ. إذا قمت بإنشاء الموارد في هذه العينة في مجموعة موارد موجودة تحتوي على الموارد التي تريد الاحتفاظ بها، يمكنك حذف كل مورد على حدة من جزءه بدلا من حذف مجموعة الموارد.

سجل الدخول إلىمدخل Azureوحددمجموعات الموارد.

في المربع "التصفية" حسب الاسم، يُرجى كتابة اسم مجموعة الموارد. استخدمت إرشادات هذه المقالة مجموعة موارد تسمى SignalRTestResources. في مجموعة الموارد في قائمة النتائج، حدد علامة الحذف (...) >حذف مجموعة الموارد.

Selections for deleting a resource group

يُطلب منك تأكيد حذف مجموعة الموارد. أدخل اسم مجموعة الموارد للتأكيد وحدد "Delete".

بعد مرور لحظات قليلة، يتم حذف مجموعة الموارد وجميع مواردها.

هل تواجه مشكلات؟ جرب دليل استكشاف الأخطاء وإصلاحها أو أخبرنا.

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

وفقاً للتشغيل السريع، أنشئ مورد خدمة SignalR Azure الجديد. ثم استخدمته مع تطبيق ويب ASP.NET Core لدفع تحديثات المحتوى في الوقت الفعلي إلى العديد من العملاء المتصلين. لمعرفة المزيد حول استخدام Azure SignalR Service، يُرجى متابعة البرنامج التعليمي الذي يوضح عملية المصادقة.