The Best Way To Import Data From Excel To SQL Server via ASP.NET

I've seen a lot of questions about the best way to import data from uploaded Excel files to a SQL Server database in an ASP.NET application. Most solutions involve the use of the JET or ACE OLEDB providers to read data from the saved Excel file, and some even show how to use Office Interop to obtain the data. However, all of these solutions rely on additional components being installed on the server, and they also require the uploaded file to be saved somewhere, even temporarily, which creates an additional maintenance task. The solution that follows makes use of a Nuget package that gets deployed with your application and can work with streams, so the uploaded file doesn't need to be saved. It is, in my submission, THE best way to import data from uploaded Excel files to SQL Server in an ASP.NET application.

The package name is EPPlus, and I have written about it before. It is available by searching for EPPlus in the Nuget Package Manager (VS 2015 onwards) or by typing

install-package epplus

in the Package Manager Console.

The following snippet shows a Web Form featuring just a FileUpload control and a Button:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="SqlBulkInsertWithEPPlus.aspx.cs" Inherits="WebFormsTest.SqlBulkInsertWithEPPlus" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <asp:FileUpload ID="Upload" runat="server" />
    <asp:Button ID="Button1" runat="server" Text="Upload" />
</asp:Content>

The code for processing the uploaded Excel file makes use of an extension method called ToDataTable, which I have defined in a class called ExcelPackageExtenstions:

using OfficeOpenXml;
using System.Data;
using System.Linq;

public static class ExcelPackageExtensions
{
    public static DataTable ToDataTable(this ExcelPackage package)
    {
        ExcelWorksheet workSheet = package.Workbook.Worksheets.First();
        DataTable table = new DataTable();
        foreach (var firstRowCell in workSheet.Cells[1, 1, 1, workSheet.Dimension.End.Column])
        {
            table.Columns.Add(firstRowCell.Text);
        }
        for (var rowNumber = 2; rowNumber <= workSheet.Dimension.End.Row; rowNumber++)
        {
            var row = workSheet.Cells[rowNumber, 1, rowNumber, workSheet.Dimension.End.Column];
            var newRow = table.NewRow();
            foreach (var cell in row)
            {
                newRow[cell.Start.Column - 1] = cell.Text;
            }
            table.Rows.Add(newRow);
        }
        return table;
    }
}

This method is a simple utility method that takes the content of an Excel file and puts it into a DataTable. The code assumes two things: that only the first worksheet is of any interest; and that the first row of the worksheet contains headers. It uses those header values for ColumnName values in the DataTable. If you want to manage more than one worksheet in a workbook or your sheet doesn't contain a header row, you will need to modify the method accordingly.

The code behind that processes the file and performs the bulk insert looks like this:

using OfficeOpenXml;
using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;

namespace WebFormsTest
{
    public partial class SqlBulkInsertWithEPPlus : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack && Upload.HasFile)
            {
                if(Path.GetExtension(Upload.FileName).Equals(".xlsx"))
                {
                    var excel = new ExcelPackage(Upload.FileContent);
                    var dt = excel.ToDataTable();
                    var table = "Contacts";
                    using (var conn = new SqlConnection("Server=.;Database=Test;Integrated Security=SSPI"))
                    {
                        var bulkCopy = new SqlBulkCopy(conn);
                        bulkCopy.DestinationTableName = table;
                        conn.Open();
                        var schema = conn.GetSchema("Columns", new[]{null, null, table, null} );
                        foreach (DataColumn sourceColumn in dt.Columns)
                        {
                            foreach (DataRow row in schema.Rows)
                            {
                                if (string.Equals(sourceColumn.ColumnName, (string)row["COLUMN_NAME"], StringComparison.OrdinalIgnoreCase))
                                {
                                    bulkCopy.ColumnMappings.Add(sourceColumn.ColumnName, (string)row["COLUMN_NAME"]);
                                    break;
                                }
                            }
                        }
                        bulkCopy.WriteToServer(dt);
                    }
                }
            }
        }
    }
}

This code checks to see if a file has been uploaded, and if one has, its extension is checked to ensure that it is an Excel file. Then the data is extracted into a DataTable using the ToDataTable extension method.The destination table is specified and then the schema of that table is obtained from the database. Each of the columns in the Excel worksheet is compared to the columns in the destination table, and if a match is found, an entry is added to the ColumnMappings collection, ensuring that any unmatched columns are ignored. Then the data is inserted into the destination table.

This is among the quickest ways to get data into a SQL Server database, and the code can be adapted easily to MVC, although the bulk of the code in the Page_Load event handler should go into a separate method that's called from the controller rather than in the controller itself. Even if you are using an ORM in your project like the Entity Framework, you are still advised to revert to ADO.NET and SqlBulkCopy for this type of operation purely for performance reasons.

You will notice that at no stage is the Excel file saved to the server, which removes any potential problems arising from permissions, file locking or file system checking. The EPPlus package is deployed to the server with the web application, so nothing needs to be installed on the server to get this to work, which means that you don't have to worry when moving the application from one host to another.

Summary

This article showed my preferred way to bulk import data from Excel into SQL Server from an uploaded file in an ASP.NET application. It uses EPPlus and SqlBulkCopy to accomplish that task quickly and efficiently.