2012-05-16 360 views
7

Estoy intentando exportar C# DataTable al archivo EXCEL sobre la marcha (sin crear un archivo físico) usando EXPORT INTEROP de Microsoft Office y descargarlo a través de Página web asp.net a través del objeto Response. Puedo generar memorystream usando la biblioteca Pero de alguna manera el archivo no se guarda a través de la secuencia de la memoria. El código de referencia se proporciona a continuación. Se le pedirá que tome referencia para DocumentFormat.OpenXml.dll & WindowsBase.DLL (que puede descargar desde el sitio de Microsoft).Descargar el archivo EXCEL desde la página ASP.NET sin Generar archivo físico en el servidor (On The Fly)

¿Alguna idea de cómo resolver el problema? ? ?

Private void DownloadFile() 
{ 
       DataSet objTable = ReadTableFromViewstate(); 
      if (objTable != null && objTable.Rows.Count > 0) 
      { 

       string strDownloadableFilename = "TestExcelFileName.xls"; 
       MemoryStream fs1 = new MemoryStream(); 
       if (CreateExcelFile.CreateExcelDocument(objTable, fs1)) 
       { 
        Response.Clear(); 
         byte[] data1 = new byte[fs1.Length]; 
         fs1.Read(data1, 0, data1.Length); 
         fs1.Close(); 

        Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; 
        Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", strDownloadableFilename)); 
        Response.BinaryWrite(data1); ; 
        Response.End(); 

       } 
       else 
       { 
        LblErrorMessage.Text = "Error Exporting File."; 
       } 
      } 

     } 

..

public static bool CreateExcelDocument(DataSet ds, System.IO.Stream excelFileStream) 
    { 
     try 
     { 
      using (SpreadsheetDocument document = SpreadsheetDocument.Create(excelFileStream, SpreadsheetDocumentType.Workbook)) 
      { 
       CreateParts(ds, document); 
      } 

      Trace.WriteLine("Successfully created: " + excelFileStream); 
      return true; 
     } 
     catch (Exception ex) 
     { 
      Trace.WriteLine("Failed, exception thrown: " + ex.Message); 
      return false; 
     } 
    } 
.. 




private static void CreateParts(DataSet ds, SpreadsheetDocument document) 
     { 
      WorkbookPart workbookPart = document.AddWorkbookPart(); 
      Workbook workbook = new Workbook(); 
      workbookPart.Workbook = workbook; 

      // If we don't add a "WorkbookStylesPart", OLEDB will refuse to connect to this .xlsx file ! 

       WorkbookStylesPart workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles"); 
      Stylesheet stylesheet = new Stylesheet(); 

      workbookStylesPart.Stylesheet = stylesheet; 

      Sheets sheets = new Sheets(); 

      // Loop through each of the DataTables in our DataSet, and create a new Excel Worksheet for each. 
     uint worksheetNumber = 1; 
     foreach (DataTable dt in ds.Tables) 
     { 
      // For each worksheet you want to create 
      string workSheetID = "rId" + worksheetNumber.ToString(); 
      string worksheetName = dt.TableName; 

      WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>(workSheetID); 
      WriteDataTableToExcelWorksheet(dt, worksheetPart); 

      Sheet sheet = new Sheet() { Name = worksheetName, SheetId = (UInt32Value)worksheetNumber, Id = workSheetID }; 
      sheets.Append(sheet); 

      worksheetNumber++; 
     } 

     workbook.Append(sheets); 
    } 
+0

¿Por qué no hacerlo como delimitado por tabuladores y luego simplemente enviar eso al usuario? Se abrirá en Excel. –

+1

No es realmente una respuesta, pero puedo recomendar [EPPLus] (http://epplus.codeplex.com/releases/view/42439) para crear archivos de Excel sobre la marcha. http://stackoverflow.com/a/10547727/284240 Entonces todo lo que necesita es 'Response.BinaryWrite (pck.GetAsByteArray());' –

+0

@James: Gracias por la sugerencia. Pero no quiero ir por ese camino, de lo contrario podría haber sido generar el archivo .csv. Quiero usar INTEROP porque en el futuro, quiero agregar Imágenes/Gráficos a la hoja de Excel (eso también sobre la marcha). – Sankalp

Respuesta

3

gracias a todos, por fin llegué solución de mi problema. Acabo de cambiar siguiente línea de código:

    byte[] data1 = new byte[fs1.Length]; 
        fs1.Read(data1, 0, data1.Length); 
        fs1.Close(); 

con esta línea

    byte[] data1 = fs1.ToArray(); 

y mi problema se resolvió.

1

Después de terminar de escribir en la secuencia de la memoria, debe volver atrás el puntero a su origen antes de leerlo.

fs1.Seek(0, SeekOrigin.Begin); 
Cuestiones relacionadas