title: How To Import and Display Excel (.xlsx) File to Blazor WASM Client Side (Without Uploading to Server)
body: <p>Like the title says. Lots of examples online for uploading files to backend but I'm after verification client side/offline followed by an upload of data only (no files). In theory, anything that runs on .Net5 should be able to run in WASM at a close performance. I'm trying to unload those hefty operations to clients' machines.</p>
  <p>I've had some success with ClosedXML but when the file is a few 1000 rows it becomes incredibly slow. Using ClosedXML in Blazor Server-Side loads 100,000's rows with ease.</p>
  <p>Notes:</p>
  <ul>
  <li>Using MudBlazor UI Components</li>
  <li>I have a stream from file instead of a file path for ClosedXML (like I would on a console app), I think this is the only way in WASM but I may be wrong.</li>
  <li>I've ran the same in NPOI with similar results (slow in WASM, fast in Server Side).</li>
  <li>I'd prefer to avoid EPPlus unless it has a magical fix.</li>
  </ul>
  <p>Page:</p>
  <pre><code>@page &quot;/upload&quot;
  @inject HttpClient Http
  
  &lt;h1&gt;Upload Data&lt;/h1&gt;
  
  &lt;p&gt;This component demonstrates uploading data from Excel.&lt;/p&gt;
  
  &lt;InputFile id=&quot;fileInput&quot; OnChange=&quot;UploadFiles&quot; hidden single /&gt;
  
  &lt;MudButton HtmlTag=&quot;label&quot;
             Variant=&quot;Variant.Filled&quot;
             Color=&quot;Color.Primary&quot;
             StartIcon=&quot;@Icons.Filled.CloudUpload&quot;
             for=&quot;fileInput&quot;&gt;
      Upload Files
  &lt;/MudButton&gt;
  
  @if (dataTable == null)
  {
      &lt;p&gt;&lt;em&gt;Please upload Excel File&lt;/em&gt;&lt;/p&gt;
  }
  else
  {
      &lt;MudTable Items=&quot;@dataTable.AsEnumerable().Take(500)&quot; Hover=&quot;true&quot; Breakpoint=&quot;Breakpoint.Sm&quot; T=&quot;DataRow&quot; RowsPerPage=&quot;100&quot;&gt;
          &lt;HeaderContent&gt;
              @foreach (DataColumn col in dataTable.Columns)
              {
                  &lt;MudTh&gt;@col.ColumnName&lt;/MudTh&gt;
              }
          &lt;/HeaderContent&gt;
          &lt;RowTemplate&gt;
              @foreach (var cell in context.ItemArray)
              {
                  &lt;MudTd&gt;@cell.ToString()&lt;/MudTd&gt;
              }
          &lt;/RowTemplate&gt;
      &lt;/MudTable&gt;
  }
  
  @code {
      //private IList&lt;IBrowserFile&gt; files = new List&lt;IBrowserFile&gt;();
      private DataTable dataTable;
  
      protected override async Task OnInitializedAsync()
      {
      }
  
      private async Task UploadFiles(InputFileChangeEventArgs e)
      {
          dataTable = await ExcelHelper.GetDataTableFromExcel(e.File);
      }
  }
  </code></pre>
  <p>Function:</p>
  <pre><code>public static async Task&lt;DataTable&gt; GetDataTableFromExcel(IBrowserFile file)
          {
              DataTable dtTable = new DataTable();
  
              using (MemoryStream memStream = new MemoryStream())
              {
                  await file.OpenReadStream(file.Size).CopyToAsync(memStream);
                  using (XLWorkbook workBook = new XLWorkbook(memStream, XLEventTracking.Disabled))
                  {
                      //Read the first Sheet from Excel file.
                      IXLWorksheet workSheet = workBook.Worksheet(1);
  
                      //Loop through the Worksheet rows.
                      bool firstRow = true;
                      foreach (IXLRow row in workSheet.Rows())
                      {
                          //Use the first row to add columns to DataTable.
                          if (firstRow)
                          {
                              foreach (IXLCell cell in row.Cells())
                              {
                                  dtTable.Columns.Add(cell.Value.ToString());
                              }
                              firstRow = false;
                          }
                          else
                          {
                              //Add rows to DataTable.
                              dtTable.Rows.Add();
                              int i = 0;
  
                              foreach (IXLCell cell in row.Cells(row.FirstCellUsed().Address.ColumnNumber, row.LastCellUsed().Address.ColumnNumber))
                              {
                                  dtTable.Rows[dtTable.Rows.Count - 1][i] = cell.Value.ToString();
                                  i++;
                              }
                          }
                      }
                  }
              }
              return dtTable;
          }
  </code></pre>
  <p>The line causing the delay is:</p>
  <pre><code>using (XLWorkbook workBook = new XLWorkbook(memStream, XLEventTracking.Disabled))
  </code></pre>
  <p>I need help fixing the slow reading of the xlsx file, or a completely different approach if there's a better way! A better way achieving this goal, no cheating/uploading files to the server :)</p>