Programowanie i konfigurowanie w usłudze Azure Functions za pomocą usługi Azure SignalR Service

Aplikacje usługi Azure Functions mogą używać powiązań usługi Azure SignalR Service do dodawania możliwości w czasie rzeczywistym. Aplikacje klienckie używają zestawów SDK klienta dostępnych w kilku językach do nawiązywania połączenia z usługą Azure SignalR Service i odbierania komunikatów w czasie rzeczywistym.

W tym artykule opisano pojęcia dotyczące tworzenia i konfigurowania aplikacji funkcji platformy Azure zintegrowanej z usługą SignalR Service.

Konfiguracja usługi SignalR Service

Usługę Azure SignalR Service można skonfigurować w różnych trybach. W przypadku korzystania z usługi Azure Functions usługa musi być skonfigurowana w trybie bezserwerowym .

W witrynie Azure Portal znajdź stronę Ustawienia zasobu usługi SignalR Service. Ustaw tryb usługi na bezserwerowy.

Tryb usługi SignalR Service

Opracowywanie usługi Azure Functions

Bezserwerowa aplikacja w czasie rzeczywistym utworzona za pomocą usług Azure Functions i Azure SignalR Service wymaga co najmniej dwóch funkcji platformy Azure:

  • Funkcja wywoływana negotiate przez klienta w celu uzyskania prawidłowego tokenu dostępu usługi SignalR Service i adresu URL punktu końcowego.
  • Co najmniej jedna funkcja, która obsługuje komunikaty wysyłane z usługi SignalR Service do klientów.

Funkcja negocjacji

Aplikacja kliencka wymaga prawidłowego tokenu dostępu w celu nawiązania połączenia z usługą Azure SignalR Service. Token dostępu może być anonimowy lub uwierzytelniony w identyfikatorze użytkownika. Aplikacje usługi SignalR Service bezserwerowe wymagają punktu końcowego HTTP o nazwie negotiate w celu uzyskania tokenu i innych informacji o połączeniu, takich jak adres URL punktu końcowego usługi SignalR Service.

Użyj funkcji platformy Azure wyzwalanej przez protokół HTTP i powiązania wejściowego SignalRConnectionInfo , aby wygenerować obiekt informacji o połączeniu. Funkcja musi mieć trasę HTTP kończącą się na ./negotiate

W przypadku modelu opartego na klasach w języku C#nie potrzebujesz SignalRConnectionInfo powiązania danych wejściowych i możesz znacznie łatwiej dodawać oświadczenia niestandardowe. Aby uzyskać więcej informacji, zobacz Środowisko negocjacji w modelu opartym na klasach.

Aby uzyskać więcej informacji na temat negotiate funkcji, zobacz Programowanie w usłudze Azure Functions.

Aby dowiedzieć się, jak utworzyć uwierzytelniony token, zobacz Korzystanie z uwierzytelniania usługi App Service.

Obsługa komunikatów wysyłanych z usługi SignalR Service

SignalRTrigger Użyj powiązania do obsługi komunikatów wysyłanych z usługi SignalR Service. Powiadomienia można otrzymywać, gdy klienci wysyłają komunikaty lub klienci są połączeni lub rozłączeni.

Aby uzyskać więcej informacji, zobacz dokumentację powiązania wyzwalacza usługi SignalR Service.

Należy również skonfigurować punkt końcowy funkcji jako nadrzędny punkt końcowy, aby usługa wyzwalała funkcję w przypadku wystąpienia komunikatu od klienta. Aby uzyskać więcej informacji na temat konfigurowania nadrzędnych punktów końcowych, zobacz Upstream endpoints (Nadrzędne punkty końcowe).

Uwaga

Usługa SignalR Service nie obsługuje komunikatu StreamInvocation z klienta w trybie bezserwerowym.

Wysyłanie komunikatów i zarządzanie członkostwem w grupie

Użyj powiązania wyjściowego SignalR , aby wysyłać komunikaty do klientów połączonych z usługą Azure SignalR Service. Komunikaty można emitować do wszystkich klientów lub wysyłać je do podzbioru klientów. Na przykład wysyłaj komunikaty tylko do klientów uwierzytelnionych przy użyciu określonego identyfikatora użytkownika lub tylko do określonej grupy.

Użytkownicy mogą być dodawani do co najmniej jednej grupy. Możesz również użyć powiązania danych wyjściowych SignalR , aby dodać lub usunąć użytkowników do/z grup.

Aby uzyskać więcej informacji, zobacz dokumentację powiązania wyjściowego.SignalR

Koncentratory SignalR

Usługa SignalR ma koncepcję koncentratorów. Każde połączenie klienta i każdy komunikat wysyłany z usługi Azure Functions ma zakres do określonego centrum. Koncentratory mogą służyć jako sposób oddzielania połączeń i komunikatów do logicznych przestrzeni nazw.

Model oparty na klasach

Model oparty na klasach jest przeznaczony dla języka C#.

Model oparty na klasach zapewnia lepsze środowisko programowania, które może zastąpić powiązania wejściowe i wyjściowe usługi SignalR następującymi funkcjami:

  • Bardziej elastyczne negocjacje, wysyłanie komunikatów i zarządzanie środowiskami grup.
  • Obsługiwane są więcej funkcji zarządzania, w tym zamykanie połączeń, sprawdzanie, czy istnieje połączenie, użytkownik lub grupa.
  • Silnie typizowane centrum
  • Ujednolicona nazwa centrum i ustawienie parametry połączenia w jednym miejscu.

Poniższy kod przedstawia sposób pisania powiązań usługi SignalR w modelu opartym na klasach:

Najpierw zdefiniuj centrum pochodzące z klasy 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);
    }
}

W pliku Program.cs zarejestruj centrum bezserwerowe:

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

Doświadczenie negocjacji w modelu opartym na klasach

Zamiast używać powiązania [SignalRConnectionInfoInput]wejściowego usługi SignalR, negocjacje w modelu opartym na klasach mogą być bardziej elastyczne. Klasa ServerlessHub podstawowa ma metodę NegotiateAsync, która umożliwia użytkownikom dostosowywanie opcji negocjacji, takich jak userId, claimsitp.

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

Wysyłanie komunikatów i zarządzanie środowiskiem w modelu opartym na klasach

Możesz wysyłać komunikaty, zarządzać grupami lub zarządzać klientami, korzystając z elementów członkowskich dostarczonych przez klasę ServerlessHubbazową .

  • ServerlessHub.Clients do wysyłania komunikatów do klientów.
  • ServerlessHub.Groups do zarządzania połączeniami z grupami, takimi jak dodawanie połączeń do grup, usuwanie połączeń z grup.
  • ServerlessHub.UserGroups do zarządzania użytkownikami przy użyciu grup, takich jak dodawanie użytkowników do grup, usuwanie użytkowników z grup.
  • ServerlessHub.ClientManager do sprawdzania istnienia połączeń, zamykania połączeń itp.

Centrum silnie typizowane

Silnie typizowane centrum umożliwia używanie silnie typiowanych metod podczas wysyłania komunikatów do klientów. Aby użyć silnie typizowanego centrum w modelu opartym na klasach, wyodrębnij metody klienta do interfejsu Ti utwórz klasę centrum pochodzącą z ServerlessHub<T>klasy .

Poniższy kod jest przykładem interfejsu dla metod klienta.

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

Następnie można użyć silnie typiowanych metod w następujący sposób:

[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));
    }
}

Uwaga

Kompletny przykład projektu można pobrać z usługi GitHub.

Ujednolicona nazwa centrum i ustawienie parametry połączenia w jednym miejscu

  • Nazwa klasy centrum bezserwerowego jest automatycznie używana jako HubName.
  • Być może atrybut SignalRConnection używany w klasach koncentratora bezserwerowego wygląda następująco:
    [SignalRConnection("AzureSignalRConnectionString")]
    public class Functions : ServerlessHub<IChatClient>
    
    Umożliwia dostosowanie miejsca, w którym znajduje się parametry połączenia dla koncentratora bezserwerowego. Jeśli jest nieobecny, zostanie użyta wartość AzureSignalRConnectionString domyślna.

Ważne

Wyzwalacze usługi SignalR i koncentratory bezserwerowe są niezależne. W związku z tym nazwa klasy bezserwerowego centrum i SignalRConnection atrybutu nie zmienia ustawień wyzwalaczy usługi SignalR, mimo że używasz wyzwalaczy SignalR wewnątrz bezserwerowego koncentratora.

Programowanie klientów

Aplikacje klienckie usługi SignalR mogą używać zestawu SDK klienta SignalR w jednym z kilku języków, aby łatwo łączyć się z usługą Azure SignalR Service i odbierać komunikaty z usługi Azure SignalR Service.

Konfigurowanie połączenia klienta

Aby nawiązać połączenie z usługą SignalR Service, klient musi wykonać pomyślne negocjacje połączenia, które składają się z następujących kroków:

  1. Prześlij żądanie do punktu końcowego HTTP omówionego powyżej, negotiate aby uzyskać prawidłowe informacje o połączeniu
  2. Połączenie do usługi SignalR Service przy użyciu adresu URL punktu końcowego usługi i tokenu dostępu uzyskanego z punktu końcowego negotiate

Zestawy SDK klienta usługi SignalR zawierają już logikę wymaganą do wykonania uzgadniania negocjacji. Przekaż adres URL punktu końcowego negocjacji, minus negotiate segment, do zestawu HubConnectionBuilderSDK . Oto przykład w języku JavaScript:

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

Zgodnie z konwencją zestaw SDK automatycznie dołącza /negotiate do adresu URL i używa go do rozpoczęcia negocjacji.

Uwaga

Jeśli używasz zestawu JAVAScript/TypeScript SDK w przeglądarce, musisz włączyć współużytkowanie zasobów między źródłami (CORS) w aplikacji funkcji.

Aby uzyskać więcej informacji na temat korzystania z zestawu SDK klienta usługi SignalR, zobacz dokumentację dotyczącą języka:

Wysyłanie komunikatów z klienta do usługi

Jeśli skonfigurowano nadrzędny zasób usługi SignalR, możesz wysyłać komunikaty z klienta do usługi Azure Functions przy użyciu dowolnego klienta usługi SignalR. Oto przykład w języku JavaScript:

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

Konfiguracja usługi Azure Functions

Aplikacje funkcji platformy Azure, które integrują się z usługą Azure SignalR Service, można wdrażać jak każda typowa aplikacja funkcji platformy Azure, korzystając z technik, takich jak ciągłe wdrażanie, wdrażanie zip i uruchamianie z pakietu.

Istnieje jednak kilka szczególnych zagadnień dotyczących aplikacji korzystających z powiązań usługi SignalR Service. Jeśli klient działa w przeglądarce, należy włączyć mechanizm CORS. Jeśli aplikacja wymaga uwierzytelniania, możesz zintegrować punkt końcowy negocjacji z uwierzytelnianiem usługi App Service.

Włączanie mechanizmu CORS

Klient JavaScript/TypeScript wysyła żądanie HTTP do funkcji negocjacji w celu zainicjowania negocjacji połączenia. Jeśli aplikacja kliencka jest hostowana w innej domenie niż aplikacja funkcji platformy Azure, udostępnianie zasobów między źródłami (CORS) musi być włączone w aplikacji funkcji lub przeglądarka zablokuje żądania.

Localhost

Podczas uruchamiania aplikacji funkcji na komputerze lokalnym można dodać sekcję Host do local.settings.json , aby włączyć mechanizm CORS. Host W sekcji dodaj dwie właściwości:

  • CORS — wprowadź podstawowy adres URL, który jest źródłem aplikacji klienckiej
  • CORSCredentials — ustaw ją tak, aby true zezwalała na żądania "withCredentials"

Przykład:

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

Chmura — mechanizm CORS usługi Azure Functions

Aby włączyć mechanizm CORS w aplikacji funkcji platformy Azure, przejdź do ekranu konfiguracji mechanizmu CORS na karcie Funkcje platformy aplikacji funkcji w witrynie Azure Portal.

Uwaga

Konfiguracja mechanizmu CORS nie jest jeszcze dostępna w planie użycia systemu Linux usługi Azure Functions. Użyj usługi Azure API Management , aby włączyć mechanizm CORS.

Mechanizm CORS z poświadczeniami Access-Control-Allow-Credentials musi być włączony, aby klient usługi SignalR mógł wywołać funkcję negocjacji. Aby ją włączyć, zaznacz pole wyboru.

W sekcji Dozwolone źródła dodaj wpis z podstawowym adresem URL aplikacji internetowej.

Konfigurowanie mechanizmu CORS

Chmura — Azure API Management

Usługa Azure API Management udostępnia bramę interfejsu API, która dodaje możliwości do istniejących usług zaplecza. Można go użyć do dodawania mechanizmu CORS do aplikacji funkcji. Oferuje warstwę zużycia z cenami płatności za akcję i miesięcznym bezpłatnym przyznaniem.

Zapoznaj się z dokumentacją usługi API Management, aby uzyskać informacje na temat importowania aplikacji funkcji platformy Azure. Po zaimportowaniu można dodać zasady ruchu przychodzącego, aby włączyć mechanizm CORS z obsługą mechanizmu 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>

Skonfiguruj klientów usługi SignalR tak, aby używali adresu URL usługi API Management.

Korzystanie z uwierzytelniania usługi App Service

Usługa Azure Functions ma wbudowane uwierzytelnianie, które obsługuje popularnych dostawców, takich jak Facebook, Twitter, Konto Microsoft, Google i Microsoft Entra ID. Tę funkcję można zintegrować z powiązaniem SignalRConnectionInfo , aby utworzyć połączenia z usługą Azure SignalR Service uwierzytelnioną w identyfikatorze użytkownika. Aplikacja może wysyłać komunikaty przy użyciu SignalR powiązania danych wyjściowych, które są przeznaczone dla tego identyfikatora użytkownika.

W witrynie Azure Portal na karcie Funkcje platformy aplikacji funkcji otwórz okno Ustawienia uwierzytelniania/autoryzacji. Postępuj zgodnie z dokumentacją uwierzytelniania usługi App Service, aby skonfigurować uwierzytelnianie przy użyciu wybranego dostawcy tożsamości.

Po skonfigurowaniu uwierzytelnione żądania HTTP zawierają x-ms-client-principal-name odpowiednio x-ms-client-principal-id i nagłówki zawierające nazwę użytkownika i identyfikator użytkownika tożsamości uwierzytelnionej.

Te nagłówki można użyć w konfiguracji powiązania, SignalRConnectionInfo aby utworzyć uwierzytelnione połączenia. Oto przykładowa funkcja negocjacji języka C#, która używa nagłówka 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;
}

Następnie możesz wysyłać komunikaty do tego użytkownika, ustawiając UserId właściwość komunikatu usługi 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 }
        });
}

Aby uzyskać informacje na temat innych języków, zobacz dokumentację powiązań usługi Azure SignalR Service dla usługi Azure Functions.

Następne kroki

Z tego artykułu dowiesz się, jak opracowywać i konfigurować bezserwerowe aplikacje usługi SignalR Service przy użyciu usługi Azure Functions. Spróbuj samodzielnie utworzyć aplikację przy użyciu jednego z przewodników Szybki start lub samouczków na stronie przeglądu usługi SignalR Service.