将即时创建的 CSV 发送回客户端以供下载
我正在将一堆 FOXPRO / FOXWEB 应用程序转换为 ASP.NET。
底层数据库仍然是foxpro(目前)。
我将一个表传递给一些 VB.NET 代码,我希望将其转换为 CSV 文件并发送回客户端以供下载。它有效!有点......有时它会起作用,但有时,它不会询问我是否要下载 CSV 文件,而是将文件喷到浏览器窗口中。
在 asp 方面,我传递响应对象、表和 csv 文件名。
<%
Dim xls_fn As String = "test01.csv"
'OLEDB call to fill up 'tbl' ... this works.
sendTableAsCSVtoClient(response, tbl, xls_fn)
%>
在文件 clsCommon.vb 中,我有以下代码:
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
- 是什么原因造成的?
- 我该如何解决它?
我猜数据源是表并不重要。 请注意,该文件是动态创建的,并且永远不会存在于服务器的文件系统中。
德克萨斯州, 特夫
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 system of the server.
tx,
tff
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不要使用
Inline
的Content-Disposition
标头,而是使用Attachment
- 这将始终提示下载。更改以下行:
To
See this 和 此作为示例。
内联类型意味着浏览器可以自由地内联渲染它(在浏览器内),如果知道如何的话。
并查看这个所以问题,询问为什么
inline
有时会提示下载(与您的问题完全相反......)。Instead of using a
Content-Disposition
header that isInline
, useAttachment
- this will always prompt for a download.Change the following line from:
To
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...).问题是您的
Content-disposition
标头。它应该是“attachment”
而不是“inline”
。您可能还希望将内容类型设置为
“text/csv”
,而不是“application/vnd.ms-excel”
。这样您就可以更加准确,如果他们更喜欢使用其他 CSV 格式,效果应该会更好。但是,对于内部应用程序,也许 vnd.ms-excel 可能会工作得更好?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?我同意 Oded 和 chmullig 的观点,即您应该更改 Content-Disposition,但我也建议使用缓冲区并通过刷新完成响应:
我相信对 .End() 的调用会抛出 ThreadAbortException 来停止执行,这可能会导致问题取决于您如何处理异常。 请参阅此处了解更多信息
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:
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