ASP.NET 2.0 FileUpload 服务器控件






4.75/5 (22投票s)
2007年8月15日
10分钟阅读

153691
Wrox 作者 Bill Evjen 讲解 ASP.NET 2.0 FileUpload 服务器控件
ASP.NET 2.0 FileUpload 服务器控件
作者:Bill Evjen
在 ASP.NET 1.0/1.1 中,您可以使用 HTML FileUpload 服务器控件上传文件。该控件会在您的网页上放置一个 <input type="file">
元素,使用户能够将文件上传到服务器。但是,要使用该文件,您必须对页面进行一些修改。例如,需要在页面的 <form>
元素中添加 enctype="multipart/form-data"
。
ASP.NET 2.0 引入了一个新的 FileUpload 服务器控件,使文件上传到服务器的过程更加简单。当赋予页面文件上传能力时,只需包含新的 <asp:FileUpload>
控件,ASP.NET 就会处理其余的事情,包括向页面的 <form>
元素添加 enctype
属性。
使用 FileUpload 控件上传文件
文件上传到服务器后,您还可以获取上传文件的属性,并将它们显示给最终用户,或者在您的页面代码后置中使用这些值。列表 1 展示了一个使用新的 FileUpload 控件的示例。该页面包含一个 FileUpload 控件,以及一个 Button 和一个 Label 控件。
列表 1:使用新的 FileUpload 控件上传文件
VB
<%@ Page Language="VB"%>
<script runat="server">
Protected Sub
Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
If FileUpload1.HasFile Then
Try
FileUpload1.SaveAs("C:\Uploads\" & _
FileUpload1.FileName)
Label1.Text = "File name: " & _
FileUpload1.PostedFile.FileName & "<br>" & _
"File Size: " & _
FileUpload1.PostedFile.ContentLength & _
" kb<br>" & _
"Content type: " & _
FileUpload1.PostedFile.ContentType
Catch ex As Exception
Label1.Text = "ERROR: " & ex.Message.ToString()
End Try
Else
Label1.Text = "You have not specified a file."
End If
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>FileUpload Server Control</title>
</head>
<body>
<form id="form1" runat="server">
<asp:FileUpload ID="FileUpload1" runat="server" />
<p>
<asp:Button ID="Button1" runat="server" Text="Upload"
OnClick="Button1_Click" /></p>
<p>
<asp:Label ID="Label1" runat="server"></asp:Label></p>
</form>
</body>
</html>
C#
<%@ Page Language="C#"%>
<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
try {
FileUpload1.SaveAs("C:\\Uploads\\" +
FileUpload1.FileName);
Label1.Text = "File name: " +
FileUpload1.PostedFile.FileName + "<br>" +
FileUpload1.PostedFile.ContentLength + " kb<br>" +
"Content type: " +
FileUpload1.PostedFile.ContentType;
}
catch (Exception ex) {
Label1.Text = "ERROR: " + ex.Message.ToString();
}
else
{
Label1.Text = "You have not specified a file.";
}
}
</script>
从这个示例中,您可以看到整个过程相当简单。页面上的单个按钮会启动上传过程。FileUpload 控件本身并不会启动上传过程。您必须通过其他事件(如 Button_Click
)来启动它。编译并运行此页面时,您可能会注意到页面生成的源代码中有几处地方。此处展示了一个生成的源代码示例
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1"><title>
FileUpload Server Control
</title></head>
<body>
<form name="form1" method="post" action="FileUpload.aspx" id="form1"
enctype="multipart/form-data">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value=
"/wEPDwUKMTI3ODM5MzQ0Mg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm
0tZGF0YWRkrSpgAFaEKed5+5/8+zKglFfVLCE=" />
</div>
<input type="file" name="FileUpload1" id="FileUpload1" />
<p>
<input type="submit" name="Button1" value="Upload" id="Button1" />
</p>
<p>
<span id="Label1"></span></p>
<div>
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION"
value="/wEWAgL1wLWICAKM54rGBqfR8MhZIDWVowox+TUvybG5Xj0y" />
</div></form>
</body>
</html>
首先要注意的是,因为 FileUpload 控件在页面上,ASP.NET 2.0 会代表您修改页面的 <form>
元素,添加了适当的 enctype
属性。还要注意,FileUpload 控件已转换为 HTML <input type="file">
元素。
文件上传后,第一个检查(在文件的 Button1_Click
事件处理程序中完成)会检查是否确实有一个文件引用被放置在 <input type="file">
元素中。如果指定了文件,则会尝试使用 FileUpload 控件的 SaveAs
方法将引用的文件上传到服务器。该方法接受一个 String
参数,该参数应包含您要保存文件的位置。在列表 1 中使用的 String
参数中,您可以看到文件被保存在名为 Uploads
的文件夹中,该文件夹位于 C:\ 驱动器上。
PostedFile.FileName
属性用于将保存的文件命名为与复制的原始文件相同的名称。如果您想为文件命名其他名称,只需使用以下方式调用 SaveAs
方法:
FileUpload1.SaveAs("C:\Uploads\UploadedFile.txt")
您还可以为文件命名,以指定其上传时间:
FileUpload1.SaveAs("C:\Uploads\" &
System.DateTime.Now.ToFileTimeUtc() & ".txt")
文件上传成功完成后,页面上的 Label 控件会填充上传文件的元数据。在此示例中,文件的名称、大小和内容类型被检索并显示在页面上供最终用户查看。当文件上传到服务器时,生成的页面与图 1 所示类似。

图 1
将文件上传到其他服务器可能会出现错误。使用适当的异常处理在代码中上传文件至关重要。这就是为什么示例中的文件使用 Try
Catch
语句上传的原因。
为 ASP.NET 提供上传文件的适当权限
当最终用户通过应用程序中的 FileUpload 控件将文件上传到您的 Web 服务器时,您可能会收到错误。这可能是因为服务器上的目标文件夹对于 ASP.NET 使用的帐户是不可写的。如果 ASP.NET 没有写入所需文件夹的权限,您可以通过文件夹的属性来启用它。
首先,右键单击 ASP.NET 文件应上传到的文件夹,然后从提供的菜单中选择“属性”。所选文件夹的“属性”对话框将打开。单击“安全”选项卡,确保 ASP.NET 计算机帐户包含在列表中,并且具有写入磁盘的适当权限。如果已启用,您将看到类似于图 2 中所示的内容。

图 2
如果您在允许访问文件夹的用户列表中看不到 ASP.NET 计算机帐户,请单击“添加”按钮,然后在提供的文本区域中输入 ASPNET(不带句点)来添加 ASP.NET(参见图 3)。

图 3
单击“确定”,然后您可以单击相应的复选框为您的应用程序提供所需的权限。
了解文件大小限制
您的最终用户可能永远不会遇到应用程序中文件上传过程的问题,但您应该知道存在一些限制。当用户进行文件上传过程时,实际上会向服务器发送一个用于上传的大小限制。默认大小限制为 4MB(4096KB);如果用户尝试上传大于 4096KB 的文件,则传输会失败。
大小限制可以保护您的应用程序。您希望阻止恶意用户将大量大文件上传到您的 Web 服务器,试图耗尽服务器上的所有可用进程。这种情况称为“拒绝服务攻击”。它会耗尽 Web 服务器的资源,导致合法用户无法获得服务器的响应。
.NET 的优点之一是它通常提供绕过限制的方法。您通常可以更改默认设置。要更改允许的上传文件大小的限制,您可以在 web.config.comments 文件(位于 ASP.NET 2.0 配置文件夹 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG 下)或您的应用程序的 web.config 文件中进行一些更改。
在 web.config.comments 文件中,找到一个名为 <httpRuntime>
的节点。在此文件中,您会看到默认允许的文件大小由 Web 服务器允许的实际请求大小(4096KB)决定。web.config.comments 文件的 <httpRuntime>
部分显示在列表 2 中。
列表 2:在 web.config 文件中更改文件大小限制设置
<httpRuntime
executionTimeout="110"
maxRequestLength="4096"
requestLengthDiskThreshold="80"
useFullyQualifiedRedirectUrl="false"
minFreeThreads="8"
minLocalRequestFreeThreads="4"
appRequestQueueLimit="5000"
enableKernelOutputCache="true"
enableVersionHeader="true"
requireRootedSaveAsPath="true"
enable="true"
shutdownTimeout="90"
delayNotificationTimeout="5"
waitChangeNotification="0"
maxWaitChangeNotification="0"
enableHeaderChecking="true"
sendCacheControlHeader="true"
apartmentThreading="false" />
您可以使用 web.config 文件的 <httpRuntime>
部分做很多事情,但有两个属性——maxRequestLength
和 executionTimeout
属性——特别值得关注。
maxRequestLength
属性是决定发送到 Web 服务器的请求大小的设置。当您上传文件时,文件包含在请求中;通过更改此属性的值,您可以更改允许上传的大小。此处的值以千字节为单位。要允许大于默认 4MB 的文件,请按以下方式更改 maxRequestLength
属性:maxRequestLength="11000"
。
此示例将 maxRequestLength
属性的值更改为 11,000KB(约 10MB)。有了此设置,您的最终用户就可以上传 10MB 的文件到服务器。更改 maxRequestLength
属性时,请注意 executionTimeout
属性的设置。此属性设置请求在 ASP.NET 关闭请求(无论是否完成)之前尝试在服务器上执行的时间(以秒为单位)。默认设置为 90
秒。如果超过时间限制,最终用户将在浏览器中收到超时错误通知。如果您允许更大的请求,请记住它们比较小的请求花费更长的时间来执行。如果您增加了 maxRequestLength
属性的大小,也应该考虑是否增加 executionTimeout
属性。
如果您处理的是较小的文件,建议通过减小 maxRequestLength
属性的值来减小分配给 Web 服务器请求的大小。这有助于保护您的应用程序免受拒绝服务攻击。
在 web.config.comments 文件中进行这些更改会将此设置应用于服务器上的所有应用程序。如果您只想将其应用于您正在处理的应用程序,请将 <httpRuntime>
节点应用于您应用程序的 web.config 文件,从而覆盖 web.config.comments 文件中的任何设置。确保此节点位于配置文件的 <system.web>
节点之间。
从同一页面上传多个文件
到目前为止,您已经看到了一些关于如何轻松上传文件的精彩示例。现在,让我们看看如何从单个页面上传多个文件到服务器。Microsoft .NET Framework 中没有内置功能可以从单个 ASP.NET 页面上传多个文件。但是,只需做一点工作,您就可以像过去使用 .NET 1.x 一样轻松地完成此任务。
诀窍是导入 System.IO
类到您的 ASP.NET 页面中,然后使用 HttpFileCollection
类来捕获随 Request
对象一起发送的所有文件。这种方法使您能够从单个页面上传任意数量的文件。如果您愿意,可以像列表 3 所示那样,单独处理每个 FileUpload 控件。
列表 3:单独处理每个 FileUpload 控件
VB
If FileUpload1.HasFile Then
' Handle file
End If
If FileUpload2.HasFile Then
' Handle file
End If
C#
if (FileUpload1.HasFile) {
// Handle file
}
if (FileUpload2.HasFile) {
// Handle file
}
如果您处理的文件上传框数量有限,此方法可行;但同时,在某些情况下,您可能希望使用 HttpFileCollection
类来处理文件。如果您处理的是服务器控件的动态生成列表,尤其如此。
例如,您可以构建一个 ASP.NET 页面,该页面具有三个 FileUpload 控件和一个 Submit 按钮(使用 Button 控件)。用户单击 Submit 按钮并将文件发布到服务器后,代码后置会将文件保存到服务器上的特定位置。文件保存后,会显示发布的文件信息(参见列表 4)。
列表 4:将多个文件上传到服务器
VB
Protected Sub Button1_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim filepath As String = "C:\Uploads"
Dim uploadedFiles As HttpFileCollection = Request.Files
Dim i As Integer = 0
Do Until i = uploadedFiles.Count
Dim userPostedFile As HttpPostedFile = uploadedFiles(i)
Try
If (userPostedFile.ContentLength > 0) Then
Label1.Text += "<u>File #" & (i + 1) & "</u><br>"
Label1.Text += "File Content Type: " & _
userPostedFile.ContentType & "<br>"
Label1.Text += "File Size: " & _
userPostedFile.ContentLength & "kb<br>"
Label1.Text += "File Name: " & _
userPostedFile.FileName & "<br>"
userPostedFile.SaveAs(filepath & "\" & _
System.IO.Path.GetFileName(_
userPostedFile.FileName))
Label1.Text += "Location where saved: " & _
filepath & "\" & _
System.IO.Path.GetFileName(_
userPostedFile.FileName) & _
"<p>"
End If
Catch ex As Exception
Label1.Text += "Error:<br>" & ex.Message
End Try
i += 1
Loop
End Sub
C#
protected void Button1_Click(object sender, EventArgs e)
{
string filepath = "C:\\Uploads";
HttpFileCollection uploadedFiles = Request.Files;
for (int i = 0; i < uploadedFiles.Count; i++)
{
HttpPostedFile userPostedFile = uploadedFiles[i];
try
{
if (userPostedFile.ContentLength > 0 )
{
Label1.Text += "<u>File #" + (i+1) +
"</u><br>";
Label1.Text += "File Content Type: " +
userPostedFile.ContentType + "<br>";
Label1.Text += "File Size: " +
userPostedFile.ContentLength + "kb<br>";
Label1.Text += "File Name: " +
userPostedFile.FileName + "<br>";
userPostedFile.SaveAs(filepath + "\\" +
System.IO.Path.GetFileName(
userPostedFile.FileName));
Label1.Text += "Location where saved: " +
filepath + "\\" +
System.IO.Path.GetFileName(
userPostedFile.FileName) +
"<p>";
}
}
catch (Exception Ex)
{
Label1.Text += "Error: <br>" + Ex.Message;
}
}
}
此 ASP.NET 页面允许最终用户选择最多三个文件并单击“上传文件”按钮,该按钮会初始化 Button1_Click
事件。使用 HttpFileCollection
类和 Request.Files
属性,您可以控制从页面上传的所有文件。当文件处于此状态时,您可以对它们进行任何操作。在本例中,会检查文件的属性并将其写入屏幕。最后,文件被保存在服务器根目录的 Uploads 文件夹中。此操作的结果如图 4 所示。

图 4

此摘录来自《Professional ASP.NET 2.0 Special Edition》的第 6 章“ASP.NET 2.0 Web 服务器控件”。该书是畅销书《Professional ASP.NET 2.0》的扩展版。这个新扩展的特别版增加了约 300 页的新内容,并对全书进行了更新。Bill Evjen(密苏里州圣路易斯)是 .NET 技术最活跃的倡导者之一。他自 2000 年起就涉足 .NET 领域,并创立了国际 .NET 协会,该协会代表着近 500,000 名全球会员。除了在 .NET 领域工作,Bill 还担任国际新闻和金融服务公司路透社首席科学家办公室的技术总监。Bill 是《Professional ASP.NET 2.0 Special Edition》和畅销书《Professional ASP.NET 2.0》的主要合著者。
版权所有 2006 Wiley Publishing Inc,经许可转载,保留所有权利。