1

I'm trying to import an Excel file. This is how my Import method looks like. What I'm doing here is just adding the excel data into a data-table and converting that data-table into a dynamic list and returning it to the controller method:

public List<dynamic> ImportFile(Stream stream)
{
    var productList = new List<Products>();
    using (var package = new ExcelPackage(stream))
    {
        var currentSheet = package.Workbook.Worksheets;
        var workSheet = currentSheet.First();

        //Creating a DataTable
        DataTable tbl = new DataTable();
        bool hasHeader = true; // adjust it accordingly( i've mentioned that this is a simple approach)

        //Creating the header
        foreach (var firstRowCell in workSheet.Cells[1, 1, 1, workSheet.Dimension.End.Column])
        {
            tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
        }

        var startRow = hasHeader ? 2 : 1;
        ////Inserting the stream into DataTable
        for (var rowNum = startRow; rowNum <= workSheet.Dimension.End.Row; rowNum++)
        {
            var wsRow = workSheet.Cells[rowNum, 1, rowNum, workSheet.Dimension.End.Column];
            var row = tbl.NewRow();
            foreach (var cell in wsRow)
            {
                row[cell.Start.Column - 1] = cell.Text;
            }
            tbl.Rows.Add(row);
        }
        //Convert datatable into dynamic list
        var dynamicDt = new List<dynamic>();
        foreach (DataRow row in tbl.Rows)
        {
            dynamic dyn = new ExpandoObject();
            dynamicDt.Add(dyn);
            foreach (DataColumn column in tbl.Columns)
            {
                var dic = (IDictionary<string, object>)dyn;
                dic[column.ColumnName] = row[column];
            }
        }
        return dynamicDt;
    }
}

This is how my controller method looks like:

[HttpPost]
public ActionResult Upload(HttpPostedFileBase upload)
{
    IExcelImporter reader = new ExcelImporter();
    var res = new List<dynamic>();
    List<Products> send = new List<Products>();
    if (ModelState.IsValid)
    {
        if (upload != null && upload.ContentLength > 0)
        {
            Stream stream = upload.InputStream;

            if (upload.FileName.EndsWith(".xlsx"))
            {
                //getting the dynamic list(returning dynamic list)
                res = reader.ImportFile(stream);

                //need to bind it a model-class(Products)
                send = res.Select(x=> 
                new Products
                {
                    ID = res.GetType().GetProperty("ID").ToString(),
                    Name = res.GetType().GetProperty("Name").ToString(),
                    //res.Select(e=>e.Price).ToString()//res.GetType().GetProperty("Price").GetValue(res, null).ToString()
                }).ToList(); 
            }
        }
    }
    return View("Index", send);
}

Question: What I want is to bind the dynamic list to a model-class(Products). So that I can return it to the View. How do I map the dynamic list to List Products?

This is how my IExcelImporter looks like:

public interface IExcelImporter
{
    List<dynamic> ImportFile(Stream stream);
}

This is how my Products Model looks like:

public class Products
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string Price { get; set; }

}

Can someone please give me an idea how to solve this. Thank you in advance.

tereško
  • 58,060
  • 25
  • 98
  • 150
Dayan
  • 711
  • 5
  • 16
  • 27
  • 1
    What's wrong with what you got? – jamesSampica Mar 22 '16 at 02:57
  • I can't map the dynamic list to the model class(Products) to return the view – Dayan Mar 22 '16 at 03:04
  • Looks like to me you're performing some reflection to get the dynamic properties and project them into your model class. Is that not working? What's wrong? – jamesSampica Mar 22 '16 at 04:33
  • You are assigning the wrong values to your Product properties. You should use the value of the property, not the name. Check this answer out which has extension methods you can use. http://stackoverflow.com/a/1954663/1009036 – Krishna Veeramachaneni Mar 22 '16 at 04:39
  • #shoe dynamic properties are not giving me the values. values are always null – Dayan Mar 22 '16 at 05:55

1 Answers1

1

On a general note, I see no reason for using dynamic as the return type. Your ImportFile method could return IEnumerable<Dictionary<string, string>>. Also, why a DataTable? I am guessing you are using to much copy-paste from another example which is using a DataTable for database use, better to create an additional list to store the column names and use them as keys in your dictionary, this will save you a lot of casting. Unless you are showing a highly simplified example, your ImportFile method has a lot of overhead both in readability and performance.

To directly answer your question though,

Here you are getting PropertyInfo of non-existing property "ID" of List<dynamic> - not what you want.

res.GetType().GetProperty("ID").ToString() 

instead you should use

// Get value of dynamic property "ID" of an item when iterating over of List<dynamic>
x.ID.ToString()
Tewr
  • 3,713
  • 1
  • 29
  • 43