Azure Functions-utveckling och -konfiguration med Azure SignalR Service
Azure Functions-program kan använda Azure SignalR Service-bindningar för att lägga till realtidsfunktioner. Klientprogram använder klient-SDK:er som är tillgängliga på flera språk för att ansluta till Azure SignalR Service och ta emot realtidsmeddelanden.
I den här artikeln beskrivs begreppen för att utveckla och konfigurera en Azure-funktionsapp som är integrerad med SignalR Service.
SignalR Service-konfiguration
Azure SignalR Service kan konfigureras i olika lägen. När den används med Azure Functions måste tjänsten konfigureras i serverlöst läge.
I Azure-portalen letar du upp sidan Inställningar för din SignalR Service-resurs. Ange Tjänstläge till Serverlös.
Azure Functions-utveckling
Ett serverlöst realtidsprogram som skapats med Azure Functions och Azure SignalR Service kräver minst två Azure Functions:
- En
negotiate
funktion som klienten anropar för att hämta en giltig SignalR Service-åtkomsttoken och slutpunkts-URL. - En eller flera funktioner som hanterar meddelanden som skickas från SignalR Service till klienter.
Förhandlingsfunktion
Ett klientprogram kräver en giltig åtkomsttoken för att ansluta till Azure SignalR Service. En åtkomsttoken kan vara anonym eller autentiserad till ett användar-ID. Serverlösa SignalR Service-program kräver en HTTP-slutpunkt med namnet negotiate
för att hämta en token och annan anslutningsinformation, till exempel SignalR-tjänstens slutpunkts-URL.
Använd en HTTP-utlöst Azure-funktion och indatabindningen SignalRConnectionInfo
för att generera anslutningsinformationsobjektet. Funktionen måste ha en HTTP-väg som slutar i /negotiate
.
Med klassbaserad modell i C# behöver du inte indatabindningen SignalRConnectionInfo
och kan lägga till anpassade anspråk mycket enklare. Mer information finns i Förhandlingsupplevelse i klassbaserad modell.
Mer information om funktionen finns i negotiate
Azure Functions-utveckling.
Information om hur du skapar en autentiserad token finns i Använda App Service-autentisering.
Hantera meddelanden som skickas från SignalR Service
Använd bindningen SignalRTrigger
för att hantera meddelanden som skickas från SignalR Service. Du kan få ett meddelande när klienter skickar meddelanden eller klienter ansluts eller kopplas från.
Mer information finns i referensen för SignalR Service-utlösarbindning.
Du måste också konfigurera funktionsslutpunkten som en överordnad slutpunkt så att tjänsten utlöser funktionen när det finns ett meddelande från en klient. Mer information om hur du konfigurerar överordnade slutpunkter finns i Överordnade slutpunkter.
Kommentar
SignalR Service stöder inte meddelandet StreamInvocation
från en klient i serverlöst läge.
Skicka meddelanden och hantera gruppmedlemskap
Använd utdatabindningen SignalR
för att skicka meddelanden till klienter som är anslutna till Azure SignalR Service. Du kan skicka meddelanden till alla klienter eller skicka dem till en delmängd av klienterna. Du kan till exempel bara skicka meddelanden till klienter som autentiserats med ett specifikt användar-ID eller endast till en viss grupp.
Användare kan läggas till i en eller flera grupper. Du kan också använda utdatabindningen SignalR
för att lägga till eller ta bort användare till/från grupper.
Mer information finns i referensen för SignalR
utdatabindning.
SignalR Hubs
SignalR har ett begrepp om hubbar. Varje klientanslutning och varje meddelande som skickas från Azure Functions är begränsad till en specifik hubb. Du kan använda hubbar som ett sätt att separera dina anslutningar och meddelanden i logiska namnområden.
Klassbaserad modell
Den klassbaserade modellen är dedikerad för C#.
Den klassbaserade modellen ger bättre programmeringsupplevelse, som kan ersätta SignalR-indata- och utdatabindningar med följande funktioner:
- Mer flexibla förhandlingar, sändning av meddelanden och hantering av grupper.
- Fler hanteringsfunktioner stöds, inklusive att stänga anslutningar, kontrollera om det finns en anslutning, användare eller grupp.
- Starkt skriven hubb
- Enhetligt hubbnamn och niska veze inställning på ett ställe.
Följande kod visar hur du skriver SignalR-bindningar i klassbaserad modell:
För det första definierar du din hubb som härletts från en klass 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);
}
}
I Program.cs-filen registrerar du din serverlösa hubb:
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults(b => b.Services
.AddServerlessHub<Functions>())
.Build();
Förhandlingsupplevelse i klassbaserad modell
I stället för att använda SignalR-indatabindning [SignalRConnectionInfoInput]
kan förhandling i klassbaserad modell vara mer flexibel. Basklassen ServerlessHub
har en metod NegotiateAsync
, som gör det möjligt för användare att anpassa förhandlingsalternativ som userId
, claims
osv.
Task<BinaryData> NegotiateAsync(NegotiationOptions? options = null)
Skicka meddelanden och hantera upplevelsen i klassbaserad modell
Du kan skicka meddelanden, hantera grupper eller hantera klienter genom att komma åt de medlemmar som tillhandahålls av basklassen ServerlessHub
.
ServerlessHub.Clients
för att skicka meddelanden till klienter.ServerlessHub.Groups
för att hantera anslutningar med grupper, till exempel lägga till anslutningar till grupper, ta bort anslutningar från grupper.ServerlessHub.UserGroups
för att hantera användare med grupper, till exempel lägga till användare i grupper, ta bort användare från grupper.ServerlessHub.ClientManager
för att kontrollera anslutningens existens, stänga anslutningar osv.
Starkt skriven hubb
Med en starkt typad hubb kan du använda starkt skrivna metoder när du skickar meddelanden till klienter. Om du vill använda starkt typad hubb i klassbaserad modell extraherar du klientmetoder till ett gränssnitt T
och gör hubbklassen härledd från ServerlessHub<T>
.
Följande kod är ett gränssnittsexempel för klientmetoder.
public interface IChatClient
{
Task newMessage(NewMessage message);
}
Sedan kan du använda de starkt inskrivna metoderna på följande sätt:
[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));
}
}
Kommentar
Du kan hämta ett fullständigt projektexempel från GitHub.
Enhetligt hubbnamn och niska veze inställning på ett ställe
- Klassnamnet för den serverlösa hubben används automatiskt som
HubName
. - Du kanske har lagt märke till attributet
SignalRConnection
som används i serverlösa hubbklasser på följande sätt:
Det gör att du kan anpassa var niska veze för serverlös hubb finns. Om den saknas används standardvärdet[SignalRConnection("AzureSignalRConnectionString")] public class Functions : ServerlessHub<IChatClient>
AzureSignalRConnectionString
.
Viktigt!
SignalR-utlösare och serverlösa hubbar är oberoende. Därför ändrar inte klassnamnet för serverlös hubb och SignalRConnection
attribut inställningarna för SignalR-utlösare, även om du använder SignalR-utlösare i den serverlösa hubben.
Klientutveckling
SignalR-klientprogram kan använda SignalR-klient-SDK på ett av flera språk för att enkelt ansluta till och ta emot meddelanden från Azure SignalR Service.
Konfigurera en klientanslutning
För att ansluta till SignalR Service måste en klient slutföra en lyckad anslutningsförhandling som består av följande steg:
- Skicka en begäran till
negotiate
HTTP-slutpunkten som beskrivs ovan för att hämta giltig anslutningsinformation - Ansluta till SignalR Service med hjälp av tjänstens slutpunkts-URL och åtkomsttoken som hämtats från
negotiate
slutpunkten
SignalR-klient-SDK:er innehåller redan den logik som krävs för att utföra handskakningen för förhandlingen. Skicka förhandlingsslutpunktens URL, minus negotiate
segmentet, till SDK:ens HubConnectionBuilder
. Här är ett exempel i JavaScript:
const connection = new signalR.HubConnectionBuilder()
.withUrl("https://my-signalr-function-app.azurewebsites.net/api")
.build();
Enligt konventionen läggs SDK automatiskt till /negotiate
i URL:en och använder den för att påbörja förhandlingen.
Kommentar
Om du använder JavaScript/TypeScript SDK i en webbläsare måste du aktivera resursdelning mellan ursprung (CORS) i funktionsappen.
Mer information om hur du använder SignalR-klient-SDK finns i dokumentationen för ditt språk:
Skicka meddelanden från en klient till tjänsten
Om du har konfigurerat uppströms för din SignalR-resurs kan du skicka meddelanden från en klient till dina Azure Functions med valfri SignalR-klient. Här är ett exempel i JavaScript:
connection.send("method1", "arg1", "arg2");
Azure Functions-konfiguration
Azure Function-appar som integreras med Azure SignalR Service kan distribueras som alla vanliga Azure-funktionsappar med hjälp av tekniker som kontinuerlig distribution, zip-distribution och körning från paket.
Det finns dock ett par särskilda överväganden för appar som använder SignalR Service-bindningar. Om klienten körs i en webbläsare måste CORS vara aktiverat. Och om appen kräver autentisering kan du integrera förhandlingsslutpunkten med App Service-autentisering.
Aktivera CORS
JavaScript/TypeScript-klienten skickar HTTP-begäran till förhandlingsfunktionen för att initiera anslutningsförhandlingen. När klientprogrammet finns på en annan domän än Azure-funktionsappen måste cors (cross-origin resource sharing) aktiveras i funktionsappen, annars blockerar webbläsaren begäranden.
Localhost
När du kör funktionsappen på den lokala datorn kan du lägga till ett Host
avsnitt i local.settings.json för att aktivera CORS. I avsnittet Host
lägger du till två egenskaper:
CORS
– ange den bas-URL som är ursprunget till klientprogrammetCORSCredentials
– ställ in den påtrue
för att tillåta "withCredentials"-begäranden
Exempel:
{
"IsEncrypted": false,
"Values": {
// values
},
"Host": {
"CORS": "http://localhost:8080",
"CORSCredentials": true
}
}
Cloud – Azure Functions CORS
Om du vill aktivera CORS i en Azure-funktionsapp går du till CORS-konfigurationsskärmen under fliken Plattformsfunktioner i funktionsappen i Azure-portalen.
Kommentar
CORS-konfigurationen är ännu inte tillgänglig i förbrukningsplanen för Azure Functions Linux. Använd Azure API Management för att aktivera CORS.
CORS med Access-Control-Allow-Credentials måste vara aktiverat för att SignalR-klienten ska kunna anropa förhandlingsfunktionen. Om du vill aktivera den markerar du kryssrutan.
I avsnittet Tillåtet ursprung lägger du till en post med ursprungsbasens URL för ditt webbprogram.
Cloud – Azure API Management
Azure API Management tillhandahåller en API-gateway som lägger till funktioner i befintliga serverdelstjänster. Du kan använda den för att lägga till CORS i funktionsappen. Den erbjuder en förbrukningsnivå med priser för betala per åtgärd och ett månatligt kostnadsfritt bidrag.
Mer information om hur du importerar en Azure-funktionsapp finns i API Management-dokumentationen. När du har importerat kan du lägga till en inkommande princip för att aktivera CORS med stöd för Åtkomstkontroll-Tillåt-autentiseringsuppgifter.
<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>
Konfigurera signalR-klienterna så att de använder API Management-URL:en.
Använda App Service-autentisering
Azure Functions har inbyggd autentisering som stöder populära leverantörer som Facebook, X, Microsoft-konto, Google och Microsoft Entra-ID. Den här funktionen kan integreras med bindningen för att skapa anslutningar till Azure SignalR Service som autentiseras SignalRConnectionInfo
till ett användar-ID. Ditt program kan skicka meddelanden med hjälp av utdatabindningen SignalR
som är riktad mot användar-ID:t.
Öppna fönstret Inställningar för autentisering/auktorisering på fliken Plattformsfunktioner i funktionsappen i Azure-portalen. Följ dokumentationen för App Service-autentisering för att konfigurera autentisering med valfri identitetsprovider.
När de har konfigurerats inkluderar x-ms-client-principal-name
autentiserade HTTP-begäranden och x-ms-client-principal-id
rubriker som innehåller den autentiserade identitetens användarnamn respektive användar-ID.
Du kan använda dessa rubriker i bindningskonfigurationen SignalRConnectionInfo
för att skapa autentiserade anslutningar. Här är ett exempel på en C#-förhandlingsfunktion som använder x-ms-client-principal-id
huvudet.
[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;
}
Du kan sedan skicka meddelanden till användaren genom att ange egenskapen för UserId
ett SignalR-meddelande.
[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 }
});
}
Information om andra språk finns i Azure SignalR Service-bindningar för Azure Functions-referensen.
Nästa steg
I den här artikeln får du lära dig hur du utvecklar och konfigurerar serverlösa SignalR Service-program med hjälp av Azure Functions. Prova att skapa ett program själv med någon av snabbstarterna eller självstudierna på översiktssidan för SignalR Service.