Read an Excel spreadsheet in memory

MuriloKunze picture MuriloKunze · Dec 18, 2012 · Viewed 11k times · Source

How can I read an Excel spreadsheet that was just posted to my server? I searched for something but I only found how to read an Excel spreadsheet with the file name path which is not my case.

I need something like that:

public ActionResult Import(HttpPostedFileBase file)
{
     var excel = new ExcelQueryFactory(file); //using linq to excel
}

Answer

Brett Allred picture Brett Allred · Dec 20, 2012

I was running into your same issue but I didn't want to switch to a paid service so this is what I did.

public class DataImportHelper : IDisposable
{
    private readonly string _fileName;
    private readonly string _tempFilePath;

    public DataImportHelper(HttpPostedFileBase file, string tempFilePath)
    {
        _fileName = file.FileName;
        _tempFilePath = Path.Combine(tempFilePath, _fileName);
        (new FileInfo(_tempFilePath)).Directory.Create();
        file.SaveAs(_tempFilePath);
    }

    public IQueryable<T> All<T>(string sheetName = "")
    {
        if (string.IsNullOrEmpty(sheetName))
        {
            sheetName = (typeof (T)).Name;
        }

        var excelSheet = new ExcelQueryFactory(_tempFilePath);

        return from t in excelSheet.Worksheet<T>(sheetName)
               select t;
    }

    public void Dispose()
    {
        File.Delete(_tempFilePath);
    }

}

Here is a Test

[Fact]
    public void AcceptsAMemoryStream()
    {
        MemoryFile file;

        using (var f = File.OpenRead("SampleData.xlsx"))
        {
            file = new MemoryFile(f, "multipart/form-data", "SampleData.xlsx");

            using (var importer = new DataImportHelper(file, "Temp/"))
            {
                var products = importer.All<Product>();

                Assert.NotEmpty(products);

            }
        }
    }

Here is MemoryFile.cs. This file is only used for testing. It is just an implementation of HttpPostedFileBase so you can test your controllers and my little helper. This was borrowed from another post.

 public class MemoryFile : HttpPostedFileBase
    {
        Stream stream;
        string contentType;
        string fileName;

        public MemoryFile(Stream stream, string contentType, string fileName)
        {
            this.stream = stream;
            this.contentType = contentType;
            this.fileName = fileName;
        }

        public override int ContentLength
        {
            get { return (int)stream.Length; }
        }

        public override string ContentType
        {
            get { return contentType; }
        }

        public override string FileName
        {
            get { return fileName; }
        }

        public override Stream InputStream
        {
            get { return stream; }
        }

        public override void SaveAs(string filename)
        {
            using (var file = File.Open(filename, FileMode.Create))
                stream.CopyTo(file);
        }
    }