使用 Azure SignalR Service 來開發與設定 Azure Functions
Azure Functions 應用程式可以使用 Azure SignalR Service 繫結來新增即時功能。 用戶端應用程式會使用數種語言的用戶端 SDK 來連線到 Azure SignalR Service並接收即時訊息。
本文說明開發及設定與 SignalR Service 整合的 Azure Function 應用程式的概念。
SignalR Service 組態
Azure SignalR Service 可以在不同模式中設定。 搭配 Azure Functions 使用時,服務必須在無伺服器模式中設定。
在 Azure 入口網站中,找出 SignalR Service 資源的 [設定] 頁面。 將 [服務模式] 設定為 [無伺服器]。
Azure Functions 開發
以 Azure Functions 和 Azure SignalR Service 建立的無伺服器即時應用程式需要至少兩個 Azure Functions:
- 用戶端會呼叫「
negotiate
」函式來取得有效的 SignalR Service 存取權杖和端點 URL。 - 處理從 SignalR Service 傳送至用戶端之訊息的一或多個函式。
交涉函式
用戶端應用程式需要有效的存取權杖,才能連線到 Azure SignalR Service。 存取權杖可以是匿名或驗證給使用者識別碼。 無伺服器 SignalR Service 應用程式需要名為 negotiate
的 HTTP 端點,才能取得權杖和其他連線資訊,例如 SignalR Service 端點 URL。
使用 HTTP 觸發的 Azure 函式和 SignalRConnectionInfo
輸入繫結來產生連線資訊物件。 函式必須有以 /negotiate
結尾的 HTTP 路由。
在 C# 中使用類別型模型時,您不需要 SignalRConnectionInfo
輸入繫結,而且可以更輕鬆地新增自訂宣告。 如需詳細資訊,請參閱類別型模型中的交涉體驗。
如需 negotiate
函式的詳細資訊,請參閱 Azure Functions 開發。
如要了解如何建立驗證權杖,請參閱使用 App Service 驗證。
處理來自 SignalR Service 的訊息
使用 SignalRTrigger
繫結來處理來自 SignalR Service 的訊息。 當用戶端傳送訊息,或是用戶端連線或中斷連線時,您就會收到通知。
如需詳細資訊,請參閱 SignalR Service 觸發繫結參考資料。
您也需要將函式端點設定為上游端點,以便服務在收到來自用戶端的訊息時觸發函式。 如需如何設定上游端點的詳細資訊,請參閱上游端點。
注意
SignalR Service 不支援來自無伺服器模式之用戶端的 StreamInvocation
訊息。
傳送訊息和管理群組成員資格
使用 SignalR
輸出繫結將訊息傳送到連線至 Azure SignalR Service 的用戶端。 您可以將訊息廣播到所有用戶端,或是傳送到用戶端子集。 例如只傳送訊息到使用特定使用者識別碼驗證的用戶端,或只傳送訊息到特定群組。
使用者可以加入一或多個群組。 您也可以使用 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();
類別型模型中的交涉體驗
類別型模型中的交涉可以不使用 SignalR 輸入繫結 [SignalRConnectionInfoInput]
,而是變得更彈性。 基底類別 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 用戶端應用程式可以使用多種語言之一的 SignalR 用戶端 SDK 來輕鬆連線,並接收來自 Azure SignalR Service 的訊息。
設定用戶端連線
如要連線至 SignalR Service,用戶端必須完成包含下列步驟的成功連線交涉:
- 對上述的
negotiate
HTTP 端點提出要求,以取得有效的連線資訊 - 使用服務端點 URL 和從
negotiate
端點取得的存取權杖連線至 SignalR Service
SignalR 用戶端 SDK 已經包含執行交涉交握所需的邏輯。 將交涉端點的 URL 減去 negotiate
區段,傳遞至 SDK 的 HubConnectionBuilder
。 以下是 JavaScript 中的範例:
const connection = new signalR.HubConnectionBuilder()
.withUrl("https://my-signalr-function-app.azurewebsites.net/api")
.build();
根據慣例,SDK 會自動將 /negotiate
附加至 URL,並使用它開始交涉。
注意
如果您在瀏覽器中使用 JavaScript/TypeScript SDK,您必須在函式應用程式上啟用跨原始資源共用 (CORS) 。
如需如何使用 SignalR 用戶端 SDK 的詳細資訊,請參閱您的語言的文件:
從用戶端傳送訊息至服務
如果您已針對 SignalR 資源設定上游,您可以使用任何 SignalR 用戶端,將訊息從用戶端傳送至 Azure Functions。 以下是 JavaScript 中的範例:
connection.send("method1", "arg1", "arg2");
Azure Functions 組態
與 Azure SignalR Service 整合的 Azure 函式應用程式可以使用持續部署、zip 部署和從套件執行等技術,像任何典型的 Azure 函式應用程式一樣進行部署。
不過,針對使用 SignalR Service 繫結的應用程式,有幾個特殊考量。 如果用戶端在瀏覽器中執行,則必須啟用 CORS。 如果應用程式需要驗證,您可以將交涉端點與 App Service 驗證整合。
啟用 CORS
JavaScript/TypeScript 用戶端會對交涉函式提出 HTTP 要求,以起始連線交涉。 當用戶端應用程式託管於與 Azure Function 應用程式不同的網域時,必須在函式應用程式上啟用 CORS,否則瀏覽器將封鎖要求。
Localhost
在您的本機電腦上執行函式應用程式時,您可以新增 [Host
] 區段到 local.settings.json 以啟用 CORS。 在 [Host
] 區段中,新增兩種屬性:
CORS
- 輸入用戶端應用程式來源的基底 URLCORSCredentials
- 將其設定為true
,以允許「withCredentials」要求
範例:
{
"IsEncrypted": false,
"Values": {
// values
},
"Host": {
"CORS": "http://localhost:8080",
"CORSCredentials": true
}
}
雲端 - Azure Functions CORS
如要在 Azure 函式應用程式上啟用 CORS,請前往 Azure 入口網站,從函式應用程式 [平台功能] 索引標籤下方進入 CORS 組態畫面。
注意
Azure Functions Linux 使用量方案尚未提供 CORS 組態。 使用 Azure API 管理來啟用 CORS。
必須啟用具有 Access-Control-Allow-Credentials 的 CORS,SignalR 用戶端才能呼叫交涉函式。 若要啟用,請選取核取方塊。
在 [允許的來源] 區段中,新增具有您網頁應用程式來源基底 URL 的項目。
雲端 - Azure API 管理
Azure API 管理提供 API 閘道,為現有的後端服務新增功能。 您可以用於將 CORS 加入您的函式應用程式。 它提供按動作付費定價和每月免費授與的使用層。
請參閱 API 管理文件,了解如何匯入 Azure 函式應用程式的詳細資訊。 匯入後,您可以新增輸入政策,以啟用具有 Access-Control-Allow-Credentials 支援的 CORS。
<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 用戶端,以使用 API 管理 URL。
使用 App Service 驗證
Azure Functions 具有內建驗證,並支援熱門提供者,例如 Facebook、X、Microsoft 帳戶、Google 和 Microsoft Entra ID。 此功能可以與 SignalRConnectionInfo
繫結整合,以與已驗證至使用者識別碼的 Azure SignalR Service 建立連線。 您的應用程式可以使用以該使用者識別碼為目標的 SignalR
輸出繫結來傳送訊息。
在 Azure 入口網站中,前往函式應用程式的 [平臺功能] 索引標籤中,開啟 [驗證/授權設定] 視窗。 按照 App Service 驗證文件的說明,使用您選擇的身分識別提供者設定驗證。
設定完成後,已驗證的 HTTP 要求會包含 x-ms-client-principal-name
和 x-ms-client-principal-id
標頭,其中分別包括已驗證的身分識別使用者名稱和使用者識別碼。
您可以在 SignalRConnectionInfo
繫結組態中使用這些標頭,以建立已驗證的連線。 以下是使用 x-ms-client-principal-id
標頭的 C# 交涉函式範例。
[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;
}
接著,您可以透過設定 SignalR 訊息的 UserId
屬性,將訊息傳送給該使用者。
[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 Service 繫結,了解 Azure Functions 參考資料。
下一步
在本文中,您了解如何使用 Azure Functions 開發和設定無伺服器 SignalR Service 應用程式。 請嘗試使用 SignalR Service 概觀頁面上的其中一個快速入門或教學課程,自行建立應用程式。