How To: Kinetic - Upload a Client File, Parse, and Display in a Grid

Another How To for how to use the File Picker Client control and file-erp-transfer widget.
This tutorial will go over how to wire up the controls, pass the file to a function, parse the data, return the dataset to App Studio, and display the rows in a grid.

  1. Create a DataView holder

  1. Create a grid and bind it to the new DataView from Step 1.

  1. Add the File Picker Client (or server) control to your form and bind it to something. I used TransView because it’s runtime and I don’t need to save the file after the fact.

  1. Add a button and create an OnClick event for it.

  2. In the OnClick event, add the file-transfer-erp widget. This will upload the file from your client to the server.

Special Folder - This will be the directory accessible to you on the server (yes, even you SaaSy folks!). I typically just use CompanyData
Server Path - If you want it at the root, just set it to the EpBinding that you set your File Picker to be (Mine is TransView.File) with the standard {} syntax. I’m adding an additional directory to mine called “Uploads”, but this is something only On Prem folks can do, I believe. Or else, you would need support to add it for you.
Client Path - Didn’t see a need for this.
Company - Optional, Company ID
Transfer Type - Upload to, well, upload!!
ErpFileBoxID - This is the ID from your File Picker Client control

  1. On the file-transfer-erp widget, click on Behavior → OnSuccess and wire it to an erp-function widget

  1. Pass in the file name from the control’s binding

  1. Set up the response based on how you wrote/named your function.

Parameter Name - The name of the DataTable
View Name - The View that you created in step 1
Parse from Response Path - Your DataSet output parameter from the function

  1. Create and set up your function (If you use mine, you’ll need to edit it and change the server path)
    MISC2.efxb (2.5 KB)

using System.IO;

string filePath = @"\\SERVER\EpicorData\APP\Companies\Company\Uploads\"; //Change this to be your server location to where you uploaded the file from the erp-file-transfer widget
bool locked = true;

// Waits until the file is done being combined
do
{
  locked = false;
  try
  {
      FileStream fs =
          File.Open(Path.Combine(filePath, FileName), FileMode.Open,
          FileAccess.Read, FileShare.None);
      fs.Close();
  }
  catch (IOException ex)
  {
      locked = true;
  }
}
while( locked );

using( StreamReader sr = new StreamReader(Path.Combine(filePath, FileName)) )
{
  string row = "";
  DataSet thisDS = new DataSet();
  thisDS.Tables.Add("CSVRows");
  DataTable dt = thisDS.Tables["CSVRows"];
    
  while(!string.IsNullOrEmpty(row = sr.ReadLine()))
  {
    string[] cols = row.Split(','); 
    
    var dr = dt.NewRow();
    
    // You can be more creative with the column headers here
    for(int i = 0; i < cols.Count(); i++)
    {  
      if( !dt.Columns.Contains("Col" + i.ToString()) )
        dr.Table.Columns.Add("Col" + i.ToString());
      dr["Col" + i.ToString()] = cols[i].ToString().Replace("\"","");
    }
    
    dt.Rows.Add(dr);
  }
  
  OutDS = thisDS;
}

FilePicker

Special thanks to @klincecum for poking the file transfer bit.

10 Likes

Great work! Thanks to both of you.

I can do it :slight_smile:

But anyway, nice job writing it up. I’m sure I’ll reference it in the future.

As far as your function, I believe Epicor has a prebuilt class or helper method that parses CSV files
for us if we can find it.

I just assume SaaS-a-frass can’t do anything except cry in frustration. :slight_smile:

Interesting! I’ll take a gander.

Now which library I came across it in is anyone’s guess. I didn’t use it, just saw it :slight_smile:

See the top part of this post.

@hkeric.wci :metal:

3 Likes

This guide has been really helpful to me. Thank you!

I have an issue regarding the refresh of the grid. If you :

  1. Upload a CSV;
  2. Add, edit, or delete columns in the CSV file;
  3. Reupload the CSV;
    ===> the Kinetic grid columns are not updated.

I clear the dataview using the dataview-clear widget when the upload button is clicked. Is there something else I could try?

I’m wondering if we could make a blank “template” dataset, and use dataview-copy to overwrite
it.

Poke it and let us know :slight_smile:

I played with the dataview-copy widget. Same issue. I appreciate the suggestion!

What’s strange is that the Debug Tool work as intended.

For example, I uploaded a CSV. I removed a column from the CSV file, then reuploaded it. The grid still displays the removed column, but the Debug Tool did remove the column.

I’ll have to look into that.

The Debug Tool is a nice addition. It still forget about it sometimes and use the CTRL+ATL+V command to display the DataViews in the browser Developer Tools console.

Just found out that expanding / collapsing a panel does refresh the columns. It would be great if I could just find the event to trigger that grid refresh.

I may end up triggering a collapse / expand of the Import CSV panel after the import is done. Not an ideal solution though! :slight_smile:

Where is the SpecialFolder path located? For instance, if I have CompanyData selected, is this going to drop it in my EpicorData\Companies\Company\ folder? If so, I may be creating a new help topic haha.

Wish all of these actions were better documented by Epicor :confused:

Mmm, it’s been a hot minute, but yes–I do believe it will be dropped there.

1 Like

Hi,
I am trying to follow this and have successfully uploaded the files to the following location

image

However, I cannot find the files physically on the server after searching for them in file explorer.

Any ideas where ‘server\uploads’ may be?

Thanks,

Andrew.

I found it - it was on our separate reports server.

Thanks so much for taking the time to write the article.

Pretty close to the csvLoader Func I made a while ago using MS VB TextFieldParser. Mine uses first row as column names.

Awesome writeup Hanna!

  /// C# CSV Loader Func
  Func<string, DataTable> CsvLoadTo =
    (filePath) =>
  {
    DataTable csvImport = new DataTable("csvImport");
    if (filePath != String.Empty)
    {
      DataRow dataRow;
      List<string> oFieldNames = new List<string>();
      csvImport.Clear();
      using (TextFieldParser parser = new TextFieldParser(filePath))
      {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        System.Type vt;
        decimal dv;
        bool badData = false;
        int r = 0, c = 0, iv = 0;
        while ((!parser.EndOfData) && (!badData))
        {
          string[] fields = parser.ReadFields();
          c = 0;
          dataRow = csvImport.NewRow();
          foreach (string field in fields)
          {
            if (r == 0)
            {
              if (field == null || field == String.Empty)
              { badData = true; break; }
              else
              { oFieldNames.Add(field); }
            }
            else
            {
              if (field == null)
              {
                badData = true;
                break;
              }
              else
              {
                vt = typeof(String);
                if (decimal.TryParse(field, out dv))
                {
                  if (int.TryParse(field, out iv))
                  {
                    dataRow[oFieldNames[c]] = field;
                  }
                  else
                  {
                    dataRow[oFieldNames[c]] = field;
                  }
                }
                else
                {
                  dataRow[oFieldNames[c]] = field;
                }
              }
              c++;
            }
          }
          if (r != 0)
          {
            csvImport.Rows.Add(dataRow);
          }
          else
          {
            foreach (string colName in oFieldNames)
            {
              csvImport.Columns.Add(colName);
            }
          }
          r++;
        }
      }
    }
    return csvImport;
  };
1 Like

I know this is a bit of an aged thread but I was wondering if this is still working in the most current version. I’m getting an error when saving the function:
ParseCSV.cs(36,23): warning ECF1002: The ‘System.IO.File.Open(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare)’ method cannot be called.
ParseCSV.cs(48,38): warning ECF1002: The ‘System.IO.StreamReader.StreamReader(string)’ constructor cannot be called.

We have a different function that gives errors like that when we save it, but the function then works fine. Our consultant has been told by Epicor that the errors we see are meaningless (and presumably will go away in the future).

For example, we see errors like this:

warning ECF1002: The ‘System.IO.File.AppendText(string)’ method cannot be called.

warning ECF1002: The ‘System.IO.Directory.GetFiles(string, string)’ method cannot be called.

1 Like

They say error, but they are just warnings.

These can be safely ignored :slight_smile: