تطوير وتكوين وظائف Azure مع خدمة Azure SignalR

يمكن لتطبيقات Azure Functions استخدام روابط خدمة Azure SignalR لإضافة قدرات في الوقت الحقيقي. تستخدم تطبيقات العميل حزم SDK للعميل المتوفرة بعدة لغات للاتصال بخدمة Azure SignalR وتلقي رسائل في الوقت الفعلي.

توضح هذه المقالة مفاهيم تطوير وتكوين تطبيق Azure Function المدمج مع SignalR Service.

تكوين خدمة SignalR

يمكن تكوين خدمة Azure SignalR في أوضاع مختلفة. عند استخدامها مع Azure Functions، يجب تكوين الخدمة في وضع Serverless .

في مدخل Microsoft Azure، حدد موقع صفحة الإعدادات لمورد SignalR Service. تعيين وضع الخدمة إلى بلا خادم.

وضع خدمة SignalR

تطوير Azure Functions

يتطلب تطبيق بلا خادم في الوقت الحقيقي تم إنشاؤه باستخدام Azure Functions وAzure SignalR Service اثنين على الأقل من وظائف Azure:

  • negotiate دالة يستدعيها العميل للحصول على رمز مميز صالح للوصول إلى SignalR Service وعنوان URL لنقطة النهاية.
  • دالة واحدة أو أكثر تعالج الرسائل المرسلة من SignalR Service إلى العملاء.

دالة التفاوض

يتطلب تطبيق العميل رمز وصول صالحا للاتصال بخدمة Azure SignalR. يمكن أن يكون الرمز المميز للوصول مجهولا أو مصادقا عليه لمعرف مستخدم. تتطلب تطبيقات خدمة SignalR بلا خادم نقطة نهاية HTTP تسمى negotiate للحصول على رمز مميز ومعلومات اتصال أخرى، مثل عنوان URL لنقطة نهاية SignalR Service.

استخدم وظيفة Azure التي تم تشغيلها من قبل HTTP وربط SignalRConnectionInfo الإدخال لإنشاء كائن معلومات الاتصال. يجب أن تحتوي الدالة على مسار HTTP ينتهي ب /negotiate.

مع النموذج المستند إلى الفئة في C#، لا تحتاج إلى SignalRConnectionInfo ربط الإدخال ويمكنك إضافة مطالبات مخصصة بسهولة أكبر. لمزيد من المعلومات، راجع تجربة التفاوض في النموذج المستند إلى الفئة.

لمزيد من المعلومات حول الدالة negotiate ، راجع تطوير Azure Functions.

لمعرفة كيفية إنشاء رمز مميز مصادق عليه، راجع استخدام مصادقة خدمة التطبيقات.

معالجة الرسائل المرسلة من SignalR Service

SignalRTrigger استخدم الربط لمعالجة الرسائل المرسلة من SignalR Service. يمكنك الحصول على إعلام عندما يرسل العملاء رسائل أو يتم توصيل العملاء أو قطع اتصالهم.

لمزيد من المعلومات، راجع مرجع ربط مشغل SignalR Service.

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

إشعار

لا تدعم SignalR Service الرسالة الواردة StreamInvocation من عميل في وضع بلا خادم.

إرسال الرسائل وإدارة عضوية المجموعة

SignalR استخدم ربط الإخراج لإرسال رسائل إلى العملاء المتصلين بخدمة Azure SignalR. يمكنك بث الرسائل إلى جميع العملاء، أو يمكنك إرسالها إلى مجموعة فرعية من العملاء. على سبيل المثال، أرسل رسائل فقط إلى العملاء المصادق عليهم باستخدام معرف مستخدم معين، أو إلى مجموعة معينة فقط.

يمكن إضافة المستخدمين إلى مجموعة واحدة أو أكثر. يمكنك أيضا استخدام SignalR ربط الإخراج لإضافة مستخدمين إلى/من المجموعات أو إزالتهم منها.

لمزيد من المعلومات، راجع SignalR مرجع ربط الإخراج.

مراكز SignalR

لدى SignalR مفهوم المراكز. يتم تحديد نطاق كل اتصال عميل وكل رسالة يتم إرسالها من Azure Functions إلى مركز معين. يمكنك استخدام المراكز كطريقة لفصل الاتصالات والرسائل إلى مساحات أسماء منطقية.

نموذج يستند إلى الفئة

النموذج المستند إلى الفئة مخصص ل C#‎.

يوفر النموذج المستند إلى الفئة تجربة برمجة أفضل، والتي يمكن أن تحل محل روابط الإدخال والإخراج SignalR، بالميزات التالية:

  • التفاوض أكثر مرونة، وإرسال الرسائل وإدارة تجربة المجموعات.
  • يتم دعم المزيد من وظائف الإدارة، بما في ذلك إغلاق الاتصالات، والتحقق مما إذا كان هناك اتصال أو مستخدم أو مجموعة.
  • مركز مكتوب بقوة
  • اسم المركز الموحد وإعداد سلسلة الاتصال في مكان واحد.

توضح التعليمات البرمجية التالية كيفية كتابة روابط SignalR في نموذج يستند إلى الفئة:

أولا، حدد المركز المشتق من فئة ServerlessHub:

[SignalRConnection("AzureSignalRConnectionString")]
public class Functions : ServerlessHub
{
    private const string HubName = nameof(Functions); // Used by SignalR trigger only

    public Functions(IServiceProvider serviceProvider) : base(serviceProvider)
    {
    }

    [Function("negotiate")]
    public async Task<HttpResponseData> Negotiate([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req)
    {
        var negotiateResponse = await NegotiateAsync(new() { UserId = req.Headers.GetValues("userId").FirstOrDefault() });
        var response = req.CreateResponse();
        response.WriteBytes(negotiateResponse.ToArray());
        return response;
    }

    [Function("Broadcast")]
    public Task Broadcast(
    [SignalRTrigger(HubName, "messages", "broadcast", "message")] SignalRInvocationContext invocationContext, string message)
    {
        return Clients.All.SendAsync("newMessage", new NewMessage(invocationContext, message));
    }

    [Function("JoinGroup")]
    public Task JoinGroup([SignalRTrigger(HubName, "messages", "JoinGroup", "connectionId", "groupName")] SignalRInvocationContext invocationContext, string connectionId, string groupName)
    {
        return Groups.AddToGroupAsync(connectionId, groupName);
    }
}

في ملف Program.cs ، سجل مركز بلا خادم:

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(b => b.Services
        .AddServerlessHub<Functions>())
    .Build();

تجربة التفاوض في النموذج القائم على الفئة

بدلا من استخدام ربط [SignalRConnectionInfoInput]إدخال SignalR، يمكن أن يكون التفاوض في النموذج المستند إلى الفئة أكثر مرونة. تحتوي الفئة ServerlessHub الأساسية على أسلوب NegotiateAsync، والذي يسمح للمستخدمين بتخصيص خيارات التفاوض مثل userId، claims، وما إلى ذلك.

Task<BinaryData> NegotiateAsync(NegotiationOptions? options = null)

إرسال الرسائل وإدارة الخبرة في النموذج المستند إلى الفئة

يمكنك إرسال رسائل أو إدارة المجموعات أو إدارة العملاء عن طريق الوصول إلى الأعضاء الذين توفرهم الفئة ServerlessHubالأساسية .

  • ServerlessHub.Clients لإرسال رسائل إلى العملاء.
  • ServerlessHub.Groups لإدارة الاتصالات مع المجموعات، مثل إضافة اتصالات إلى المجموعات، وإزالة الاتصالات من المجموعات.
  • ServerlessHub.UserGroups لإدارة المستخدمين الذين لديهم مجموعات، مثل إضافة مستخدمين إلى المجموعات، وإزالة المستخدمين من المجموعات.
  • ServerlessHub.ClientManager للتحقق من وجود الاتصالات، وإغلاق الاتصالات، وما إلى ذلك.

مركز مكتوب بقوة

يسمح لك المركز الذي تم كتابته بقوة باستخدام أساليب مكتوبة بقوة عند إرسال رسائل إلى العملاء. لاستخدام لوحة وصل مكتوبة بقوة في نموذج يستند إلى الفئة، استخرج أساليب العميل في واجهة T، واجعل فئة المركز مشتقة من ServerlessHub<T>.

التعليمات البرمجية التالية هي نموذج واجهة لأساليب العميل.

public interface IChatClient
{
    Task newMessage(NewMessage message);
}

ثم يمكنك استخدام الأساليب مكتوبة بقوة كما يلي:

[SignalRConnection("AzureSignalRConnectionString")]
public class Functions : ServerlessHub<IChatClient>
{
    private const string HubName = nameof(Functions);  // Used by SignalR trigger only

    public Functions(IServiceProvider serviceProvider) : base(serviceProvider)
    {
    }

    [Function("Broadcast")]
    public Task Broadcast(
    [SignalRTrigger(HubName, "messages", "broadcast", "message")] SignalRInvocationContext invocationContext, string message)
    {
        return Clients.All.newMessage(new NewMessage(invocationContext, message));
    }
}

إشعار

يمكنك الحصول على عينة مشروع كاملة من GitHub.

اسم المركز الموحد وإعداد سلسلة الاتصال في مكان واحد

  • يتم استخدام اسم فئة المركز بلا خادم تلقائيا ك HubName.
  • ربما لاحظت السمة SignalRConnection المستخدمة في فئات المركز بلا خادم كما يلي:
    [SignalRConnection("AzureSignalRConnectionString")]
    public class Functions : ServerlessHub<IChatClient>
    
    يسمح لك بتخصيص مكان سلسلة الاتصال لمركز بلا خادم. إذا لم يكن موجودا، يتم استخدام القيمة AzureSignalRConnectionString الافتراضية.

هام

مشغلات SignalR ومراكز بلا خادم مستقلة. لذلك، لا يغير اسم فئة المركز والسمة SignalRConnection بلا خادم إعدادات مشغلات SignalR، على الرغم من أنك تستخدم مشغلات SignalR داخل المركز بلا خادم.

تطوير العميل

يمكن لتطبيقات عميل SignalR استخدام SDK لعميل SignalR بإحدى اللغات المتعددة للاتصال بسهولة ب Azure SignalR Service وتلقيها.

تكوين اتصال عميل

للاتصال بخدمة SignalR، يجب على العميل إكمال تفاوض اتصال ناجح يتكون من الخطوات التالية:

  1. تقديم طلب إلى نقطة نهاية HTTP التي negotiate تمت مناقشتها أعلاه للحصول على معلومات اتصال صالحة
  2. الاتصال إلى SignalR Service باستخدام عنوان URL لنقطة نهاية الخدمة والرمز المميز للوصول الذي تم الحصول عليه من negotiate نقطة النهاية

تحتوي SDKs لعميل SignalR بالفعل على المنطق المطلوب لإجراء تأكيد اتصال التفاوض. مرر عنوان URL لنقطة نهاية التفاوض، مطروحا منه negotiate الجزء، إلى SDK.HubConnectionBuilder فيما يلي مثال في JavaScript:

const connection = new signalR.HubConnectionBuilder()
  .withUrl("https://my-signalr-function-app.azurewebsites.net/api")
  .build();

حسب الاصطلاح، تلحق /negotiate SDK تلقائيا بعنوان URL وتستخدمه لبدء التفاوض.

إشعار

إذا كنت تستخدم JavaScript/TypeScript SDK في مستعرض، فأنت بحاجة إلى تمكين مشاركة الموارد عبر المنشأ (CORS) على تطبيق الوظائف.

لمزيد من المعلومات حول كيفية استخدام SDK لعميل SignalR، راجع وثائق لغتك:

إرسال رسائل من عميل إلى الخدمة

إذا قمت بتكوين المصدر لمورد SignalR الخاص بك، يمكنك إرسال رسائل من عميل إلى Azure Functions باستخدام أي عميل SignalR. فيما يلي مثال في JavaScript:

connection.send("method1", "arg1", "arg2");

تكوين Azure Functions

يمكن نشر تطبيقات Azure Function التي تتكامل مع Azure SignalR Service مثل أي تطبيق Azure Function نموذجي، باستخدام تقنيات مثل النشر المستمر والنشر المضغوط والتشغيل من الحزمة.

ومع ذلك، هناك بعض الاعتبارات الخاصة للتطبيقات التي تستخدم روابط SignalR Service. إذا كان العميل يعمل في مستعرض، يجب تمكين CORS. وإذا كان التطبيق يتطلب مصادقة، يمكنك دمج نقطة نهاية التفاوض مع App Service Authentication.

تمكين CORS

يقوم عميل JavaScript/TypeScript بإجراء طلب HTTP إلى وظيفة التفاوض لبدء تفاوض الاتصال. عند استضافة تطبيق العميل على مجال مختلف عن تطبيق Azure Function، يجب تمكين مشاركة الموارد عبر المنشأ (CORS) على تطبيق الوظائف، وإلا سيحظر المستعرض الطلبات.

Localhost

عند تشغيل تطبيق الوظائف على الكمبيوتر المحلي، يمكنك إضافة Host قسم إلى local.settings.json لتمكين CORS. في Host القسم ، أضف خاصيتين:

  • CORS - أدخل عنوان URL الأساسي الذي هو الأصل لتطبيق العميل
  • CORSCredentials - قم بتعيينه إلى true للسماح بطلبات "withCredentials"

مثال:

{
  "IsEncrypted": false,
  "Values": {
    // values
  },
  "Host": {
    "CORS": "http://localhost:8080",
    "CORSCredentials": true
  }
}

Cloud - Azure Functions CORS

لتمكين CORS على تطبيق Azure Function، انتقل إلى شاشة تكوين CORS ضمن علامة التبويب Platform features لتطبيق Function في مدخل Microsoft Azure.

إشعار

تكوين CORS غير متوفر بعد في خطة استهلاك Azure Functions Linux. استخدم Azure API Management لتمكين CORS.

يجب تمكين CORS مع Access-Control-Allow-Credentials لعميل SignalR لاستدعاء دالة التفاوض. لتمكينه، حدد خانة الاختيار.

في قسم الأصول المسموح بها، أضف إدخالا باستخدام عنوان URL الأساسي الأصل لتطبيق الويب الخاص بك.

تكوين CORS

السحابة - إدارة واجهة برمجة تطبيقات Azure

توفر إدارة واجهة برمجة تطبيقات Azure بوابة واجهة برمجة التطبيقات التي تضيف قدرات إلى الخدمات الخلفية الموجودة. يمكنك استخدامه لإضافة CORS إلى تطبيق الوظائف. ويوفر مستوى استهلاك مع تسعير الدفع لكل إجراء ومنحة مجانية شهرية.

راجع وثائق إدارة واجهة برمجة التطبيقات للحصول على معلومات حول كيفية استيراد تطبيق Azure Function. بمجرد الاستيراد، يمكنك إضافة نهج وارد لتمكين CORS مع دعم Access-Control-Allow-Credentials.

<cors allow-credentials="true">
  <allowed-origins>
    <origin>https://azure-samples.github.io</origin>
  </allowed-origins>
  <allowed-methods>
    <method>GET</method>
    <method>POST</method>
  </allowed-methods>
  <allowed-headers>
    <header>*</header>
  </allowed-headers>
  <expose-headers>
    <header>*</header>
  </expose-headers>
</cors>

تكوين عملاء SignalR لاستخدام عنوان URL لإدارة واجهة برمجة التطبيقات.

استخدام مصادقة App Service

تحتوي Azure Functions على مصادقة مضمنة، تدعم موفري الخدمات الشائعين مثل Facebook وTwitter وحساب Microsoft وGoogle ومعرف Microsoft Entra. يمكن دمج هذه الميزة SignalRConnectionInfo مع الربط لإنشاء اتصالات بخدمة Azure SignalR التي تمت مصادقتها على معرف مستخدم. يمكن للتطبيق الخاص بك إرسال رسائل باستخدام SignalR ربط الإخراج المستهدف لمعرف المستخدم هذا.

في مدخل Microsoft Azure، في علامة التبويب Function app's Platform features ، افتح نافذة Authentication/authorization settings. اتبع وثائق App Service Authentication لتكوين المصادقة باستخدام موفر هوية من اختيارك.

بمجرد التكوين، تتضمن x-ms-client-principal-name طلبات HTTP المصادق عليها وعناوين x-ms-client-principal-id تحتوي على اسم المستخدم ومعرف المستخدم للهوية المصادق عليها، على التوالي.

يمكنك استخدام هذه العناوين في تكوين الربط لإنشاء SignalRConnectionInfo اتصالات مصادق عليها. فيما يلي مثال على دالة التفاوض C# التي تستخدم x-ms-client-principal-id العنوان.

[FunctionName("negotiate")]
public static SignalRConnectionInfo Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req,
    [SignalRConnectionInfo
        (HubName = "chat", UserId = "{headers.x-ms-client-principal-id}")]
        SignalRConnectionInfo connectionInfo)
{
    // connectionInfo contains an access key token with a name identifier claim set to the authenticated user
    return connectionInfo;
}

يمكنك بعد ذلك إرسال رسائل إلى هذا المستخدم عن طريق تعيين UserId خاصية رسالة SignalR.

[FunctionName("SendMessage")]
public static Task SendMessage(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post")]object message,
    [SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages)
{
    return signalRMessages.AddAsync(
        new SignalRMessage
        {
            // the message will only be sent to these user IDs
            UserId = "userId1",
            Target = "newMessage",
            Arguments = new [] { message }
        });
}

للحصول على معلومات حول اللغات الأخرى، راجع ارتباطات خدمة Azure SignalR لمرجع Azure Functions.

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

في هذه المقالة، ستتعلم كيفية تطوير وتكوين تطبيقات SignalR Service بلا خادم باستخدام Azure Functions. حاول إنشاء تطبيق بنفسك باستخدام أحد البدايات السريعة أو البرامج التعليمية في صفحة نظرة عامة على SignalR Service.