Search code examples
c#asp.net-core-webapidotnet-httpclient

Stop a download in progress in ASP.NET Core


If I wanted to interrupt the download without corrupting the .flv file stream, how could I do that? Considering that there might be multiple downloads at the same time, so I don't want to interrupt them all at once.

Here is how I download the file:

app.MapGet("/stream", async context =>
{
    var httpClient = new HttpClient();

    var request = new HttpRequestMessage(HttpMethod.Get, url);
    var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);

    context.Response.ContentType = "application/octet-stream";
    context.Response.Headers.Add("Content-Disposition", "attachment; filename=\"file.flv\"");
    context.Response.Headers.Add("Transfer-Encoding", "chunked");

    using var responseStream = await 
    response.Content.ReadAsStreamAsync();
    await responseStream.CopyToAsync(context.Response.Body);
});

app.MapGet("/stop", async context =>
{
    await context.Response.WriteAsync("Download stopped.");
    // How do I stop?????????
});

Solution

  • I see the option of implementing that through CancellationTokenSource, you need to keep reference to every download you start, so you can abort it in different request.

    var builder = WebApplication.CreateBuilder(args);
    
    var app = builder.Build();
    
    app.UseHttpsRedirection();
    
    var cancellationTokens = new Dictionary<string, CancellationTokenSource>();
    
    app.MapGet("/stream", async context =>
    {
        var id = context.Request.Query["id"];
        var cts = new CancellationTokenSource();
        cancellationTokens[id] = cts;
    
        var httpClient = new HttpClient();
    
        var request = new HttpRequestMessage(HttpMethod.Get, "https://filesamples.com/samples/video/flv/sample_1280x720_surfing_with_audio.flv");
        var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token);
        
        context.Response.ContentType = "application/octet-stream";
        context.Response.Headers.Add("Content-Disposition", "attachment; filename=\"file.flv\"");
        context.Response.Headers.Add("Transfer-Encoding", "chunked");
    
        using var responseStream = await response.Content.ReadAsStreamAsync(cts.Token);
    
        await responseStream.CopyToAsync(context.Response.Body, cts.Token);
    });
    
    app.MapGet("/stop", async context =>
    {
        var id = context.Request.Query["id"];
    
        cancellationTokens[id].Cancel();
    
        await context.Response.WriteAsync("Download stopped.");
    });
    
    app.Run();
    

    Call to stop endpoint produces following stacktrace in console indicating that cancellation is done inside of CopyToAsync method. I also pass the same token in all methods that accept it

    enter image description here