إنشاء تطبيق دردشة Blazor Server

هذا البرنامج التعليمي يوضح لك كيفية بناء وتعديل تطبيق Blazor Server. ستتعلم كيفية:

  • بناء غرفة دردشة بسيطة مع قالب تطبيق Blazor Server.
  • العمل مع مكونات Blazor.
  • استخدم معالجة الأحداث وربط البيانات في مكونات Razor.
  • نشر سريع إلى Azure App Service في Visual Studio.
  • ترحيل من SignalR المحلية إلى خدمة Azure SignalR.

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

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

هل تواجه مشكلات؟ أبلغنا بها.

بناء غرفة دردشة محلية في تطبيق Blazor Server

بدءاً من Visual Studio الإصدار 16.2.0 من 2019، تم تضمين خدمة Azure SignalR في عملية نشر تطبيق الويب لجعل إدارة التبعيات بين تطبيق الويب وخدمة SignalR أكثر ملاءمة. يمكنك العمل في مثيل SignalR محلي في بيئة تطوير محلية والعمل في خدمة Azure SignalR لخدمة تطبيقات Azure في نفس الوقت دون أي تغييرات في التعليمات البرمجية.

  1. قم بإنشاء تطبيق دردشة Blazor:

    1. في Visual Studio، قم بإنشاء مشروع جديد.

    2. حدد تطبيق Blazor.

    3. قم بتسمية التطبيق واختر مجلداً.

    4. حدد قالب تطبيق خادم Blazor.

      إشعار

      تأكد من أنك قمت بالفعل بتثبيت .NET Core SDK 3.0+ لتمكين Visual Studio من التعرف بشكل صحيح على إطار عمل الهدف.

      In Create a new project, select the Blazor app template.

    5. يمكنك أيضاً إنشاء مشروع عن طريق تشغيل dotnet new الأمر في .NET CLI:

      dotnet new blazorserver -o BlazorChat
      
  2. إضافة ملف C# جديد يسمى BlazorChatSampleHub.cs وإنشاء فئة جديدة BlazorChatSampleHub مشتقة من الفئة Hubلتطبيق الدردشة. لمزيد من المعلومات حول إنشاء لوحات الوصل، راجع إنشاء لوحات الوصل واستخدامها.

    using System;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.SignalR;
    
    namespace BlazorChat
    {
        public class BlazorChatSampleHub : Hub
        {
            public const string HubUrl = "/chat";
    
            public async Task Broadcast(string username, string message)
            {
                await Clients.All.SendAsync("Broadcast", username, message);
            }
    
            public override Task OnConnectedAsync()
            {
                Console.WriteLine($"{Context.ConnectionId} connected");
                return base.OnConnectedAsync();
            }
    
            public override async Task OnDisconnectedAsync(Exception e)
            {
                Console.WriteLine($"Disconnected {e?.Message} {Context.ConnectionId}");
                await base.OnDisconnectedAsync(e);
            }
        }
    }
    
  3. إضافة نقطة نهاية لوحة الوصل في الأسلوب Startup.Configure().

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapFallbackToPage("/_Host");
        endpoints.MapHub<BlazorChatSampleHub>(BlazorChatSampleHub.HubUrl);
    });
    
  4. تثبيت Microsoft.AspNetCore.SignalR.Client الحزمة لاستخدام عميل SignalR.

    dotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.7
    
  5. إنشاء مكون Razor جديد يسمى ضمن المجلد لتنفيذ ChatRoom.razor عميل Pages SignalR. اتبع الخطوات أدناه أو استخدم ملف ChatRoom.razor.

    1. إضافة @page التوجيه وعبارات الاستخدام. استخدم @inject التوجيه لإدخال NavigationManager الخدمة.

      @page "/chatroom"
      @inject NavigationManager navigationManager
      @using Microsoft.AspNetCore.SignalR.Client;
      
    2. في المقطع @code، أضف الأعضاء التاليين إلى عميل SignalR جديد لإرسال واستقبال الرسائل.

      @code {
          // flag to indicate chat status
          private bool _isChatting = false;
      
          // name of the user who will be chatting
          private string _username;
      
          // on-screen message
          private string _message;
      
          // new message input
          private string _newMessage;
      
          // list of messages in chat
          private List<Message> _messages = new List<Message>();
      
          private string _hubUrl;
          private HubConnection _hubConnection;
      
          public async Task Chat()
          {
              // check username is valid
              if (string.IsNullOrWhiteSpace(_username))
              {
                  _message = "Please enter a name";
                  return;
              };
      
              try
              {
                  // Start chatting and force refresh UI.
                  _isChatting = true;
                  await Task.Delay(1);
      
                  // remove old messages if any
                  _messages.Clear();
      
                  // Create the chat client
                  string baseUrl = navigationManager.BaseUri;
      
                  _hubUrl = baseUrl.TrimEnd('/') + BlazorChatSampleHub.HubUrl;
      
                  _hubConnection = new HubConnectionBuilder()
                      .WithUrl(_hubUrl)
                      .Build();
      
                  _hubConnection.On<string, string>("Broadcast", BroadcastMessage);
      
                  await _hubConnection.StartAsync();
      
                  await SendAsync($"[Notice] {_username} joined chat room.");
              }
              catch (Exception e)
              {
                  _message = $"ERROR: Failed to start chat client: {e.Message}";
                  _isChatting = false;
              }
          }
      
          private void BroadcastMessage(string name, string message)
          {
              bool isMine = name.Equals(_username, StringComparison.OrdinalIgnoreCase);
      
              _messages.Add(new Message(name, message, isMine));
      
              // Inform blazor the UI needs updating
              InvokeAsync(StateHasChanged);
          }
      
          private async Task DisconnectAsync()
          {
              if (_isChatting)
              {
                  await SendAsync($"[Notice] {_username} left chat room.");
      
                  await _hubConnection.StopAsync();
                  await _hubConnection.DisposeAsync();
      
                  _hubConnection = null;
                  _isChatting = false;
              }
          }
      
          private async Task SendAsync(string message)
          {
              if (_isChatting && !string.IsNullOrWhiteSpace(message))
              {
                  await _hubConnection.SendAsync("Broadcast", _username, message);
      
                  _newMessage = string.Empty;
              }
          }
      
          private class Message
          {
              public Message(string username, string body, bool mine)
              {
                  Username = username;
                  Body = body;
                  Mine = mine;
              }
      
              public string Username { get; set; }
              public string Body { get; set; }
              public bool Mine { get; set; }
      
              public bool IsNotice => Body.StartsWith("[Notice]");
      
              public string CSS => Mine ? "sent" : "received";
          }
      }
      
    3. إضافة ترميز واجهة المستخدم قبل @code المقطع للتفاعل مع عميل SignalR.

      <h1>Blazor SignalR Chat Sample</h1>
      <hr />
      
      @if (!_isChatting)
      {
          <p>
              Enter your name to start chatting:
          </p>
      
          <input type="text" maxlength="32" @bind="@_username" />
          <button type="button" @onclick="@Chat"><span class="oi oi-chat" aria-hidden="true"></span> Chat!</button>
      
          // Error messages
          @if (_message != null)
          {
              <div class="invalid-feedback">@_message</div>
              <small id="emailHelp" class="form-text text-muted">@_message</small>
          }
      }
      else
      {
          // banner to show current user
          <div class="alert alert-secondary mt-4" role="alert">
              <span class="oi oi-person mr-2" aria-hidden="true"></span>
              <span>You are connected as <b>@_username</b></span>
              <button class="btn btn-sm btn-warning ml-md-auto" @onclick="@DisconnectAsync">Disconnect</button>
          </div>
          // display messages
          <div id="scrollbox">
              @foreach (var item in _messages)
              {
                  @if (item.IsNotice)
                  {
                      <div class="alert alert-info">@item.Body</div>
                  }
                  else
                  {
                      <div class="@item.CSS">
                          <div class="user">@item.Username</div>
                          <div class="msg">@item.Body</div>
                      </div>
                  }
              }
              <hr />
              <textarea class="input-lg" placeholder="enter your comment" @bind="@_newMessage"></textarea>
              <button class="btn btn-default" @onclick="@(() => SendAsync(_newMessage))">Send</button>
          </div>
      }
      
  6. تحديث NavMenu.razor المكون لإدراج مكون جديد NavLink لربط غرفة المحادثة تحت NavMenuCssClass.

    <li class="nav-item px-3">
        <NavLink class="nav-link" href="chatroom">
            <span class="oi oi-chat" aria-hidden="true"></span> Chat room
        </NavLink>
    </li>
    
  7. إضافة بعض فئات CSS إلى site.css الملف إلى نمط عناصر واجهة المستخدم في صفحة المحادثة.

    /* improved for chat text box */
    textarea {
        border: 1px dashed #888;
        border-radius: 5px;
        width: 80%;
        overflow: auto;
        background: #f7f7f7
    }
    
    /* improved for speech bubbles */
    .received, .sent {
        position: relative;
        font-family: arial;
        font-size: 1.1em;
        border-radius: 10px;
        padding: 20px;
        margin-bottom: 20px;
    }
    
    .received:after, .sent:after {
        content: '';
        border: 20px solid transparent;
        position: absolute;
        margin-top: -30px;
    }
    
    .sent {
        background: #03a9f4;
        color: #fff;
        margin-left: 10%;
        top: 50%;
        text-align: right;
    }
    
    .received {
        background: #4CAF50;
        color: #fff;
        margin-left: 10px;
        margin-right: 10%;
    }
    
    .sent:after {
        border-left-color: #03a9f4;
        border-right: 0;
        right: -20px;
    }
    
    .received:after {
        border-right-color: #4CAF50;
        border-left: 0;
        left: -20px;
    }
    
    /* div within bubble for name */
    .user {
        font-size: 0.8em;
        font-weight: bold;
        color: #000;
    }
    
    .msg {
        /*display: inline;*/
    }
    
  8. ثم اضغط F5 لتشغيل البرنامج. الآن، يمكنك بدء الدردشة:

    An animated chat between Bob and Alice is shown. Alice says Hello, Bob says Hi.

هل تواجه مشكلات؟ أبلغنا بها.

نشر إلى Azure

عند نشر التطبيق Blazor إلى خدمة التطبيقات Azure، نوصي باستخدام خدمة Azure SignalR. تسمح خدمة Azure SignalR بتوسيع تطبيق Blazor Server إلى عدد كبير من اتصالات SignalR المتزامنة. بالإضافة إلى ذلك، فإن الانتشار العالمي لخدمة SignalR ومراكز البيانات عالية الأداء تساعد بشكل كبير في تقليل الكمون بسبب الجغرافيا.

هام

في تطبيق خادم Blazor، يتم الاحتفاظ بحالات واجهة المستخدم على جانب الخادم، ما يعني أن جلسة عمل الخادم المثبتة مطلوبة للحفاظ على الحالة. إذا كان هناك خادم تطبيق واحد، يتم ضمان جلسات العمل المثبتة حسب التصميم. ومع ذلك، إذا كانت هناك خوادم تطبيقات متعددة، فهناك احتمالية أن تفاوض العميل والاتصال به قد ينتقل إلى خوادم مختلفة ما قد يؤدي إلى إدارة حالة واجهة مستخدم غير متسقة في تطبيق Blazor. ومن ثم، فمن المستحسن تمكين جلسات عمل الخادم المثبتة على النحو المبين أدناه في appsettings.json:

"Azure:SignalR:ServerStickyMode": "Required"
  1. انقر بزر الماوس الأيمن فوق المشروع ثم انتقل إلى نشر. استخدم الإعدادات التالية:

    • الهدف: Azure
    • هدف محدد: يتم دعم جميع أنواع خدمة تطبيقات Azure.
    • خدمة التطبيقات: إنشاء مثيل خدمة التطبيق أو تحديده.

    The animation shows selection of Azure as target, and then Azure App Serice as specific target.

  2. إضافة تبعية خدمة SignalR من Azure.

    بعد إنشاء ملف تعريف النشر، يمكنك مشاهدة رسالة توصية لإضافة خدمة SignalR من Azure ضمن تبعيات الخدمة. حدد تكوين لإنشاء خدمة SignalR من Azure جديدة أو حددها في الجزء .

    On Publish, the link to Configure is highlighted.

    ستقوم تبعية الخدمة بتنفيذ الأنشطة التالية لتمكين التطبيق من التبديل تلقائياً إلى خدمة Azure SignalR عند تشغيل Azure:

    • حدث HostingStartupAssembly لاستخدام Azure SignalR Service.
    • إضافة مرجع حزمة NuGet من خدمة Azure SignalR.
    • تحديث خصائص ملف التعريف لحفظ إعدادات التبعية.
    • تكوين مخزن أسرار وفقاً لاختيارك.
    • أضف التكوين في appsettings.js لجعل تطبيقك يستهدف خدمة Azure SignalR.

    On Summary of changes, the checkboxes are used to select all dependencies.

  3. انشر التطبيق.

    الآن التطبيق جاهز للنشر. عند الانتهاء من عملية النشر، يتم تشغيل التطبيق تلقائياً في مستعرض.

    إشعار

    قد يتطلب التطبيق بعض الوقت للبدء بسبب زمن بدء تشغيل نشر خدمة Azure App. يمكنك استخدام أدوات مصحح أخطاء المستعرض (عادة عن طريق الضغط على F12)للتأكد من إعادة توجيه حركة المرور إلى خدمة Azure SignalR.

    Blazor SignalR Chat Sample has a text box for your name, and a Chat! button to start a chat.

هل تواجه مشكلات؟ أبلغنا بها.

تمكين خدمة Azure SignalR للتطوير المحلي

  1. إضافة مرجع إلى SDK SignalR Azure باستخدام الأمر التالي.

    dotnet add package Microsoft.Azure.SignalR
    
  2. إضافة مكالمة إلى AddAzureSignalR() في كما هو موضح Startup.ConfigureServices() أدناه.

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSignalR().AddAzureSignalR();
        ...
    }
    
  3. تكوين سلسلة اتصال خدمة SignalR Azure إما في appsettings.jsأو باستخدام أداة "إدارة سرية".

إشعار

يمكن استبدال الخطوة 2 بتكوين استضافة مجموعات بدء التشغيل لاستخدام SIGNALR SDK.

  1. إضافة التكوين لتشغيل خدمة Azure SignalR في appsettings.json:

    "Azure": {
      "SignalR": {
        "Enabled": true,
        "ConnectionString": <your-connection-string>       
      }
    }
    
    
  2. قم بتكوين مجموعة بدء تشغيل الاستضافة لاستخدام Azure SignalR SDK. تحرير launchSettings.json وإضافة تكوين مثل المثال التالي داخل environmentVariables :

    "environmentVariables": {
        ...,
       "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.Azure.SignalR"
     }
    
    

هل تواجه مشكلات؟ أبلغنا بها.

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

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

الموارد الإضافية

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

في هذا البرنامج التعليمي، نتعلم طريقة القيام بما يأتي:

  • بناء غرفة دردشة بسيطة مع قالب تطبيق Blazor Server.
  • العمل مع مكونات Blazor.
  • استخدم معالجة الأحداث وربط البيانات في مكونات Razor.
  • نشر سريع إلى Azure App Service في Visual Studio.
  • ترحيل من SignalR المحلية إلى خدمة Azure SignalR.

اقرأ المزيد عن إمكانية التوافر العالي: