I add setTimeout in below code, and it works properly. I am not experts in Angular. Adjustments to Angular-related codes require collaboration between you and your team.

async ngOnInit(): Promise<void> {
// Subscribe to progress updates from SignalR
this.signalRService.progress$.subscribe(({ downloadId, status }) => {
setTimeout(() => {
if (downloadId === this.currentDownloadId) {
console.log("Updating downloadStatus signal with:", JSON.stringify(status));
this.downloadStatus.set({ ...status });
// Update UI with latest output
if (status.output && status.output.length > this.output().length) {
this.output.set([...status.output]);
}
this.cdr.detectChanges();
// Check if download is completed
if (status.isCompleted) {
this.isDownloading = false;
if (status.isSuccessful) {
this.showSuccessMessage(status.filePath);
} else {
this.showErrorMessage('Download failed', status.errorMessage);
}
}
}
}, 500);
});
}
After testing, I determined that this problem only occurs during vs2022 debugging. If this application is published, this problem will not occur.
The reason is that SPA uses proxy configuration when debugging in VS2022. So when it starts, we can see that the angular application is running on port 63349 and the api project is running on port 7217.
If you are still in the development stage, you can explicitly specify the url in the angular project as .withUrl("https://localhost:7217/downloadHub"). And we also need to enable cors feature as well.
Here is the detailed steps.
signalr.service.ts
private apiHub = "https://localhost:7217/downloadHub";
constructor() {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(this.apiHub) // Match the SignalR hub URL on the server
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Debug)
.build();
}
Program.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Text.Json.Serialization;
using YtSharp.Server;
using YtSharp.Server.services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Add CORS Settings
builder.Services.AddCors(options => options.AddPolicy("CorsPolicy", policy =>
{
policy
.WithOrigins("https://127.0.0.1:63349", "https://localhost:63349")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
builder.Services.AddSignalR();
builder.Services.AddDirectoryBrowser();
builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddScoped<IYtSharpService, YtSharpService>();
builder.Services.AddControllers().AddNewtonsoftJson(
options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.TypeNameHandling = TypeNameHandling.None;
options.SerializerSettings.Formatting = Formatting.Indented;
}
)
.AddXmlSerializerFormatters()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
})
.AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()
);
var app = builder.Build();
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
var MimeProvider = new FileExtensionContentTypeProvider();
MimeProvider.Mappings[".flac"] = "audio/flac";
MimeProvider.Mappings[".flv"] = "video/x-flv";
MimeProvider.Mappings[".mkv"] = "video/mp4";
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(@"c:/medias"),
RequestPath = "/medias",
ContentTypeProvider = MimeProvider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(@"c:/medias"),
RequestPath = "/medias"
});
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.UseSwaggerUI(
options =>
{
options.SwaggerEndpoint("../openapi/v1.json", "version 1");
});
}
app.UseRouting();
// Enable CORS Feature
app.UseCors("CorsPolicy");
app.UseAuthorization();
app.MapHub<DownloadHub>("/downloadHub");
app.MapControllers();
app.MapFallbackToFile("/index.html");
app.Run();
Test Result
