1

I'm trying to enable a user to click a button and download a CSV file with Blazor and I keep downloading an empty file, not sure what I'm doing wrong. I was able to reproduce this in a new Blazor project as well which I'll reference the code for here. My _Host.cshtml file looks like this:

<script>
    window.downloadFileFromStream = async (fileName, contentStreamReference) => {
        const arrayBuffer = await contentStreamReference.arrayBuffer();
        const blob = new Blob([arrayBuffer]);
        const url = URL.createObjectURL(blob);
        const anchorElement = document.createElement('a');
        anchorElement.href = url;
        anchorElement.download = fileName ?? '';
        anchorElement.click();
        anchorElement.remove();
        URL.revokeObjectURL(url);
    }
</script>

My Index.razor looks like this:

@page "/"
@using CsvHelper.Configuration
@using System.Globalization
@using System.Text
@using CsvHelper

@inject IJSRuntime JSRuntime;

@code {

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        var csvFileName = "test.csv";
        var csvConfig = new CsvConfiguration(CultureInfo.CurrentCulture)
        {
            HasHeaderRecord = true,
            Delimiter = ",",
            Encoding = Encoding.UTF8
        };

        DotNetStreamReference streamRef;
        
        var records = new List<TestRecord>();
        var record = new TestRecord {Id = 1, Name = "First"};
        records.Add(record);

        using (var mem = new MemoryStream())
        using (var writer = new StreamWriter(mem))
        using (var csvWriter = new CsvWriter(writer, csvConfig))
        {
            csvWriter.WriteHeader<TestRecord>();
            await csvWriter.WriteRecordsAsync(records);

            await writer.FlushAsync();
            
            streamRef = new DotNetStreamReference(stream: mem);
            await JSRuntime.InvokeVoidAsync("downloadFileFromStream", csvFileName, streamRef);
        }
    }

    public class TestRecord
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

If I try and read the memory stream after writer.FlushAsync(); I'm able to read the record I added. Is anything glaringly obvious as to why my output file is always empty?

Mike
  • 11
  • 1
  • Does rewinding the stream by setting `mem.Position = 0` before uploading solve your problem? – dbc Aug 15 '22 at 19:04
  • Also, I'd probably do `using var mem = new MemoryStream(); using (var writer = new StreamWriter(mem , leaveOpen : true)) using (var csvWriter = new CsvWriter(writer, csvConfig)) { }` to close & the `StreanWriter` and `CsvWriter` while leaving the `mem` stream open. – dbc Aug 15 '22 at 19:08
  • See e.g. [this specific answer](https://stackoverflow.com/a/40255365/3744182) by [Josh](https://stackoverflow.com/users/1486642/josh) to [CsvHelper not writing anything to memory stream](https://stackoverflow.com/q/13646105/3744182). Incidentally, if you're writing to a `MemoryStream` there is no need to use `async` serialization. – dbc Aug 15 '22 at 19:11
  • 1
    @dbc Resetting the mem.Position to 0 did resolve it! Thanks so much! – Mike Aug 15 '22 at 19:24
  • This a good duplicate then? [File Size Goes to Zero when Returning FileStreamResult from MVC Controller](https://stackoverflow.com/a/27152415/3744182). – dbc Aug 15 '22 at 19:32
  • Yeah I think thats close enough for a duplicate – Mike Aug 15 '22 at 19:40

0 Answers0