diff --git a/src/Blog/wwwroot/posts/providing-real-time-feedback-about-long-running-task-with-signal-r/index.md b/src/Blog/wwwroot/posts/providing-real-time-feedback-about-long-running-task-with-signal-r/index.md index a425cc3..3564b2a 100644 --- a/src/Blog/wwwroot/posts/providing-real-time-feedback-about-long-running-task-with-signal-r/index.md +++ b/src/Blog/wwwroot/posts/providing-real-time-feedback-about-long-running-task-with-signal-r/index.md @@ -245,7 +245,6 @@ main { width: 100%; height: 100%; display: flex; - justify-content: center; align-items: center; } @@ -271,22 +270,203 @@ app }) .WithName("AddTask") .WithDisplayName("Add Task") - .WithDescription("Add a new task to the queue") - .WithOpenApi(); + .WithDescription("Add a new task to the queue"); ``` Run client and server. Click the add task button. You should see a success message with id of the task just added. ### Implement the task queue +```csharp +class BackgroundTask +{ + public string Id { get; set; } = Guid.NewGuid().ToString(); +} +``` + +```csharp +class BackgroundTaskQueue +{ + private readonly Channel _channel = Channel.CreateUnbounded(); + + public async Task EnqueueAsync(BackgroundTask task) + { + await _channel.Writer.WriteAsync(task); + } + + public async Task DequeueAsync(CancellationToken cancellationToken) + { + return await _channel.Reader.ReadAsync(cancellationToken); + } +} +``` + ### Implement the task service +```csharp +class TaskService(BackgroundTaskQueue taskQueue) : BackgroundService +{ + private readonly BackgroundTaskQueue _taskQueue = taskQueue; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + var task = await _taskQueue.DequeueAsync(stoppingToken); + + // Execute the task + Console.WriteLine($"Task {task.Id} is starting"); + + await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); + + Console.WriteLine($"Task {task.Id} is complete"); + } + } +} +``` + ### Update add task endpoint to add task to queue +```csharp +app + .MapPost("/add-task", async (BackgroundTaskQueue queue) => + { + var task = new BackgroundTask(); + await queue.EnqueueAsync(task); + return Results.Json(data: task, statusCode: (int)HttpStatusCode.Created); + }) + .WithName("AddTask") + .WithDisplayName("Add Task") + .WithDescription("Add a new task to the queue"); +``` + ### Let's add signal r hub +```csharp +builder.Services.AddSignalR(); + +app.MapHub("/task-hub"); +``` + ### Add client code to establish connection to server hub ```sh npm install @microsoft/signalr ``` + +```vue + +... +``` + +### Update server CORS policy to allow signal r connections + +```csharp +... +builder.Services.AddCors( + options => + options.AddDefaultPolicy( + builder => builder + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials() + .WithOrigins("https://localhost:5173") + ) +); +... +``` + +### Update server to actually send updates to client as tasks are processed + +```csharp +class TaskService( + BackgroundTaskQueue taskQueue, + IHubContext taskHub +) : BackgroundService +{ + private readonly BackgroundTaskQueue _taskQueue = taskQueue; + private readonly IHubContext _taskHub = taskHub; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + var task = await _taskQueue.DequeueAsync(stoppingToken); + + // Execute the task + await _taskHub.Clients.All.SendAsync("ReceiveMessage", $"Task {task.Id} is starting", cancellationToken: stoppingToken); + + await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); + + await _taskHub.Clients.All.SendAsync("ReceiveMessage", $"Task {task.Id} is complete", cancellationToken: stoppingToken); + } + } +} +``` + +### Update client to display updates instead of logging them + +```vue + + + +... +``` + +### Now you can run the client and server and see the updates as tasks are processed + +Pretty cool huh? + +## Conclusion + +Probably mentioned typed hubs here.