how can i create a true, binary excel file using pure asp - asp-classic

is it possible to create a binary excel file in asp classic?
the common method is using this
Response.ContentType = "application/octet-stream"
Response.AddHeader "Content-Disposition", "attachment; filename=test.txt"
which is not a "true" excel file

In .net you could use the Microsoft.Office.Interop.Excel namespace - very easy to use, if you have access to .net i'd certainly go for that.
You say "in pure asp" - if this means without com objects etc - i dont think it's possible.
If however you wish to persevere with classic asp with the option of using a com object you can create full binary spreadsheets using the Interop com object - to do this you will need Excel installed on the webserver.
For example, to open a blank excel file on disk (i.e. a template), change a value and save the finished file:
'#### Ready Excel
Set ExcelApp = CreateObject("Excel.Application")
ExcelApp.Application.Visible = True
'#### Open a blank Excel File
Set ExcelBook = ExcelApp.workbooks.Open("d:\wwwroot2\blankTemplate.xls")
'#### Select a sheet and change the value of a cell
ExcelBook.Worksheets("SheetName").Cells(1, 1).Value = "Lorem Ipsum"
'#### Switch between sheets
ExcelBook.Worksheets("AnotherSheetName").Select
'#### Save the finished file with a different name (to leave the template ready for easy re-use)
ExcelBook.SaveAs "d:\wwwroot2\FinishedFile.xls"
'#### Tidy up
ExcelBook.Close
ExcelApp.Application.Quit
Set ExcelApp = Nothing
Set ExcelBook = Nothing
Good thing about this method is the interop com object mimics VBA methods etc very closely, so if your ever unsure how to do something, record a macro in excel, view the raw vba, the code it produces, specifically the methods and parameters would be very similar in most cases to the code you would use for the com object.

Related

Generating Excel Documents with ASP.NET Website

I have an ASP.NET application that helps the user create a Gridview with certain data in it. Once this table is generated I want the user to push a button and be able to save the table as an Excel document.There are two different methods I know of:
Using HtmlTextWriter with ContentType "application/vnd.ms-excel" to send the file as an HttpResponse. I use GridView1.RenderControl(htmlTextWriter) to render the gridview. This almost works, but the excel file always shows a warning when the file opens because the content doesn't match the extension. I have tried various content types to no avail. This makes sense I guess, because I'm using an HtmlWriter. It also doesn't seem a good practice.
The second thing I've tried is generating the Excel file using Office Automation. But for the file to be generated, I need to save it to disk and then read it again. From what I have read, this is the only way, because the Excel object only becomes a real Excel file once you save it. I found that the .saveas method from the Excel class would throw an exception because of write permissions, even if I tried to save in the App_Data folder. So I did some research and found that apparently Office Automation is discouraged for web services: https://support.microsoft.com/en-us/kb/257757
Microsoft does not currently recommend, and does not support,
Automation of Microsoft Office applications from any unattended,
non-interactive client application or component (including ASP,
ASP.NET, DCOM, and NT Services), because Office may exhibit unstable
behavior and/or deadlock when Office is run in this environment.
There surely must be a save way to have a website generate an Excel file and offer it to the user!? I can't imagine that this problem is unsolved or so rare that nobody cares about it, but yet I can't find any good solution to this.
the easiest (and best) way to create an excel file is by using epplus
Epplus sample for webapplication
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Demo");
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(tbl, true);
//Format the header for column 1-3
using (ExcelRange rng = ws.Cells["A1:C1"])
{
rng.Style.Font.Bold = true;
rng.Style.Fill.PatternType = ExcelFillStyle.Solid; //Set Pattern for the background to Solid
rng.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(79, 129, 189)); //Set color to dark blue
rng.Style.Font.Color.SetColor(Color.White);
}
//Example how to Format Column 1 as numeric
using (ExcelRange col = ws.Cells[2, 1, 2 + tbl.Rows.Count, 1])
{
col.Style.Numberformat.Format = "#,##0.00";
col.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
}
//Write it back to the client
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment; filename=ExcelDemo.xlsx");
Response.BinaryWrite(pck.GetAsByteArray());
}

Trouble Understanding Code to Export Excel Spreadsheet from HTML

I have been asked to make changes to an ASP.NET WebForms application written in VB (I normally use C#).
One task is to try and fix an Excel download. The client reported that he gets an error about the spreadsheet being corrupt when he attempts to open it in Excel.
The code that exports the Excel download appears in the Load event of a dedicated ASPX page. And looks something like this:
Dim mytable As New HtmlTable
mytable = [Populate HTML Table Here]
mytable = returnclass.displaytable
mytable.Border = 1
mytable.BorderColor = "#CCCCCC"
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.Buffer = True
Response.Write("<html xmlns:x=""urn:schemas-microsoft-com:office:excel"">")
Response.Write("<head>")
Response.Write("<!--[if gte mso 9]><xml>")
Response.Write("<x:ExcelWorkbook>")
Response.Write("<x:ExcelWorksheets>")
Response.Write("<x:ExcelWorksheet>")
Response.Write("<x:Name>" & worksheetTitle & "</x:Name>")
Response.Write("<x:WorksheetOptions>")
Response.Write("<x:Print>")
Response.Write("<x:ValidPrinterInfo/>")
Response.Write("</x:Print>")
Response.Write("</x:WorksheetOptions>")
Response.Write("</x:ExcelWorksheet>")
Response.Write("</x:ExcelWorksheets>")
Response.Write("</x:ExcelWorkbook>")
Response.Write("</xml>")
Response.Write("<![endif]--> ")
Response.Write("</head>")
Response.Write("<body>")
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=hhexport.xls ")
HttpContext.Current.Response.Charset = ""
'ouput table to html so excel can interperet.
Me.EnableViewState = False
Dim stringWriter As New System.IO.StringWriter()
Dim htmlWriter As New System.Web.UI.HtmlTextWriter(stringWriter)
mytable.RenderControl(htmlWriter)
HttpContext.Current.Response.Write(stringWriter.ToString)
I really don't understand what this is trying to do.
Questions:
The code produces a regular ASP.NET HtmlTable and assigns it to mytable. On what planet can Excel open HTML?
I'm really kind of loss by the XML in general here, and by the <!--[if gte mso 9] comment. Can anyone help me understand what is going on here.
The result appears valid but I'm just not familiar with what the intent is here. Any tips appreciated.
EDIT
On further testing, the problem seems related to the extension given to the file (xls). The current version of Excel will go ahead and load the file if I indicate that. But all formatting is lost. Any suggestions on what type of file this would be?
EDIT
And it looks like the original author got the idea from here, although that page doesn't really describe what is happening.
UPDATE
Thanks for everyone's response. I will credit those replies according to how they addressed the questions above. However, for my purposes the code appears to have worked all along. It just appears that newer versions of Excel now warn the user that an XLS file that contains HTML is a file of a different type than suggested by the file extension. And it appears there is nothing that can be done about this except for exporting using CSV, OpenXML or some other approach. I found more details in this blog.
The code basically wraps an HTML table in some special XML tags that relate to Excel (defining a Workbook and Worksheets, etc). This is supposed to allow the output to be opened by either Excel or a browser.
To answer your questions:
The code produces a regular ASP.NET HtmlTable and assigns it to mytable. On what planet can Excel open HTML? Actually, that's a feature of Excel. You can use a special combination of XML and HTML tags to create files that are open-able on the web and in Excel. See this MSDN article: How to format an Excel workbook while streaming MIME content
I'm really kind of loss by the XML in general here, and by the <!--[if gte mso 9] comment. Can anyone help me understand what is going on here. That specific comment is checking for the availability of MS Excel (whether it's being opened by Excel or a browser), I believe. The XML is specific tags that have special meaning in MS Excel. There's a reference you can download here: Microsoft® Office HTML and XML Reference
I found this article on C# Corner to be pretty helpful in understanding this type of code: Creating a Dynamic Excel Using HTML.
As far as I know Excel has been able to read HTML for quite a while. This particular approach is pretty common, but it's definitely not best practice.
The important part of this logic is here:
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=hhexport.xls ")
HttpContext.Current.Response.Charset = ""
'ouput table to html so excel can interperet.
Me.EnableViewState = False
Dim stringWriter As New System.IO.StringWriter()
Dim htmlWriter As New System.Web.UI.HtmlTextWriter(stringWriter)
mytable.RenderControl(htmlWriter)
HttpContext.Current.Response.Write(stringWriter.ToString)
The Response.Write logic is just being used to control the workbook and worksheet that gets outputted. If that logic was not there, the file would open with three worksheets similar to a new Excel workbook.

FileUpload control in asp/VB.net cannot access the file because it is being used by another process

Error message:
The process cannot access the file 'C:\SampleProjectName\mytestcsv.csv' because it is being used by another process.
I am trying to read numerous files (CSV, XML, HTML) in asp/VB.net using the fileupload (file upload) control.
I'm saving the file using Server.MapPath so I can process the file in another procedure. It's very odd, but sometimes I can browse and upload the same file over and over with no issues, but sometimes it immediately fails.
I've found that I can ultimately kill the WebDev.WebServer40.exe it releases whatever lock is present. This is annoying, but fine for my debugging... but unacceptable for endusers.
My fileupload code:
If fuImport.HasFile Then
If (System.IO.File.Exists(Server.MapPath("myhtml.html"))) Then
System.IO.File.Delete(Server.MapPath("myhtml.html"))
End If
Dim dtFromHTML As New Data.DataTable
Dim dtFromSQL As New Data.DataTable
Try
fuImport.SaveAs(Server.MapPath("mytestcsv.csv"))
'Process data here
ProcessCSVData(Server.MapPath("mytestcsv.csv"))
Catch ex As Exception
Response.Write("error: " & ex.Message)
Finally
fuImport.PostedFile.InputStream.Flush()
fuImport.PostedFile.InputStream.Close()
fuImport.FileContent.Dispose()
End Try
'Other things happen here
Else
Response.Write("no file...")
End If
Any ideas would be appreciated.
Use FileShare.Read to read a file even if it is opened exclusively by an another process.
You may not be releasing the file in your code for access. You should use the keyword "using".
Read this post:
The process cannot access the file because it is being used by another process - using static class
and this:
http://msdn.microsoft.com/en-us/library/htd05whh.aspx
I am not a VB.NET coder but try something along the lines of:
Using {fuImport.SaveAs(Server.MapPath("mytestcsv.csv")) }
ProcessCSVData(Server.MapPath("mytestcsv.csv"))
End Using
The next procedure that uses file...
Try closing input stream before accessing the file:
UPDATED To use temp filename
Dim sTempName = Path.GetRandomFileName
fuImport.SaveAs(Server.MapPath(sTempName))
'close before accessing saved file
fuImport.PostedFile.InputStream.Close()
'Process data here
ProcessCSVData(Server.MapPath(sTempName)

asp.net form output: streamwriter to write to file versus database connection

I have to make an ASP.net form and only need to gather 3 fields: name, bday and email.
Do you think it's best to write the info to a csv or xml file, or do you think it's worth it to write to a SQL DB or something and then export from there to a file?
I'm of the opinion that just writing to a flat file is best because it's just going to need to be exported into a csv/xml file anyway so it can be appended to an excel file.
I'd use something like streamwriter or filestream in my C# submitbutton function:
StreamWriter sw = new StreamWriter(filename, true);
sw.WriteLine(string.Concat
( textBox1.Text
, textBox2.Text
, textBox3.Text
, textBox4.Text
, textBox5.Text
, textBox6.Text
, textBox7.Text ));
sw.Close();
Am I overlooking shortcomings of using csv and StreamWriter? Like do any weird things happen when the file gets to a certain size?
Also, how is Streamwriter compared to Filestream, or should I be looking at a different method entirely?
Even for small applications you will never regret using a database. Especially if they ever change / grow. Text files are a lot harder to make a change if you want to store other data.
File access for web applications be challenging at best. If you do use a Database I would ultimately look in to XML/XSD and using Data Sets.

How can I export my ASP.NET page to Excel?

How can I export the data in my webapp to an Excel sheet from ASP.NET (VB.NET,SQL 2005)?
change the contenttype of your ASP.Net page
Response.ContentType = "application/ms-excel"
One of my most popular blogs is how to generate an Excel document from .NET code, using the Excel XML markup (this is not OpenXML, it's standard Excel XML) - http://www.aaron-powell.com/linq-to-xml-to-excel
I also link off to an easier way to do it with VB 9.
Although this is .NET 3.5 code it could easily be done in .NET 2.0 using XmlDocument and creating the nodes that way.
Then it's just a matter to set the right response headers and streaming back in the response.
SpreadsheetGear for .NET will do it. You can find a bunch of live ASP.NET samples with C# & VB.NET source on this page.
Disclaimer: I own SpreadsheetGear LLC
If you can display your data in a GridView control, it inherently supports "right-click-->Export to Excel" without having to write any code whatsoever.
SQL Server Reporting services would be the best way to export data from an application into Excel.
If you dont have access to / dont wan't to use reporting services depending on the data you want to extract / format possibly using a CSV structure instead of Excel may be easiest.
Use the Microsoft.Office.Interop.Excel dlls to create excel files with your data and then provide links to download the files using Hunter Daley's download method...
As a general solution, you may want to consider writing handler (ashx) for exporting -- and pass either the query parameters to recreate the query to generate the data or an identifier to get the data from the cache (if cached). Depending on whether CSV is sufficient for your Excel export you could just format the data and send it back, setting the ContentType as #Hunter suggests or use the primary interop assemblies (which would require Excel on the server) to construct a real Excel spreadsheet and serialize it to the response stream.
I prefer to use a OLEDB connection string.
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Excel.xls;Extended Properties="Excel 8.0;HDR=Yes;IMEX=1";
Not sure about exporting a page but if you just want to export a dataset or datatable
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
HttpContext.Current.Response.ContentType = "application/ms-excel"
Dim sw As StringWriter = New StringWriter
Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
Dim table As Table = New Table
table.RenderControl(htw)
' render the htmlwriter into the response
HttpContext.Current.Response.Write(sw.ToString)
HttpContext.Current.Response.End()
I use almost the same exact code as CodeKiwi. I would use that if you have a DataTable and want to stream it to the client browser.
If you want a file, you could also do a simple loop through each row/column, create a CSV file and I guess provide a link to the client - you can use a file extension of CSV or XLS. Or if you stream the resulting file to the client it will prompt them if they want to open or save it to disk.
The interops are (well were last time I tried them) great for small datasets, but didn't scale well - horrifically slow for larger datasets.

Resources