Reputation: 1142
I'm trying to parse a csv file to a list of item of a a given class. I'm pretty new to dotnet world. I'm using .NET (2.2.402) This is the code for my class
public class ItemResource
{
public string Msisdn { get; set; }
public float Amount { get; set; }
public string PersonName { get; set; }
public string Message { get; set; }
public string Description { get; set; }
/// <summary>
/// Tells wether or not the customer will receive a notification
/// </summary>
///
public int Notify { get; set; }
}
This is the section of the code where I try to parse the file
StreamReader reader = new StreamReader("path-to-file.csv");
var csvReader = new CsvReader(reader);
//csvReader.Configuration.Delimiter = ";";
//csvReader.Configuration.HeaderValidated = null;
var records = csvReader.GetRecords<ItemResource>();
_logger.LogInformation(records.Count().ToString());
foreach(var record in records)
{
_logger.LogInformation(record.ToString());
}
This is the content of the file
Msisdn, Amount, PersonName, Message, Description, Notify
69947943,150,Name 1,TEST,Test,1
69947943,150,Name 2,TEST,Test,1
69947943,150,Name 3,TEST,Test,1
69947943,150,Name 4,TEST,Test,1
69947943,150,Name 4,TEST,Test,1
69947943,150,Name 5,TEST,Test,1
As you can see for the sake of the test, I harcoded the path. This is the error I'm getting
CsvHelper.HeaderValidationException: Header with name 'Msisdn' was not found. If you are expecting some headers to be missing and want to ignore this validation, set the configuration HeaderValidated to null. You can also change the functionality to do something else, like logging the issue. at CsvHelper.Configuration.ConfigurationFunctions.HeaderValidated(Boolean isValid, String[] headerNames, Int32 headerNameIndex, ReadingContext context) at CsvHelper.CsvReader.ValidateHeader(ClassMap map) at CsvHelper.CsvReader.GetRecordsT+MoveNext() at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source) at OMBulkPayment.Controllers.PaymentsController.Payment(SavePaymentResource resource) in C:\Users\BMHB8456\source\repos\OMBulkPayment\OMBulkPayment\Controllers\PaymentsController.cs:line 59 at lambda_method(Closure , Object , Object[] ) at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters) at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
Upvotes: 0
Views: 1290
Reputation: 388
Nice find on using CSVHelper, it's an open source project and is the easiest library I've found to use.
I tried the following with your test data and was able to successfully get it working:
void Main()
{
using (var reader = new StreamReader("D:\\PROJECTS\\2019\\DVP_Salary_Payment_Local\\Payment\\test_2.csv"))
using (var csv = new CsvReader(reader))
{
csv.Configuration.Delimiter = ",";
var records = csv.GetRecords<ItemResource>();
}
}
public class ItemResource
{
public string Msisdn { get; set; }
public float Amount { get; set; }
public string PersonName { get; set; }
public string Message { get; set; }
public string Description { get; set; }
public int Notify { get; set; }
}
You can view a nearly identical example listed on their site here.
Upvotes: 2
Reputation: 623
Explicitly set the delimiter. Replace the line
//csvReader.Configuration.Delimiter = ";";
with
csvReader.Configuration.Delimiter = ",";
The default delimiter depends on the system's regional settings called List separator.
Also remove spaces between header name of csv file. Keep them like below:
Msisdn,Amount,PersonName,Message,Description,Notify
Upvotes: 1
Reputation: 1839
Not really sure about CsvHelper, but you don't really need any extra components to read CSV files natively... You can use OleDb to read it as a flat data file:
public DataTable ReadCsv(string filename, bool hasHeaders = true, string delimiter = ",")
{
var dt = new System.Data.DataTable();
var fi = new System.IO.FileInfo(filename);
var connStr = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"{0}\";Extended Properties='text;HDR={1};FMT=Delimited({2})';",
fi.DirectoryName,
((hasHeaders) ? "Yes" : "No"),
delimiter);
var commStr = string.Format("SELECT * FROM [{0}]", fi.Name);
using (var conn = new System.Data.OleDb.OleDbConnection(connStr))
using (var cmd = new System.Data.OleDb.OleDbCommand(commStr, conn))
using (var adapter = new System.Data.OleDb.OleDbAdapter(cmd))
{
adapter.Fill(dt);
}
return dt;
}
This also has the advantage to be able to query for specific rows to return by changing the SELECT query, which you could also pass as a parameter. If you absolutely want typed data instead of strings, just create the columns manually on the datatable before calling Fill() on the adapter.
Upvotes: 0