将即时创建的 CSV 发送回客户端以供下载

发布于 2024-10-21 05:31:15 字数 2234 浏览 1 评论 0原文

我正在将一堆 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
  1. 是什么原因造成的?
  2. 我该如何解决它?

我猜数据源是表并不重要。 请注意,该文件是动态创建的,并且永远不会存在于服务器的文件系统中。

德克萨斯州, 特夫

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
  1. What's causing this?
  2. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

憧憬巴黎街头的黎明 2024-10-28 05:31:15

不要使用 InlineContent-Disposition 标头,而是使用 Attachment - 这将始终提示下载。

更改以下行:

resp.AddHeader("Content-Disposition", "inline; filename=" & lcFileNameONLY & ".csv")

To

resp.AddHeader("Content-Disposition", "attachment; filename=" & lcFileNameONLY & ".csv")

See this作为示例。

内联类型意味着浏览器可以自由地内联渲染它(在浏览器内),如果知道如何的话。

并查看这个所以问题,询问为什么inline有时会提示下载(与您的问题完全相反......)。

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...).

沉溺在你眼里的海 2024-10-28 05:31:15

问题是您的 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?

心的位置 2024-10-28 05:31:15

我同意 Oded 和 chmullig 的观点,即您应该更改 Content-Disposition,但我也建议使用缓冲区并通过刷新完成响应:

 resp.Clear()
 resp.Buffer = true

 'build csv

 resp.Flush()
 resp.Close()

我相信对 .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:

 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文