3

I'm uploading CSV file from client to .NET CORE Web Api app.

I'm using CsvHelper .net library.

I receive file successfully and I would like to parse it to my custom classes so I could loop throught the rows from csv.

But everytime I get Empty result like there are no rows.

I'm not sure what is wrong with my approach:

[HttpPost("import")]
public async Task<ActionResult> ImportData([FromForm] IFormFile file)
{

    using var memoryStream = new MemoryStream(new byte[file.Length]);
    await file.CopyToAsync(memoryStream);
    memoryStream.Position = 0;

    using (var reader = new StreamReader(memoryStream))
    using (var csvReader = new CsvReader(reader, System.Globalization.CultureInfo.InvariantCulture))
    {
        csvReader.Read();
        var records = csvReader.GetRecords<SiteDto>();
    }

    return Ok("ok");
}

This is how my CSV looks a like:

enter image description here

My Site Dto:

public class SiteDto
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
    public string CompanyName { get; set; }
    public string Location { get; set; }
}

And when I expand my result I saw something like warning about some headers? enter image description here

4
  • @maytham-ɯɐɥʇʎɐɯ tried allready with try-catch. Does this have anything somewith with headers? Check for my edit please Commented Jan 18, 2021 at 22:33
  • Have you tried either changing the class property names or giving them manual Name attributes to match your csv file? Commented Jan 18, 2021 at 22:42
  • @maytham-ɯɐɥʇʎɐɯ That’s not how using var works - it gets disposed when it goes out of scope. Commented Jan 18, 2021 at 23:45
  • @stuartd sure agree, this is what happen when I comment late around sleeping time 😁 Commented Jan 19, 2021 at 7:53

3 Answers 3

2

I have created generic csv file converter to list of T type

public static class CSVParser
{
    
   
    public static DataTable ConvertCSVtoDataTable(IFormFile file)
    {
        DataTable dt = new DataTable();
        using (var stream = file.OpenReadStream())
        using (StreamReader sr = new StreamReader(stream))
        {
            string[] headers = sr.ReadLine().Split(',');
            foreach (string header in headers)
            {
                dt.Columns.Add(header);
            }
            while (!sr.EndOfStream)
            {
                string[] rows = sr.ReadLine().Split(',');
                DataRow dr = dt.NewRow();
                for (int i = 0; i < headers.Length; i++)
                {
                    dr[i] = rows[i];
                }
                dt.Rows.Add(dr);
            }

        }


        return dt;
    }
    public static List<T> ConvertDataTable<T>(DataTable dt)
    {
        List<T> data = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            T item = GetItem<T>(row);
            data.Add(item);
        }
        return data;
    }
    private static T GetItem<T>(DataRow dr)
    {
        Type temp = typeof(T);
        T obj = Activator.CreateInstance<T>();

        foreach (DataColumn column in dr.Table.Columns)
        {
            foreach (PropertyInfo pro in temp.GetProperties())
            {
                 

            if (pro.Name == column.ColumnName)
                {
                    var typeGEt = pro.PropertyType;
                    Type type = Nullable.GetUnderlyingType(pro.PropertyType) ?? pro.PropertyType;
                    string typeName = type.Name;

                   try
                    {
                        if (typeName == "Int16" || typeName == "Int32" || typeName == "Int64")
                        {
                            pro.SetValue(obj, Convert.ToInt32(dr[column.ColumnName]), null);

                        }
                        else if (typeName == "DateTime")
                        {

                            pro.SetValue(obj, DateTime.ParseExact((string)dr[column.ColumnName], "mm/dd/yyyy", CultureInfo.InvariantCulture), null);

                        }
                        else
                        {
                            pro.SetValue(obj, dr[column.ColumnName], null);

                        }
                    }

                    catch(Exception ex)
                    {
                        continue;

                    }



                }
                else
                    continue;
            }
        }
        return obj;
    }


    public static IEnumerable<T> toList<T>(this DataTable? dt)
    {
        List<T> data = new List<T>();
        foreach (DataRow row in dt.Rows)
        {
            T item = GetItem<T>(row);
            data.Add(item);
        }
        return data;
    }

    public static string getExtension(this string name)
    {
       return Path.GetExtension(name);
        
    }
    public static IEnumerable<T> CSVToList<T>(this IFormFile? file)
    {
        if (file != null)
        {
             if (file.FileName.getExtension() != ".csv")
                throw new Exception("File is not valid CSV");
            else
                return ConvertCSVtoDataTable(file).toList<T>();

        }
        else
            throw new Exception("File can not be empty");
    }
 }

To use this

postedFile.CSVToList<TypeModal>();

postedFile is IFormFile and TypeModal is Entity

Sign up to request clarification or add additional context in comments.

1 Comment

Hi Ahsan Ismail, whilst you answer provides a possible solution to reading CSV files in general. I'm not sure that it actually answers the original question which is about how to use the CsvHelper .NET library to read a CSV.
1

https://joshclose.github.io/CsvHelper/getting-started

The GetRecords method will return an IEnumerable that will yield records. What this means is that only a single record is returned at a time as you iterate the records.

Try calling ToList() to iterate the records and remove csvReader.Read();. GetRecords() calls Read() internally. Using both is causing CsvReader to skip the header row.

using (var reader = new StreamReader(memoryStream))
using (var csvReader = new CsvReader(reader, System.Globalization.CultureInfo.InvariantCulture))
{
    var records = csvReader.GetRecords<SiteDto>().ToList();
}

Also add a name attribute to your class, so that CsvHelper knows how to map the Id property.

public class SiteDto
{
    [Name("SiteId")]
    public long Id { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
    public string CompanyName { get; set; }
    public string Location { get; set; }
}

Comments

1
public List<organizations> ReadCSVFile([FromForm] UploadFile location)
{
  try
  {
    using var memoryStream = new MemoryStream(new byte[location.Files.Length]);
    location.Files.CopyToAsync(memoryStream);
    memoryStream.Position = 0;
    using (var reader = new StreamReader(memoryStream))
    using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
      csvReader.Context.RegisterClassMap<organizationsMap>();
      var records = csvReader.GetRecords<organizations>().ToList();
      return records;
    }
  }
  catch (Exception e)
  {
    throw e;
  }
  return null;
}

2 Comments

you can try above it's a running code
Your answer could be improved by adding more information on what the code does and how it helps the OP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.