CsvHelper icon indicating copy to clipboard operation
CsvHelper copied to clipboard

Never returns when using GetRecordsAsync

Open Sellorio opened this issue 4 years ago • 15 comments
trafficstars

Describe the bug

I output a file using the library. No problems. I try to read the same file to the same data structure. Program is stuck on GetRecordsAsync endlessly.

To Reproduce

As stated above. Really simple use case.

Switching to GetRecords works so it's clearly not any issues on my end.

Expected behavior

Should work.

There is absolutely no circumstance where a library should just hold a thread forever. If there is an error, bubble it up. Never use infinite loops.

Needless to say, after spending ages dealing with this, I'm very frustrated.

Sellorio avatar Mar 23 '21 10:03 Sellorio

Can you give a small example that reproduces this?

JoshClose avatar Mar 23 '21 16:03 JoshClose

private async Task SaveAsync()
{
    var directory = Path.GetDirectoryName(Filename);

    if (!Directory.Exists(directory))
    {
        Directory.CreateDirectory(directory);
    }

    using var stream = new StreamWriter(Filename);
    using var csvWriter = new CsvWriter(stream, CultureInfo.InvariantCulture);

    await csvWriter.WriteRecordsAsync(_data);
}

public static async Task<VocabularyUserData> LoadAsync()
{
    if (File.Exists(Filename))
    {
        using var stream = new StreamReader(Filename);
        using var csvReader = new CsvReader(stream, CultureInfo.InvariantCulture);

        return new VocabularyUserData(await csvReader.GetRecordsAsync<VocabularyUserDataItem>().ToListAsync());
    }
    else
    {
        return new VocabularyUserData(new List<VocabularyUserDataItem>());
    }
}

private class VocabularyUserDataItem
{
    public string Kanji { get; set; }
    public DateTime LastAnswered { get; set; }
    public int Rank { get; set; }
}

I'm saving the file using SaveAsync so only CSV Helper is interacting with the file (so the format can't be wrong).

I've debugged it a fair bit so I can confirm it's the GetRecordsAsync and not anywhere else that it is getting stuck.

Sellorio avatar Mar 23 '21 22:03 Sellorio

Now also experiencing lock ups during save.

Sellorio avatar Mar 23 '21 23:03 Sellorio

And the data was lost despite failing to save.

Sellorio avatar Mar 23 '21 23:03 Sellorio

Try putting brackets in for your using blocks.

using var stream = new StreamWriter(Filename);
using var csvWriter = new CsvWriter(stream, CultureInfo.InvariantCulture);
{
    await csvWriter.WriteRecordsAsync(_data);
}

JoshClose avatar Mar 24 '21 15:03 JoshClose

This won't make a difference. Even before the new using syntax was implemented, having no braces would be equivalent to the following:

using (var stream = new StreamWriter(Filename))
{
    using (var csvWriter = new CsvWriter(stream, CultureInfo.InvariantCulture))
    {
        await csvWriter.WriteRecordsAsync(_data);
    }
}

Sellorio avatar Mar 24 '21 20:03 Sellorio

I'm not able to reproduce the issue.

Here is my test code.

async Task Main()
{
	var records = new List<VocabularyUserDataItem>();
	for (var i = 0; i < 1_000_000; i++)
	{
		var row = i + 1;
		records.Add(new VocabularyUserDataItem
		{
			Kanji = $"row {i}",
			LastAnswered = DateTime.Now,
			Rank = row,
		});
	}
	
	var path = @"C:\Users\narsh\Documents\issue-1751.csv";
	var config = new CsvConfiguration(CultureInfo.InvariantCulture)
	{
	};
	using (var stream = File.Open(path, FileMode.Create))
	using (var writer = new StreamWriter(stream))
	using (var csv = new CsvWriter(writer, config))
	{
		await csv.WriteRecordsAsync(records);
	}
}

private class VocabularyUserDataItem
{
	public string Kanji { get; set; }
	public DateTime LastAnswered { get; set; }
	public int Rank { get; set; }
}

JoshClose avatar Mar 24 '21 20:03 JoshClose

Your code is not similar to mine.

Also this issue is for GetRecordsAsync not write.

Sellorio avatar Mar 24 '21 22:03 Sellorio

Oops. You mentioned saving issues so I got that mixed up.

This works for me. Can you update this so it fails?

async Task Main()
{
	var path = @"C:\Users\narsh\Documents\issue-1751.csv";
	var config = new CsvConfiguration(CultureInfo.InvariantCulture)
	{
	};
	using var reader = new StreamReader(path);
	using var csv = new CsvReader(reader, config);

	var records = await csv.GetRecordsAsync<VocabularyUserDataItem>().ToListAsync();
}

private class VocabularyUserDataItem
{
	public string Kanji { get; set; }
	public DateTime LastAnswered { get; set; }
	public int Rank { get; set; }
}

JoshClose avatar Mar 25 '21 15:03 JoshClose

@JoshClose I also tried your code for async but does not work gives error.

Error CS1061 'IAsyncEnumerable<VocabularyUserDataItem>' does not contain a definition for 'ToListAsync' and no accessible extension method 'ToListAsync' accepting a first argument of type 'IAsyncEnumerable<VocabularyUserDataItem>' could be found (are you missing a using directive or an assembly reference?)

CSVHelper version 27.2.1 dotnet version 6.0

Alik2015 avatar Feb 24 '22 22:02 Alik2015

I am also experiencing this issue for csv.GetRecordsAsync(...) CSVHelper version 27.2.1 dotnet version 6.0

wongomao avatar Apr 18 '22 12:04 wongomao

@Alik2015 ToListAsync is a part of System.Linq in assembly System.Linq.Async.

JoshClose avatar Apr 27 '22 19:04 JoshClose

If someone can give me a unit test that produces the issue, I'll take a look at it. Right now I can't reproduce it.

JoshClose avatar Apr 27 '22 19:04 JoshClose

Same issue. Never returns. No error message. csv file is 13kb.

Edit: I have a similar issue with stream.CopyToAsync which isn't a part of csvhelper, so beginning to think this is a signalR issue.

Edit 2: I believe I found the issue. If this is happening to you when reading a memory stream directly from a blazor file input (such as was the case with me), it will cause significant memory issues. See [here].(https://docs.microsoft.com/en-us/aspnet/core/blazor/file-uploads?view=aspnetcore-5.0&pivots=server) The Getrecordsasync method works fine after this.

MaxBrooks114 avatar Jun 17 '22 15:06 MaxBrooks114

I believe the folks in this issue are experiencing a deadlock caused by running in a SynchronizationContext (blazor server, or window GUI app for example). There are a few missing ConfigureAwait(false) calls in the code that I think are the culprits. PR #2007 should hopefully resolve it.

MarkPflug avatar Jul 22 '22 18:07 MarkPflug

I am still seeing the issue with version 30.0.1 on .NET7. Getting null from "GetRecordsAsync". No error with "GetRecords" method Anyone else?

supershopping avatar Feb 09 '23 17:02 supershopping