Merhaba, iş yoğunluğu nedeni ile uzun zamandır blog'umu ihmal ettim. 2010'un ilk yazısı ile başlayalım. Veri raporlama hepimizin zaman zaman ihtiyaç duyduğu önemli konulardan biri. Projelerde muhasebe veya başka departmanların kullandıkları programlar ile otomasyonunu sağlamak için sistemlerinden bağımsız çalışan programlar ile çalışırken başları genelde derttedir. Geliştirici olarak projenizin bu gibi durumlarda hayat kurtarmasını sağlamak hem müşterinizin hemde sizin omuzlarınızdaki yükü kesinlikle azaltacaktır. Her zaman ihtiyaca göre çözüm üretmeye çalışmak geliştiricinin en önemli handikaplarından ve gerekliliklerinden biri olmuştur.
Bu yazıda aslında uzun süre kafamı kurcalayan, değişik çözümler denediğim ve en sonunda daha kullanışlı bir yol bulduğum verileri Excel dökümanı olarak çıktı vermek üzerinde duracağım. Denediğim çözümler arasında Microsoft.Office.Interop ve
OOXML çözümleri gerçekten çok başımı ağrıttı.
MVP Burak Selim Şenyurt'un
şu adreste anlattığı COM Interop genişletmeleri ile yeni sürüm gerçekten çok daha kolaylık sağlayacakmış, bekleyip göreceğiz.
1) Başta OOXML çözümünü deneyip bu dökümanın server üzerinde oluşturulması (çok fazla kayıtta) neredeyse imkansız hale geliyor. Office 2007 çıktısı vermesi, düşük sürüm office kullanıcıların eklentisiz dosyayı açamaması eksi. Dosya oluşturmada bekleme süreleri uzadıkça uzuyor, server üzerinde çok fazla yük oluşturması da cabası.
2) Daha sonra COM Interop kullanıp yine hüsranla sonuçlanan çabalar... Microsoft.Office.Interop.Excel.dll kullandığınızda server'da Office'in gerekli sürümünün ve
PIA (Primary Interop Assemblies)'in yüklü olması gerekiyor. Sonra server üzerinde konfigürasyonlar. Assembly'lere gerekli yetkilerin verilmesi vs. uzayıp giden bir liste. Sonunda Neredeyse OOXML'den bile kötü bir performans... Sorunlar, sorunlar.
Unutmadan Microsoft'un bu çözümü önermediğini de eklemem gerekiyor.
3) Harici olarak komponent satın almak. En mantıklı çözümlerden biri bu gibi gözüksede bunun için ekstra bir harcama yapmak istemeyebilirsiniz.
Sonunda hayatımı kurtaran şu çözüme yelken açtım ve sizlerle paylaşayım dedim.
Bu metodda OutputStream kullanacağımız için hem server üzerinde fiziksel olarak bir dosya oluşturmayacak (bu isteğe bağlı) hemde istenen dosyaya anında geri dönüş sağlayarak bekleme süresini minimuma indireceğiz. Kolay uygulanabilir olmasının yanı sıra istenen dosyaya anında yanıt vermesi de hayat kurtaran niteliklerinden biri. Sözü fazla uzatmadan örneğimize geçelim.
Gerekli ad uzayımız
Imports System.IO
Oluşturulacak dosyamız için gerekli ayarlamalarımızı yapalım.
Dim DosyaAdi As String = "gonderilecekDosyaAdi.xls" 'Siz istediğiniz adı verin
Response.Buffer = True
Response.ContentType = "application/vnd.ms-excel" 'MIME type'ımızı belirtiyoruz
Response.AddHeader("Content-Disposition", "attachment;filename=" + DosyaAdi) 'Dosyayı download edilmeye zorluyoruz
Response.Clear() 'Temizliğimizi yapıyoruz
Me.EnableViewState = False 'WiewState'e tabii ki ihtiyacımız yok
Dim excelDoc As StreamWriter 'Baş yardımcımızı tanımlıyoruz
excelDoc = New StreamWriter(Response.OutputStream)
İlk olarak String, Integer, Decimal, DateTime, Currency gibi tipler için stiller oluşturuyoruz. Siz kendi datatipleriniz için stiller ekleyebilirsiniz. En çok kullanılanlar bunlar herhalde.
Dim ExcelXMLbasi As New StringBuilder()
ExcelXMLbasi.Append("<xml version>")
ExcelXMLbasi.AppendLine("<Workbook xmlns=""urn:schemas-microsoft-com:office:spreadsheet""")
ExcelXMLbasi.AppendLine(" xmlns:o=""urn:schemas-microsoft-com:office:office""")
ExcelXMLbasi.AppendLine(" xmlns:x=""urn:schemas- microsoft-com:office:excel""")
ExcelXMLbasi.AppendLine(" xmlns:ss=""urn:schemas-microsoft-com:office:spreadsheet"">")
ExcelXMLbasi.AppendLine(" <Styles>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""Default"" ss:Name=""Normal"">")
ExcelXMLbasi.AppendLine(" <Alignment ss:Vertical=""Bottom""/>")
ExcelXMLbasi.AppendLine(" <Borders/>")
ExcelXMLbasi.AppendLine(" <Font/>")
ExcelXMLbasi.AppendLine(" <Interior/>")
ExcelXMLbasi.AppendLine(" <NumberFormat/>")
ExcelXMLbasi.AppendLine(" <Protection/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""KalinBaslik"">")
ExcelXMLbasi.AppendLine(" <Font x:Family=""Swiss"" ss:Bold=""1""/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""StringLiteral"">")
ExcelXMLbasi.AppendLine(" <NumberFormat ss:Format=""@""/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""Decimal"">")
ExcelXMLbasi.AppendLine(" <NumberFormat ss:Format=""0""/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""Integer"">")
ExcelXMLbasi.AppendLine(" <NumberFormat ss:Format=""0""/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""Currency"">")
ExcelXMLbasi.AppendLine(" <NumberFormat ss:Format=""0.00 TL""/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" <Style ss:ID=""DateLiteral"">")
ExcelXMLbasi.AppendLine(" <NumberFormat ss:Format=""dd.mm.yyyy;@""/>")
ExcelXMLbasi.AppendLine(" </Style>")
ExcelXMLbasi.AppendLine(" </Styles>")
excelDoc.Write(ExcelXMLbasi.toString) 'Yazmaya başlıyoruz
Tablomuzun başlık satırlarını oluşturuyoruz. Örnek olsun diye her tipten bir başlık oluşturuyorum. Siz kendi tablo yapınıza göre oluşturabilirsiniz.
excelDoc.Write(" <Worksheet ss:Name=""Rapor"">") 'WorkSheet imizin adı
excelDoc.Write("<Table>")
excelDoc.Write("<Row>")
excelDoc.Write("<Cell ss:StyleID=""KalinBaslik""><Data ss:Type=""String"">Sıra</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""KalinBaslik""><Data ss:Type=""String"">Adı Soyadı</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""KalinBaslik""><Data ss:Type=""String"">Kayıt tarihi</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""KalinBaslik""><Data ss:Type=""String"">Adet</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""KalinBaslik""><Data ss:Type=""String"">Fiyat</Data></Cell>")
excelDoc.Write("</Row>")
ve kayıtlarımızı girelim. Bu satırları veritabanından alacağınız kayıtlara göre basit bir döngü ile çoğaltabilirsiniz.
excelDoc.Write("<Row>")
excelDoc.Write("<Cell ss:StyleID=""Integer""><Data ss:Type=""Number"">1</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""StringLiteral""><Data ss:Type=""String"">Cenk SARI</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""DateLiteral""><Data ss:Type=""String"">13.01.2010</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""Decimal""><Data ss:Type=""Number"">1</Data></Cell>")
excelDoc.Write("<Cell ss:StyleID=""Currency""><Data ss:Type=""Number"">1</Data></Cell>")
excelDoc.Write("</Row>")
Son satırlarımızı yazdırıp dökümanı hazırlıyoruz.
excelDoc.Write("</Table>")
excelDoc.Write("</Worksheet>")
excelDoc.Write("</Workbook>")
excelDoc.Flush()
excelDoc.Close()
Response.End()
İşte bu kadar. Dökümanımız download edilmeye hazır hale geldi. Bu örnekte işin mantığını anlamanız için basit bir şekilde anlattım. Siz veritabanı şemanıza göre otomatize edebilirsiniz tabii ki. Başlık sütunları ve veriler için gerekli tanımlamaları yapıp database şemanızı çıkarsınız ve bunu bir class haline getirip projelerinize ekleyip kolayca kullanabilirsiniz. İşe yarayan gerçek hayat çözümleri ile 2010'da da buralarda olmaya çalışacağım. Bütün sorularınız için iletişim bölümünden bana ulaşabilirsiniz. Soru sormaktan çekinmeyin.
Projenin çalışan halini indirmek için buraya tıklayabilirsiniz.