Sunday, January 31, 2016

ASP.NET MVC web application : How to Read CSV File


Introduction

This article shows you two methods to read data from CSV (Comma Separated File) file:
  • First method: Reading CSV file without any specific library
  • Second method: Reading CSV File using LinqToCsv lib

Using the Code

Before we begin the explanation of example, let's know about CSV file.

a) CSV File

A Comma Separated File stores tabular data (text, number) in plain text each line of file is a record, and each record consists of many fields separated by delimiter (',' , ';' , etc.).
Example of CSV content:

Names,Dates
Name 1,12/12/2015
Name 2,12/11/2015

The scenario adopted in the next examples:
User must choose between the method of parsing CSV file (with or not using the LinqToCsv library), click on the Parser button to send an HTTP request to the server to analyze CSV file (that exists in server Resources) and return a result as List.
In this application, we considered the first record of CSV file as header:

 
 

b) First Method

The following example considers a CSV File as a plain text, and according to the definition of CSV, the parsing is done.

1) First Implementation :

 public IEnumerable<Person> Method1(string fileSrc, char sep)  
    {  //Without using LinqToCsv lib  
      var list = new List<Person>();  
      var reader = new StreamReader( fileSrc );  
      bool header = true;  
      while (!reader.EndOfStream)  
      {  
        //get the first line  
        var line = reader.ReadLine();  
        //specify the separator line  
        //Split : string is separated by a delimiter to form a table as result  
        if(header == true)  
        { //escape first line  
          header = false;  
        }  
        else  
        {  
          var values = line.Split(sep);  
          Person person = new Person();  
          person.Name = values[0];  
          person.Date = values[1];  
          list.Add(person);  
        }  
      }  
      return list.AsEnumerable();  
    }  
 

2) Exception :


Or this code cannot handle the case when we add separator character into data fields.
Example to better understand :


1) Edit CSV file by using an editor :




2) When you run parsing you will get a wrong result :



To improve it we will use the Microsoft.VisualBasic.FileIO.TextFieldParser (see documentation), the most suitable class for better analyse CSV file.
Then the code will be : 

3) Second Implementation :


First, To use TextFieldParse you must add Microsoft.VisualBasic in your project references.

 
 
- Code C# :
 public IEnumerable<Person> Method1(string fileSrc, string sep)  
     {  //Without using LinqToCsv lib  
       var list = new List<Person>();  
       bool header = true;  
       using (TextFieldParser parser = new TextFieldParser(fileSrc))  
       {  
         parser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited;  
         //specify the delimiter  
         parser.SetDelimiters(sep);  
         while (!parser.EndOfData)  
         {  
           //read Fileds  
           string[] fields = parser.ReadFields();  
           //Processing row  
           if (header == true)  
           { //escape first line  
             header = false;  
           }  
           else  
           {  
             Person person = new Person();  
             person.Name = fields[0];  
             person.Date = fields[1];  
             list.Add(person);  
           }  
         }  
       }  
       return list.AsEnumerable();  
     }  

- Correct Result : 


c) Second Method

In this example, we used the LinqToCSV Library to do the parsing.

1) Requirements

Add the LinqToCsv lib to your project references.

2) Implementation

 public IEnumerable<Person> Method2(string fileSrc, char sep)  
   { //Using LinqToCsv lib  
     CsvFileDescription inputFileDescription = new CsvFileDescription  
     {  
       SeparatorChar = sep,//specify the separator line  
       FirstLineHasColumnNames = true //Header is in the first line  
     };  
     CsvContext csvContext = new CsvContext();  
     IEnumerable<Person> list =  
       csvContext.Read<Person>(fileSrc, inputFil, Description);  
     // Data is now available via variable list.  
     return list;  
   }  

d) Extra Code for Two Methods

1) Code HTML

 <div class="row">  
   <div class="col-lg-12">  
     <form class="form" method="POST"   
     action="/Home/Index">  
       <div class="form-group">  
         <label>Choose a method :</label>  
         <br>  
         <input type="radio" name="method"   
         value="0" checked />   
   Method 1 : without LinqToCSV lib<br>  
         <input type="radio" name="method"   
         value="1" /> Method 2 : LinqToCSV lib  
       </div>  
       <div class="form-group">  
         <input type="submit"   
         class="form-control btn btn-default"   
          value="Start parsing" />  
       </div>  
     </form>  
   </div>  
 </div>  
 <hr>  
 <div class="row">  
   <div class="col-lg-12">  
      <label>Parsing result :</label>  
   </div>  
 </div>  
 <div class="row">  
   <div class="col-sm-4">  
     <table class="table">  
       @if (@Model != null)  
       {  
         @Html.Raw("<thead><th>Names</th>  
         <th>Dates</th></thead><tbody>");  
         foreach (var elem in @Model as IEnumerable  
         <WebApplicationReadingCSVFile.Models.Person>)  
          {  
            @Html.Raw("<tr ><td>" +   
            @elem.Name + "</td><td>" +   
            @elem.Date + "</td></tr>");  
          }  
         @Html.Raw("</tbody>");  
       }  
     </table>  
   </div>  
   <div class="col-sm-8"></div>  
 </div>  

2) Code C# ASP.NET MVC

- Class Person: It contains the record fields:

 public class Person  
  {  
    //CsvColumn is key word used by LinqToCSV  
    //CsvColumn : specify the Name of Header and the index of column  
    [CsvColumn(Name = "Names", FieldIndex = 1)]  
    public string Name { get; set; }  
    [CsvColumn(Name = "Dates", FieldIndex = 2)]  
    public string Date { get; set; }  
  }  

 
- Action Index: is the entry point of the parsing methods:
 public ActionResult Index()  
  {  
   //get the selected radio value  
   string method = Request.Params["method"];  
   char sep = ';';  
   //initialize list  
   IEnumerable<Person> list = new List<Person>();  
   if (method != null && method != "")  
    {  
     //Get Server Path of CSV file  
     string fileSrc = Server.MapPath("~/Content/Files/CsvFile.csv");  
     //Build Result  
     if (method == "0")  
     {  
       list = Method1(fileSrc, sep);  
     }  
     else{  
       list = Method2(fileSrc, sep);  
     }  
     //return the list as Enumerable  
    }  
    return View(list);  
  }  

e) Result

 

History of updates

v1 : we used split and LinqToCSV.
v2 : we replaced split by using Microsoft.VisualBasic.FileIO.TextFieldParser due an error in parsing.

No comments:

Post a Comment