Using the ExcelPackage class on a web page

by Ken Tucker 17. December 2007 14:12

Dr. John Tunicliffe wrote a nice class for creating excel 2007 spreadsheets and was nice enough to post his work on the codeplex web site. 

 

http://www.codeplex.com/ExcelPackage

 

I was looking to use the ExcelPackage to create a spreadsheet on a website with out having to save the spreadsheet on the server first.  Well to do this we are going to have to modify the ExcelPackage class to have an constructor which accepts a stream.  After you download the ExcelPackage class from codeplex add the following code to ExcelPackage.cs contructors region.

 

        #region ExcelPackage Constructors
        /// <summary>
        /// Creates a new instance of the ExcelPackage class based on a stream.
        /// </summary>
        /// <param name="stream">Creates a new ExcelPackage from a stream</param>
        public ExcelPackage(Stream stream)
        {
            _package = Package.Open(stream, FileMode.OpenOrCreate);
            // save a temporary part to create the default application/xml content type
            Uri uriDefaultContentType = new Uri("/default.xml", UriKind.Relative);
            PackagePart partTemp = _package.CreatePart(uriDefaultContentType, "application/xml");

            XmlDocument workbook = Workbook.WorkbookXml; // this will create the workbook xml in the package

            // create the relationship to the main part
            _package.CreateRelationship(Workbook.WorkbookUri, TargetMode.Internal, schemaRelationships + "/officeDocument");

            // remove the temporary part that created the default xml content type
            _package.DeletePart(uriDefaultContentType);
        }

Once you compile the class we can add it as a reference to a website which targets the .Net framework 3.0 or 3.5.

So to write a spreadsheet to webpage we need to first create a MemoryStream to save the spreadsheet to.  I use a MemoryStream because the Response.OutputStream will give you an error about the FileMode or FileAccess type not being valid for this stream. Once we write the spreadsheet to the MemoryStream  set the Response's ContextType. Then we can write the MemoryStream to the webpage.

Imports OfficeOpenXml
Imports System.IO

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim ms As New MemoryStream

        Using pack As New ExcelPackage(ms)
            Dim ws As ExcelWorksheet = pack.Workbook.Worksheets.Add("Sheet1")
            ws.Cell(1, 1).Value = "Product Name"
            ws.Column(1).Width = 30
            ws.Cell(1, 2).Value = "Price"
            ws.Column(2).Width = 10

            For r As Integer = 0 To 9
                ws.Cell(r + 2, 1).Value = "Product " & r.ToString
                ws.Cell(r + 2, 2).Value = r.ToString()
            Next

            pack.Workbook.Properties.Author = "Ken Tucker"
            pack.Workbook.Properties.Title = "Create spreadsheet from web"
            pack.Save()
        End Using
        Response.ContentType = "application/vnd.openxmlformats"
        Response.AddHeader("Content-Disposition", "attachment; filename= Data.xlsx;")
        Response.OutputStream.Write(ms.GetBuffer, 0, CInt(ms.Length))
        Response.Flush()
        Response.Close()
        Response.End()

    End Sub

End Class

Hope this helps


kick it on DotNetKicks.com

Using Linq to XML to create an excel spreadsheet

by Ken Tucker 25. November 2007 11:30

For this example we are going to create a Excel 2007 spreadsheet using the Microsoft OpenXml Sdk and Linq to XML.

To start with lets create a new Windows forms app which targets the .Net Framework 3.5.  Add a Linq to Sql design surface to your project and name it Northwind and drag the Northwind Products table on to the surface.  On the windows form I added a DataGridview to display the data we are going to export to excel.  We also need a button named btnExport on the form.

To create a excel spreadsheet we need to use the openxml sdk to create a spreadsheet document, workbook, worksheet, and a string table. 

       Using doc = SpreadsheetDocument.Create("Export.xlsx", SpreadsheetDocumentType.Workbook)
            Dim workbook = doc.AddWorkbookPart
            Dim stringTable = workbook.AddNewPart(Of SharedStringTablePart)()
            Dim worksheet = workbook.AddNewPart(Of WorksheetPart)()

The worksheet, workbook, and string table are xml documents contained inside a package.  Before we get to far we need to import a few xml namespaces

 

Imports <xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
Imports <xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">

 

Now that we imported the name space we can use some of the new xml features in VB 2008 to create the xml documents.  Since we are not using a string table we just need a blank xml file

 

Dim xmlStringTable = <sst></sst>

The workbook xml needs to relate the spreadsheet with its id

 

           Dim xmlWorkbook = <workbook>
                                  <sheets>
                                      <sheet name="Exported" sheetId="1" r:id=<%= sheetId %>></sheet>
                                  </sheets>
                              </workbook>


Note the <%= sheetId %> allows you to get data from a variable

 

Finally we need to create the worksheet.  In the worksheet we set the column widths and use a linq query to populate the data.

            Dim xmlWorkSheet = <worksheet>
                                   <sheetFormatPr defaultRowHeight="15"/>
                                   <cols>
                                       <col min="1" max="1" width="30" bestFit="1" customWidth="1"/>
                                       <col min="2" max="2" width="10" bestFit="1" customWidth="1"/>
                                   </cols>
                                   <sheetData>
                                       <row>
                                           <c t="inlineStr">
                                               <is>
                                                   <t>Product Name</t>
                                               </is>
                                           </c>
                                           <c t="inlineStr">
                                               <is>
                                                   <t>Unit Price</t>
                                               </is>
                                           </c>
                                       </row>
                                       <%= From p In db.Products Select _
                                           <row>
                                               <c t="inlineStr">
                                                   <is>
                                                       <t><%= p.ProductName %></t>
                                                   </is>
                                               </c>
                                               <c>
                                                   <v><%= p.UnitPrice %></v>
                                               </c>
                                           </row> %>
                                   </sheetData>
                               </worksheet>

 

Here is the function for writing the xml to the file

   Sub WriteXmlToPart(ByVal part As OpenXmlPart, ByVal x As XElement)
        Dim fs As New IO.StreamWriter(part.GetStream, New System.Text.UTF8Encoding)

        Dim xmlWriter As New Xml.XmlTextWriter(part.GetStream, New UTF8Encoding)
        xmlWriter.Formatting = Xml.Formatting.Indented
        Dim enc As New UTF8Encoding

        xmlWriter.WriteStartDocument()
        x.WriteTo(xmlWriter)
        xmlWriter.WriteEndDocument()
        xmlWriter.Flush()
        xmlWriter.Close()
    End Sub

 

Here is the complete listing for program

 

Imports Microsoft.Office.DocumentFormat.OpenXml.Packaging
Imports System.Text
Imports <xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
Imports <xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">

Public Class Form1
    Dim bs As New BindingSource
    Dim db As New NorthwindDataContext

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        bs.DataSource = From p In db.Products _
                        Select p.ProductName, p.UnitPrice

        DataGridView1.DataSource = bs
    End Sub

    Private Sub btnExport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExport.Click
        Using doc = SpreadsheetDocument.Create("Export.xlsx", SpreadsheetDocumentType.Workbook)
            Dim workbook = doc.AddWorkbookPart
            Dim stringTable = workbook.AddNewPart(Of SharedStringTablePart)()
            Dim worksheet = workbook.AddNewPart(Of WorksheetPart)()
            Dim sheetId = workbook.GetIdOfPart(worksheet)

            'create the string table
            Dim xmlStringTable = <sst></sst>
            WriteXmlToPart(stringTable, xmlStringTable)

            'create the workbook
            Dim xmlWorkbook = <workbook>
                                  <sheets>
                                      <sheet name="Exported" sheetId="1" r:id=<%= sheetId %>></sheet>
                                  </sheets>
                              </workbook>
            WriteXmlToPart(workbook, xmlWorkbook)

            'create the spreadsheet
            Dim xmlWorkSheet = <worksheet>
                                   <sheetFormatPr defaultRowHeight="15"/>
                                   <cols>
                                       <col min="1" max="1" width="30" bestFit="1" customWidth="1"/>
                                       <col min="2" max="2" width="10" bestFit="1" customWidth="1"/>
                                   </cols>
                                   <sheetData>
                                       <row>
                                           <c t="inlineStr">
                                               <is>
                                                   <t>Product Name</t>
                                               </is>
                                           </c>
                                           <c t="inlineStr">
                                               <is>
                                                   <t>Unit Price</t>
                                               </is>
                                           </c>
                                       </row>
                                       <%= From p In db.Products Select _
                                           <row>
                                               <c t="inlineStr">
                                                   <is>
                                                       <t><%= p.ProductName %></t>
                                                   </is>
                                               </c>
                                               <c>
                                                   <v><%= p.UnitPrice %></v>
                                               </c>
                                           </row> %>
                                   </sheetData>
                               </worksheet>

            WriteXmlToPart(worksheet, xmlWorkSheet)

        End Using
    End Sub

    Sub WriteXmlToPart(ByVal part As OpenXmlPart, ByVal x As XElement)
        Dim fs As New IO.StreamWriter(part.GetStream, New System.Text.UTF8Encoding)

        Dim xmlWriter As New Xml.XmlTextWriter(part.GetStream, New UTF8Encoding)
        xmlWriter.Formatting = Xml.Formatting.Indented
        Dim enc As New UTF8Encoding

        xmlWriter.WriteStartDocument()
        x.WriteTo(xmlWriter)
        xmlWriter.WriteEndDocument()
        xmlWriter.Flush()
        xmlWriter.Close()
    End Sub

End Class


kick it on DotNetKicks.com