任务:根据 API 请求更新所有打开会话中的页面。当 API 发送请求时,两个会话都必须更新。例如,如果 Alice 和 Bob 打开页面,则两个页面都应该更新。
问题:目前,如果您打开第二个会话并且它离开页面 X,则第一个会话将失去其订阅并且不再接收更新。
状况:
- 第一个 Web 应用程序是在 Blazor Server 中编写的。
- 第二个是一个简单的 API 挂钩。
如何确保两个会话保持签名并接收更新,而不管用户在另一个会话中的操作如何?
挂钩API
public static readonly ConcurrentDictionary<string, string> Subscribers = new();
[HttpPost("subscribe")]
public IActionResult Subscribe([FromBody] SubscriptionRequest request)
{
Subscribers[request.Url] = request.Url;
return Ok(new { status = "subscribed" });
}
[HttpPost("unsubscribe")]
public IActionResult Unsubscribe([FromBody] SubscriptionRequest request)
{
Subscribers.TryRemove(request.Url, out _);
return Ok(new { status = "unsubscribed" });
}
private async Task<IActionResult> SendWebhookToSubscribers(IEnumerable<SimpleDataForHookTest> payload)
{
var client = _httpClientFactory.CreateClient();
foreach (var subscriber in Subscribers.Values)
{
await client.PostAsJsonAsync(subscriber, payload);
}
return Ok(new { status = "webhook sent" });
}
布拉佐尔
protected override async Task OnInitializedAsync()
{
await SubscriptionService.Subscribe("https://localhost:7052/api/TestHook/TestWebHook");
HookService.Register(ReceivePlanningData);
}
private void ReceivePlanningData(IEnumerable<SimpleDataForHookTest> planningListDto)
{
MyPropertyTestHook = planningListDto;
InvokeAsync(StateHasChanged);
}
public void Dispose()
{
HookService.UnRegister(ReceivePlanningData);
SubscriptionService.Unsubscribe("https://localhost:7052/api/TestHook/TestWebHook").GetAwaiter().GetResult();
}
完整的代码位于 GitHub 上(这里我分享了控制器和 Razor 页面的主要代码)。如果您运行这两个应用程序,则 15 秒后页面 1 会更新,但如果您并行打开页面 2 并保留它,则第一个页面将不再更新。
我试过:
a) Blazor 端的计时器每 n 分钟发出 GET 请求。这是昂贵的并且会在用户工作时破坏页面。
b) SignalR,虽然订阅成功了,但没有起作用,也不刷新页面。在 main 上有一个带有 SignalR 的版本,我无法修改它。
GitHub 上的工作分支:
(我通常使用Azure DevOps,我不知道是否需要在GitHub上创建拉取请求,或者我是否可以克隆。我通过Visual Studio创建了一个新分支并提交了它,但我找不到该选项在 GitHub 上创建拉取请求)。
也许有人有自己的想法,可以告诉我如何从 API 更新数据。数据如何到达 API 并不重要,但 API 将数据发送给订阅者(在此示例中为 Blazor Web)。
如果在实现 SignalR 时向应用程序地址本身添加标识符,则可以获得每个会话的唯一链接,从而使每个连接都是唯一的。
因此,使用SignalR,可以实现所有会话的更新,无论其中之一是否已离开订阅。
挂钩API
PlanningHub.csEventController.cs布拉佐尔
UpdateHub.csPageRazorExample.razor.csProgram.cs已测试:在多个会话中工作(Chrome 中的 1 个页面 + 通过 Ctrl+Shift+N 的 2 个页面)。刷新两个页面以重置 HTML,然后退出页面 2,页面 1 将继续刷新。