【发布时间】:2019-08-27 03:54:57
【问题描述】:
我在 VB NET 2005 Web 项目中有一个页面。在页面加载时,它从登录用户那里获取数据,查找该用户拥有的一组文档,并为每个文档创建一个“下载”按钮。目前,此按钮会打开一个流式传输文档的新窗口,但我们希望按钮本身触发下载。
我对此有一些选择,但它们看起来都有些老套,虽然我还没有找到任何好的解决方案,但这似乎应该是一个已解决的问题。
按钮在表单中(因此带有隐藏字段的回发是“hacky”选项之一)。
【问题讨论】:
我在 VB NET 2005 Web 项目中有一个页面。在页面加载时,它从登录用户那里获取数据,查找该用户拥有的一组文档,并为每个文档创建一个“下载”按钮。目前,此按钮会打开一个流式传输文档的新窗口,但我们希望按钮本身触发下载。
我对此有一些选择,但它们看起来都有些老套,虽然我还没有找到任何好的解决方案,但这似乎应该是一个已解决的问题。
按钮在表单中(因此带有隐藏字段的回发是“hacky”选项之一)。
【问题讨论】:
假设我有一个包含 3 列的 GridView:Filename、Size 和一个 Download 按钮。然后设置按钮的CommandName和CommandArgument。出于安全原因,使用用户的文档 ID 而不是像我一样使用完整路径名可能是一个更好的主意。您可以使用当前用户和文档ID的组合来获取真实文件。
<asp:TemplateField HeaderText="Filename">
<ItemTemplate>
<asp:Label ID="lblFilename" runat="server" Text='<%# Bind("Filename") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Size">
<ItemTemplate>
<asp:Label ID="lblSize" runat="server" Text='<%# Bind("Size") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Download">
<ItemTemplate>
<asp:Button ID="btnDownload" runat="server" Text="Download"
CommandName="Download" CommandArgument='<%# Eval("FullName") %>' />
</ItemTemplate>
</asp:TemplateField>
这是我用来保存下载文件列表的类。此类的列表绑定到 GridView。
Public Class MyFileInfo
Public Property Filename As String
Public Property Fullname As String
Public Property Size As Long
End Class
最后是处理下载按钮的点击。我使用CommandName 和CommandArgument 来传递单击的按钮以及需要向浏览器提供的文件。我使用流并在标题中使用正确的MIME type 写入浏览器。
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
If e.CommandName = "Download" Then
DownloadFile(e.CommandArgument)
End If
End Sub
Sub DownloadFile(filename As String)
Using fs = New FileStream(filename, FileMode.Open)
Response.BufferOutput = False
Response.AddHeader("Content-Length", fs.Length.ToString())
Response.AppendHeader("Content-Disposition", "attachment;filename=" & Path.GetFileName(filename))
Response.ContentType = "application/msword"
fs.Position = 0
fs.CopyTo(Response.OutputStream)
Response.Flush()
Response.End()
End Using
End Sub
完整代码(aspx):
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateField HeaderText="Filename">
<ItemTemplate>
<asp:Label ID="lblFilename" runat="server" Text='<%# Bind("Filename") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Size">
<ItemTemplate>
<asp:Label ID="lblSize" runat="server" Text='<%# Bind("Size") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Download">
<ItemTemplate>
<asp:Button ID="btnDownload" runat="server" Text="Download"
CommandName="Download" CommandArgument='<%# Eval("FullName") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
完整代码(后面的代码):
Imports System.IO
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then BindGridList()
End Sub
Protected Sub GridView1_RowCommand(sender As Object, e As GridViewCommandEventArgs) Handles GridView1.RowCommand
If e.CommandName = "Download" Then
DownloadFile(e.CommandArgument)
End If
End Sub
Sub BindGridList()
GridView1.DataSource = GetFiles()
GridView1.DataBind()
End Sub
Function GetFiles() As List(Of MyFileInfo)
Dim listFileInfos = New List(Of MyFileInfo)
Dim dirInfo = New DirectoryInfo(Server.MapPath("~/Data"))
Dim fileInfos = dirInfo.GetFiles("*.doc")
For Each fileInfo In fileInfos
listFileInfos.Add(New MyFileInfo With {.Filename = fileInfo.Name, .Size = fileInfo.Length, .Fullname = fileInfo.FullName})
Next
Return listFileInfos
End Function
Sub DownloadFile(filename As String)
Using fs = New FileStream(filename, FileMode.Open)
Response.BufferOutput = False
Response.AddHeader("Content-Length", fs.Length.ToString())
Response.AppendHeader("Content-Disposition", "attachment;filename=" & Path.GetFileName(filename))
Response.ContentType = "application/msword"
fs.Position = 0
fs.CopyTo(Response.OutputStream)
Response.Flush()
Response.End()
End Using
End Sub
End Class
Public Class MyFileInfo
Public Property Filename As String
Public Property Fullname As String
Public Property Size As Long
End Class
【讨论】: