Search code examples
c#asp.netexcelinteropout-of-memory

Why am I getting an Out of Memory Error doing ASP .NET Excel Interop?


This was working..and I moved the disposal code to the finally block, and now it fails every time.

I have a test spreadsheet with 4 records, 6 columns long. Here is the code I'm using to bring it in. This is ASP .Net 3.5 on IIS 5 (my pc) and on IIS 6 (web server).

It blows up on the line right before the catch: "values = (object[,])range.Value2;" with the following error:

11/2/2009 8:47:43 AM :: Not enough storage is available to complete this operation. (Exception from HRESULT: 0x8007000E (E_OUTOFMEMORY))

Any ideas? Suggestions? I got most of this code off codeproject, so I have no idea if this is the correct way to work with Excel. Thanks for any help you can provide.

Here is my code:

Excel.ApplicationClass app = null;
Excel.Workbook book = null;
Excel.Worksheet sheet = null;
Excel.Range range = null;

object[,] values = null;

try
{
    // Configure Excel
    app = new Excel.ApplicationClass();
    app.Visible = false;
    app.ScreenUpdating = false;
    app.DisplayAlerts = false;

    // Open a new instance of excel with the uploaded file
    book = app.Workbooks.Open(path);

    // Get first worksheet in book
    sheet = (Excel.Worksheet)book.Worksheets[1];

    // Start with first cell on second row
    range = sheet.get_Range("A2", Missing.Value);

    // Get all cells to the right
    range = range.get_End(Excel.XlDirection.xlToRight);

    // Get all cells downwards
    range = range.get_End(Excel.XlDirection.xlDown);

    // Get address of bottom rightmost cell
    string downAddress = range.get_Address(false, false, Excel.XlReferenceStyle.xlA1, Type.Missing, Type.Missing);

    // Get complete range of data
    range = sheet.get_Range("A2", downAddress);

    // get 2d array of all data
    values = (object[,])range.Value2;
}
catch (Exception e)
{
    LoggingService.log(e.Message);
}
finally
{
    // Clean up
    range = null;
    sheet = null;

    if (book != null)
        book.Close(false, Missing.Value, Missing.Value);

    book = null;

    if (app != null)
        app.Quit();

    app = null;
}

return values;

Solution

  • I'm not sure if this is your issue or not, but it very well may be. You are not cleaning up your excel objects properly. They are unmanaged code and can be tricky to clean up. Finally should look something like this: And as the comments have noted working with excel from asp.net is not a good idea. This cleanup code is from a winform app:

     GC.Collect();
     GC.WaitForPendingFinalizers();
    
    
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range);
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
    
     WB.Close(false, Type.Missing, Type.Missing);
    
     Excel.Quit();
     System.Runtime.InteropServices.Marshal.FinalReleaseComObject(Excel);
    

    EDIT

    An alternative would be to use ado.net to open the workbook.

                DataTable dt = new DataTable();
    
                string connectionString;
                System.Data.OleDb.OleDbConnection excelConnection;
                System.Data.OleDb.OleDbDataAdapter da;
                DataTable dbSchema;
                string firstSheetName;
                string strSQL;
    
                connectionString = @"provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filename + @";Extended Properties=""Excel 12.0;HDR=YES;IMEX=1""";
                excelConnection = new System.Data.OleDb.OleDbConnection(connectionString);
                excelConnection.Open();
                dbSchema = excelConnection.GetOleDbSchemaTable(System.Data.OleDb.OleDbSchemaGuid.Tables, null);
                firstSheetName = dbSchema.Rows[0]["TABLE_NAME"].ToString();
                strSQL = "SELECT * FROM [" + firstSheetName + "]";
                da = new OleDbDataAdapter(strSQL, excelConnection);
                da.Fill(dt);
    
                da.Dispose();
                excelConnection.Close();
                excelConnection.Dispose();