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

4.64 (11 votes)

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.

You might also like...

Date Posted:
Last Updated:
Posted by:
Total Views to date: 24638

3 Comments

- Satyabrata Mohapatra

Another beauty !!!! Thanks for sharing.

- sharey

nice work gentleman.Really helpfull.

- A. Truong

Awesome work! Lifesaver.

Recent Comments

Gfw 03/02/2017 09:48
In response to Free SSL Certificates On IIS With LetsEncrypt
I have used WinSimple for about the last 9 months - works great. One thing that you want to make of...

Ted Driver 02/02/2017 13:24
In response to Free SSL Certificates On IIS With LetsEncrypt
This looks great is you have command line access to your web server - what about those of us on Is...

Carl T. 06/11/2016 05:43
In response to Server.MapPath Equivalent in ASP.NET Core
Very succinct and easy to follow. Worked perfectly the first time for me. Thanks!!...

Manoj Kulkarni 04/11/2016 05:47
In response to Entity Framework Core DbContext Updated
Great post....

Sivu 19/10/2016 08:21
In response to Entity Framework Core TrackGraph For Disconnected Data
Oh that's very very very nice ! Thanks for the write up Mike, much appreciated for the taking the to...

Mark 12/10/2016 16:42
In response to ASP.NET Web Pages vNext or Razor Pages
Although "Web Pages" was removed from the roadmap, has it just been renamed to "Razor Pages"?...

Satyabrata 12/10/2016 09:20
In response to Entity Framework Core TrackGraph For Disconnected Data
Nice article. Please write more articles featuring ASP.Net web pages. Thank you...

Julian 26/09/2016 14:27
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Fantastic, many thanks Mike! Had got half way down this road before finding your article - saved...

Abolfazl Roshanzamir 14/09/2016 05:36
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Nice article. Thanke you so much ....

cyrus 02/09/2016 15:12
In response to ASP.NET Web Pages vNext or Razor Pages
I've got some news. As Damian stated in this link: https://github.com/aspnet/Mvc/issues/5208 “We...