0

Im working on a service to download large files. There is a web frontend, that sends a get request, which recieves the file as a stream. I have looked into Streamsaver.js, but i dont want the mitm. Currently using it like this

async function downloadFileFromStream(fileName, streamRef) {
    // Get the stream from the .NET stream reference
    const response = await streamRef.stream();
    const readableStream = response.getReader();
    const fileStream = streamSaver.createWriteStream(fileName);

    if (window.WritableStream && readableStream.pipeTo) {
        await readableStream.pipeTo(fileStream);
        return;
    }

    const writer = fileStream.getWriter();
    

    const pump = () => readableStream.read()
        .then(({ done, value }) => {
            if (done) {
                writer.close();
                return;
            }
            return writer.write(value).then(pump);
        });

    await pump();
}

// To register the function in the global window object so it can be called from C#
window.downloadFileFromStream = downloadFileFromStream;

I would like to know if there is a way similar to how i would have done it in C#

psudo-code

Readstream r;
Writestream w;

r.copyToAsync(w);

2 Answers 2

1
window.downloadFileFromStream = async function (fileName, streamRef) {
    // Get the response from the stream reference
    const response = await streamRef.stream();
    const reader = response.getReader();

    // Show file picker to choose save location
    const handle = await window.showSaveFilePicker({
        suggestedName: fileName
    });

    // Create a writable stream and wait for it to be ready
    const writableStream = await handle.createWritable();

    // Function to pump data from the reader to the writable stream
    const pump = async () => {
        const { done, value } = await reader.read();
        if (done) {
            await writableStream.close();
            console.log("done");
            return;
        }
        await writableStream.write(value);
        return pump(); // Call pump again for the next chunk
    };

    // Start pumping data
    await pump();
}

I tried this, and got it to work if anyone still has this issue. The only problem i see in this is that it does not show the progress in the browser downloadstab, only in the filesystem downloads

0

javascript:

window.downloadFileFromStream = async function (fileName, streamRef) {
    const response = await streamRef.stream();
    const reader = response.getReader();

    const writableStream = new WritableStream({
        async write(chunk, controller) {
            await writer.write(chunk);
        },
        close() {
            writer.close();
        }
    });

    const writer = writableStream.getWriter();

    const pump = () => reader.read().then(({ done, value }) => {
        if (done) {
            writer.close();
            return;
        }
        return writer.write(value).then(pump);
    });

    await pump();
}

Include this js file.

@page "/download"
@inject IJSRuntime JS

<button @onclick="DownloadFile">Download File</button>

@code {
    private async Task DownloadFile()
    {
        var streamRef = new DotNetStreamReference(await GetFileStream());
        await JS.InvokeVoidAsync("downloadFileFromStream", "example.txt", streamRef);
    }

    private async Task<Stream> GetFileStream()
    {
        var stream = new MemoryStream();
        using (var writer = new StreamWriter(stream, leaveOpen: true))
        {
            await writer.WriteAsync("Example file content");
        }
        stream.Position = 0;
        return stream;
    }
}
1
  • 1
    this does not work. the writable stream you created does not stream to the downloads folder on the computer, it only creates a stream inside the browser. Commented Jul 1 at 5:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.