@page "/" @using UndoExample @using Microsoft.AspNetCore.SignalR.Client @using System.Collections.Concurrent @inject IMessageSession MessageSession @inject NavigationManager Navigation <PageTitle>Index</PageTitle> <div class="container"> <div class="mb-3"> <textarea class="form-control" @bind="NewMessage"></textarea> </div> <div class="mb-3"> <button class="btn btn-primary" @onclick="SendNow">Send Now</button> <button class="btn btn-primary" @onclick="SendWithDelay">Send with Delay</button> </div> @foreach (var tweet in _tweets) { <div class="alert alert-primary alert-dismissible fade show" role="alert"> @tweet.Message @if (tweet.CanUndo) { <button type="button" class="btn-close" data-bs-dismiss="alert" @onclick="() => UndoTweet(tweet.TweetId)" aria-label="Close"></button> } </div> } </div> @code { private record ClientTweet(Guid TweetId, string Message, bool CanUndo); private HubConnection? _hubConnection; private readonly ConcurrentBag<ClientTweet> _tweets = new(); private string NewMessage { get; set; } = ""; protected override async Task OnInitializedAsync() { _hubConnection = new HubConnectionBuilder() .WithUrl(Navigation.ToAbsoluteUri("/tweethub")) .Build(); _hubConnection.On<Guid, string>("tweeted", (tweetId, message) => { RemoveTweet(tweetId); _tweets.Add(new ClientTweet(tweetId, message, false)); InvokeAsync(StateHasChanged); }); _hubConnection.On<Guid>("undone", (tweetId) => { RemoveTweet(tweetId); InvokeAsync(StateHasChanged); }); await _hubConnection.StartAsync(); } private void RemoveTweet(Guid tweetId) { var existingTweet = _tweets.SingleOrDefault(x => x.TweetId == tweetId); if (existingTweet != null) { _tweets.TryTake(out existingTweet); } } private async Task SendNow() { await MessageSession.Send(new Tweet(Guid.NewGuid(), NewMessage)); NewMessage = string.Empty; } private async Task SendWithDelay() { var tweet = new TweetWithDelay(Guid.NewGuid(), NewMessage); await MessageSession.Send(tweet); _tweets.Add(new ClientTweet(tweet.TweetId, tweet.Message, true)); NewMessage = string.Empty; } private async Task UndoTweet(Guid tweetId) { await MessageSession.Send(new UndoTweet(tweetId)); } }