如何使用交互式服务器端渲染在 Blazor 中创建跨会话、多用户通知中心?

问题描述 投票:0回答:1

我正在使用 Blazor .Net Core 8 和交互式服务器端渲染编写一个多用户、云托管应用程序。

该应用程序使用 .Net Events 创建审计跟踪,我的意图是将它们也用于通知中心,但由于我是使用事件的新手,所以我没有意识到这不是交叉的正确选择-会话/多用户通知。

通知的一个示例是当用户正在编辑价格表时,例如,第二个用户开始编辑相同的价格表。

所需的功能是在第二个用户开始编辑价目表后尽快向两个用户弹出通知,告知他们正在处理同一价目表,而无需任何用户交互来刷新 UI。

由于事件似乎不是正确的方法,我看了一下 SignalR,它似乎是在不同会话中向用户发送通知的自然选择。然而,微软非常小心地提及,SignalR 在使用服务器端渲染时没有任何意义 - 服务器基本上会自言自语 - 并且 SignalR 应该与 WASM 一起使用。

我尝试在 WASM 中仅运行 SignalR 通知中心组件,但这导致了许多我无法解决的问题。尽管我读到您可以对各个组件使用不同的渲染模式,但在这种特定情况下可能是不可能的。

在我花更多时间进行徒劳的追逐之前,我决定与这个社区核实一下,看看是否有既定的方法来实现我所追求的功能。

澄清一下,挑战并不是在收到通知时更新 UI,而是首先将通知发送给一个或多个用户。

也许可以在 WASM 中运行我的通知中心组件,但我只是不知道如何运行。也许有一种方法可以让 .Net Events 做我想做的事。也许隐藏在阴影中的第三种选择才是正确的选择。

我不会选择既不使用 SignalR 也不使用 Events,只要我可以获得我想要的功能 - 并且最好不必从头开始编写功能 - 我愿意接受建议。

c# blazor blazor-server-side
1个回答
0
投票

对于 blazor 服务器,您可以尝试使用

IObservable
https://github.com/dotnet/reactive
来使用 System.Reactive。这是满足您需求的小样本。

Center.cs(用于管理当前用户的ActiveUsersList)

    public class Center
    {
        public List<string> ActiveUsersList { get; set; } = new();

        private readonly Subject<Unit> _notification = new Subject<Unit>();
        public IObservable<Unit> Notification => _notification;
        public void Notify()
        {
            _notification.OnNext(Unit.Default);
        }
    }

注册为单例以共享跨会话。

builder.Services.AddSingleton<Center>();

Home.razor(当你编辑div时,“HandleFocusIn”被触发,你用用户名更新用户列表,然后通知所有会话更新用户列表并再次渲染)

@page "/"
@inject Center _Center

<ul>
    @foreach (var user in usersForRender)
    {
        <li>@user</li>
    }
</ul>

<div @onfocusin="HandleFocusIn" @onfocusout="HandleFocusOut">
    <input type="text" @bind="inputValue1" />
    <input type="text" @bind="inputValue2" />

</div>

@code {
    private List<string> usersForRender = new();
    private IDisposable? subscription;

    private string inputValue1 = "Value 1";
    private string inputValue2 = "Value 2";

    protected override void OnInitialized()
    {
        usersForRender = _Center.ActiveUsersList;
        if (subscription == null) // Only subscribe if no active subscription exists
        {
            subscription = _Center.Notification.Subscribe(message =>
            {
                usersForRender = _Center.ActiveUsersList;
                InvokeAsync(StateHasChanged); 
            });
        }

    }

    public void Dispose()
    {
        // Unsubscribe to avoid memory leaks
        subscription?.Dispose();
    }

    private void HandleFocusIn(FocusEventArgs e)
    {
        //Just assume user is Tom, you could fetch the username from AuthenticationStateProvider.
        _Center.ActiveUsersList.Add("Tom");
        _Center.Notify();
    }

    private void HandleFocusOut(FocusEventArgs e)
    {
        _Center.ActiveUsersList.Remove("Tom");
        _Center.Notify();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.