Sending CSV created on the fly back to client for download
I'm converting a bunch of FOXPRO / FOXWEB apps to ASP.NET.
The underlying DB is still foxpro (for the moment).
I am passing a table to some VB.NET code that I want to have converted to a CSV file and sent back to the client for download. And it works! Sort of ... It works sometimes, but at other times, instead of asking me if I want to download the CSV file, it just spews the file to the browser window.
On the asp side, I am passing the response object, the table and the csv file name.
<%
Dim xls_fn As String = "test01.csv"
'OLEDB call to fill up 'tbl' ... this works.
sendTableAsCSVtoClient(response, tbl, xls_fn)
%>
In the file clsCommon.vb, I have the following code:
Option Explicit On
'Option Strict On
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.Page
Imports System.IO
Imports Microsoft.VisualBasic
Imports System.Diagnostics
Imports System.Data
Imports System.Data.OleDb
Public Class clsCommon
Inherits Page
Public Shared Function enq(ByVal str As String) As String
Dim dq As String
dq = """"
Return dq & str & dq
End Function
' some other functions and subs defined in here ... blah blah blah
' ...
Public Shared Function sendTableAsCSVtoClient(ByVal resp As HttpResponse, ByVal sqlTable As DataTable, ByVal xls_fn As String) As Boolean
Dim r As DataRow
Dim c As DataColumn
Dim sep As String = ","
Dim FileExtension As String
Dim lcFileNameONLY As String
Dim i As Integer
Dim dq As String = """"
FileExtension = UCase(Path.GetExtension(xls_fn))
lcFileNameONLY = UCase(Path.GetFileNameWithoutExtension(xls_fn))
resp.Clear()
resp.ClearContent()
resp.ClearHeaders()
resp.ContentType = "application/vnd.ms-excel"
resp.AddHeader("Content-Disposition", "inline; filename=" & lcFileNameONLY & ".csv")
For Each c In sqlTable.Columns
resp.Write(UCase(c.ColumnName) & sep)
Next
resp.Write(vbCrLf)
For Each r In sqlTable.Rows
For i = 0 To sqlTable.Columns.Count - 1
resp.Write(enq(r(i)) & sep)
Next
resp.Write(vbCrLf)
Next
resp.End()
Return True
End Function
End Class
- What's causing this?
- How do I get around it?
I'm guessing it doesn't really matter that the source of the data is a table. Note that the file is created on the fly and never exists on the file sys开发者_如何学运维tem of the server.
tx, tff
Instead of using a Content-Disposition
header that is Inline
, use Attachment
- this will always prompt for a download.
Change the following line from:
resp.AddHeader("Content-Disposition", "inline; filename=" & lcFileNameONLY & ".csv")
To
resp.AddHeader("Content-Disposition", "attachment; filename=" & lcFileNameONLY & ".csv")
See this and this for examples.
The inline type means that the browser is free to render it inline (within the browser), if in knows how to.
And see this SO question, asking why inline
sometimes prompts for downloads (the exact opposite of your question...).
The issue is your Content-disposition
header. It should be "attachment"
instead of "inline"
.
You may also want to set the content type to be "text/csv"
instead of "application/vnd.ms-excel"
. This way you're more accurate, and if they prefer to use something else for CSV it should work better. However for an in-house app perhaps vnd.ms-excel might work better?
I agree with the Oded and chmullig that you should change the Content-Disposition, but I also recommend using the buffer and finishing the response with a flush:
resp.Clear()
resp.Buffer = true
'build csv
resp.Flush()
resp.Close()
I believe a call to .End() throws a ThreadAbortException to stop execution which can cause issues depending on how you handle your exceptions. See here for more info
精彩评论