【发布时间】:2022-09-23 09:24:49
【问题描述】:
我有一个 Azure SignalR 无服务器实例;我创建了一个按预期工作的 Azure 函数协商终结点。我按照此处提供的“协商服务器”指南使用隔离的 Azure 函数进行了设置。
https://github.com/aspnet/AzureSignalR-samples/tree/main/samples/Management
然后,我使用来自同一链接的“SignalR 客户端”下的指导来创建客户端应用程序 - 主要是对事件的订阅,即 hubConnection.On(\“HubMethodName\”, action => { ... })。在这里使用 HubConnection 对象是理想的,因为 HubConnectionBuilder 是针对代理 URI 执行的 - 即 https://myfunctionapp.com/hubName,这会触发协商功能并返回 HubConnection 实际使用的连接详细信息。在这一点上,我还将指出 HubConnection 有一些与发送消息相关的方法 - 即 SendAsync(...) 和 InvokeAsync(...)。
在消息发布方面,文档似乎忽略了上述这些方法,而是指初始化一个ServiceManager创建一个HubContext,然后利用中心上下文提供的代理方法进行消息发送(即hubContext.Clients.All.发送异步(...))。我的问题是这个 ServiceManager / HubContext 感觉非常服务器端 - 它们是我在我的 Azure Function 上用来实现协商的对象,提供比发送/订阅更多的管理功能,并且不适合我的协商终结点的概念(ServiceBuilder 接受 Azure SignalR 连接字符串并且不利用协商终结点)。
话虽如此,我非常倾向于从我的客户端代码中排除 ServiceManager / HubContext 并且非常渴望弄清楚如何使用严格的 HubConnection 实例来使其工作。但是,使用 SendAsync / InvokeAsync 方法不会成功。首先,我通过创建一个发送消息的附加 Azure Function 端点来确认我的订阅工作成功。 _context.Clients.All.SendAsync(\"method\", \"some text\") 成功触发我的客户端订阅。但是,当我从客户端使用 hubConnection.SendAsync(\"method\", \"some text\") 方法时,不会触发我的订阅。
调查后,我发现实际上没有发送任何“消息”。在 Azure SignalR 日志中,我可以看到正在初始化的连接并且连接数在增加;但是,当我在 HubConnection 上调用 SendAsync(...) 时,消息计数统计信息不会改变。通过将传输模式更改为长轮询并使用 Fiddler,我确认在调用 hubConnection.SendAsync(...) 方法时正在发生 HTTP 发布 - 它确实对我的 Azure SignalR 服务执行 POST。
POST https://xxx.signalr.net/client/?hub=testhub&id=xxx HTTP/1.1
Host: xxx.service.signalr.net
User-Agent: Microsoft SignalR/6.0 (6.0.9+3fe12b935c03138f76364dc877a7e069e254b5b2; Windows NT; .NET; .NET 6.0.9)
X-Requested-With: XMLHttpRequest
Authorization: Bearer xxx
Content-Length: 88
{\"type\":1,\"target\":\"method\",\"arguments\":[\"test message\"]}
长话短说,这个 POST 不是在广播消息时应该发生的——至少不是我的意图。切入正题,看看我的“成功的测试用例”会发生什么——当服务器调用 hubContext.Clients.All.SendAsync(...) 时,它使用的逻辑与 HubConnection 的 SendAsync(... ) 方法。在这种情况下,我们看到 RestApiProvider 影响被调用的端点 (https://github.com/Azure/azure-signalr/blob/180cf1923e828c19967e2ad44bd5e3693bff4218/src/Microsoft.Azure.SignalR.Management/RestApiProvider.cs#L45)。
public Task<RestApiEndpoint> GetBroadcastEndpointAsync(string appName, string hubName, TimeSpan? lifetime = null, IReadOnlyList<string> excluded = null)
{
var queries = excluded == null ? null : new Dictionary<string, StringValues>() { { \"excluded\", excluded.ToArray() } };
return GenerateRestApiEndpointAsync(appName, hubName, \"/:send\", lifetime, queries);
}
在工作案例中(使用 HubContext.Clients.All.SendAsync),我们最终使用路径 \"api/testhub/:send?api-version=2022-06-01\" 对 Azure SignalR 服务执行 POST 和在非工作情况下(使用 HubConnetion.SendAsync),我们最终使用路径 \"client/?hub=testhub&id=xxx\" 对 Azure SignalR 服务执行 POST - 最显着的区别是 /api/ 与。 /client/ 端点路径。
这通过使用 Azure SignalR 的实时跟踪日志捕获一些实时日志得到进一步证实。
两者之间的区别似乎很根本,因为 HubConnection.SendAsync(...) 方法似乎放弃了 RestApiProvider 中包含的所有逻辑,并且无服务器 SignalR 实现没有默认 SignalR 服务模式的“具体”集线器方法做。
有没有人能够使用 HubConnection.SendAsync(...) 从无服务器 Azure SignalR 环境中的客户端成功发送消息?
-
我使用 azure signalR 构建了小型 pub-sub 应用程序。希望对你有帮助github.com/ayyappangs/AzureSignalR.Angular
标签: c# azure .net-core azure-functions azure-signalr