admin管理员组

文章数量:1279118

I have an Angular client tries to download video from a website thru a IIS server (c#). The download process is working now (I am using youtubeDLSharp Dll to do it). Things I don't know how to do it is to send data (like how much progress and text info) back to the Angular Client while the youtubeDLSharp processes. code in c# controller

[HttpPost("download")]
public async Task<IActionResult> Download([FromBody] DownloadRequest request)
{
    if (string.IsNullOrEmpty(request.Url))
        return BadRequest("URL is required");

    // Create download ID
    string downloadId = Guid.NewGuid().ToString();

    // Initialize download status
    var downloadStatus = new DownloadStatus
    {
        Id = downloadId,
        Url = request.Url,
        State = "Initializing",
        Progress = 0,
        IsCompleted = false
    };

    // Store the download status
    _downloads[downloadId] = downloadStatus;

    // Start download process asynchronously
    await Task.Run(async () =>
    {
        try
        {
            // Set up progress tracking
            var progress = new Progress<DownloadProgress>(p =>
            {
                downloadStatus.State = p.State.ToString();
                downloadStatus.Progress = p.Progress;
                downloadStatus.DownloadSpeed = p.DownloadSpeed;
                downloadStatus.ETA = p.ETA;
            });

            var output = new Progress<string>(s =>
            {
                downloadStatus.Output.Add(s);
                
            });

            // Parse custom options
            OptionSet? custom = null;
            if (!string.IsNullOrEmpty(request.Options))
            {
                custom = OptionSet.FromString(request.Options.Split('\n'));
            }

            // Start download
            RunResult<string> result;
            if (request.AudioOnly)
            {
                result = await _youtubeDL.RunAudioDownload(
                    request.Url,
                    AudioConversionFormat.Mp3,
                    progress: progress,
                    output: output,
                    overrideOptions: custom
                );
            }
            else
            {
                result = await _youtubeDL.RunVideoDownload(
                    request.Url,
                    progress: progress,
                    output: output,
                    overrideOptions: custom
                );
            }

            // Update download status after completion
            downloadStatus.IsCompleted = true;
            downloadStatus.IsSuccessful = result.Success;

            if (result.Success)
            {
                downloadStatus.FilePath = result.Data;
            }
            else
            {
                downloadStatus.ErrorMessage = string.Join("\n", result.ErrorOutput);
            }
        }
        catch (Exception ex)
        {
            downloadStatus.IsCompleted = true;
            downloadStatus.IsSuccessful = false;
            downloadStatus.ErrorMessage = ex.Message;
        }
    });

    // Return the download ID for status tracking
    return Ok(new { DownloadId = downloadId });
}


// this is the process return status back to client run every second.
[HttpGet("status/{id}")]
public Task<IActionResult> GetDownloadStatus(string id)
{
    if (!_downloads.TryGetValue(id, out var status))
    {
        return Task.FromResult<IActionResult>(NotFound("Download not found"));
    }

    return Task.FromResult<IActionResult>(Ok(status));
}

on Angular Client service

downloadVideo(request: DownloadRequest): Observable<DownloadResponse> {
  return this.http.post<DownloadResponse>(`${this.apiUrl}/download`, request);
}

getDownloadStatus(id: string): Observable<DownloadStatus> {
  return this.http.get<DownloadStatus>(`${this.apiUrl}/status/${id}`);
}

component.ts try to pull status every second.

this.statusSubscription = interval(1000)
  .pipe(
    switchMap(() => this.youtubeDlService.getDownloadStatus(this.currentDownloadId!))
  )
  .subscribe({
    next: (status) => {
      this.downloadStatus = status;

      // Update UI with latest output
      if (status.output && status.output.length > this.output.length) {
        this.output = [...status.output];
      }

      // Check if download is completed
      if (status.isCompleted) {
        this.isDownloading = false;
        this.statusSubscription?.unsubscribe();

        if (status.isSuccessful) {
          this.showSuccessMessage(status.filePath);
        } else {
          this.showErrorMessage('Download failed', status.errorMessage);
        }
      }
    },
    error: (error) => {
      console.error('Error polling status:', error);
      this.isDownloading = false;
      this.statusSubscription?.unsubscribe();
    }
  });

What happend on server c# via debugger is that the logic await Task.Run(async () never works. It processes until it is done then it send the downloadId back to client ( return Ok(new { DownloadId = downloadId });) and on client side, it never receive any status from server. Please point to what I have done wrong in the logic. Example would be very nice. Thanks.

My env is dotnet 9 and Angular 19.

Githup source code for this

本文标签: Sending updating status from IIS server (c) back to Angular ClientStack Overflow