MultiUpload,一个更智能的 AJAX 文件上传服务器控件
一个受 Google Mail 文件附件选择启发而创建的 ASP.NET 服务器控件,实现了 ASP.NET AJAX Extensions 1.0。
引言
HTML 文件输入控件及其派生的 ASP.NET FileUpload
控件存在一些重要限制,包括糟糕的图形设计和安全限制。我们的目标是提供一个更好的文件上传组件。这个功能由 MultiUpload
控件实现,它改进了 Google Mail 的文件附件体验。我们的环境是 Windows 和 IIS 上的 ASP.NET 2.0,并且我们的 MultiUpload
控件使用了 ASP.NET AJAX Extensions 1.0,您可以从此处下载和安装。
背景
本文参考了“Memba Velodoc XP Edition”的开源控件,您可以从此处下载(该页面提供了 Codeplex、Google Code 和 Sourceforge.NET 的链接),并且这些控件在 GPL 许可下分发。这些控件包括我们在这篇文章中使用的 MultiUpload
控件。您可以在此链接上实时体验这些控件。
使用代码
在 Visual Studio 2005 中,创建一个新的 ASP.NET AJAX 启用网站,并添加对包含 MultiUpload
和 MultiUpload2
服务器控件的 Memba.WebControls.XP.dll 的引用。Memba.WebControls.XP.dll 是 Memba Velodoc XP Edition 的一部分。源代码可在上述下载位置找到。
MultiUpload
和 MultiUpload2
暴露相同的属性和方法。只有实现方式不同。
MultiUpload
是我们基于锚点标签实现此控件的第一次尝试。单击锚点标签会触发一个不可见的输入控件的Click
事件。不幸的是,Firefox 中文件输入控件不实现Click
方法,因此此控件仅在 Internet Explorer 中有效。MultiUpload2
是我们第二次尝试实现此控件。MultiUpload2
是一个span
标签,上面覆盖了一个文件输入控件。请注意,span
标签可以轻松地替换为按钮或图像。文件输入控件的不透明度设置为 0,使其不可见,但可以接收“浏览”按钮的Click
事件。每次填充文件输入控件后,它会被移到隐藏位置并被一个新的控件替换,以便允许多个上传。
打开 Default.aspx 页面,通过将控件从工具箱拖放到页面上,或者简单地在现有的 <form>
标签之间添加以下代码来添加 MultiUpload2
服务器控件。
<form id="form1" runat="server" enctype="multipart/form-data">
<asp:ScriptManager ID="ScriptManager" runat="server" />
<!-- MultiUpload2 -->
<mbui:MultiUpload2 ID="MultiUpload" runat="server"
Text="Click me"
CssClass="cssMultiUpload"
HoverCssClass="cssHoverMultiUpload">
</mbui:MultiUpload2>
<!-- MultiUpload2 -->
<hr />
<div id="divDisplay" style="min-height:50px;">
<asp:Literal ID="litDisplay" runat="server"></asp:Literal>
</div>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
</form>
表单还包含一个 div
(divDisplay
),其中包含一个 ASP.NET Literal
(litDisplay
)和一个 ASP.NET 提交按钮(btnSubmit
)。
您可能需要在页面顶部使用以下语句注册标签前缀
<%@ Register Assembly="Memba.WebControls.XP"
Namespace="Memba.WebControls" TagPrefix="mbui" %>
为了使文件上传正常工作,您需要进行两项重要设置:
- 在
<form>
标签上定义enctype="multipart/form-data"
; - 在 web.config 的
<system.web>
部分添加一个httpRuntime
部分,并具有以下属性:
<httpRuntime maxRequestLength="1000000" executionTimeout="20000"/>
maxRequestLength
定义了 post 请求的最大大小(以千字节为单位)。ASP.NET 的默认值为 4096,这会将 post 请求的大小限制为 4 MB。executionTimeout
定义了请求的最大持续时间(以秒为单位)。建议使用 web.config 中的 <location>
部分将这些设置限制在特定页面。
从演示的角度来看,MultiUpload2
控件是一个 SPAN
。将以下样式添加到页面 </head>
关闭标签之上:
<style type="text/css">
<!--
.cssMultiUpload{
color:CornflowerBlue;
text-decoration:none;
}
.cssHoverMultiUpload{
color:CornflowerBlue;
text-decoration:underline;
}
//-->
</style>
您的 MultiUpload2
控件现在应该看起来像这样:
现在页面已经设计好,我们需要代码来保存已发布的 文件。双击“提交”按钮 (btnSubmit
) 以在 Default.aspx.cs 中实现服务器端 Click
事件处理程序。
private const string TARGET_DIR = "~/";
protected void btnSubmit_Click(object sender, EventArgs e)
{
//Check target directory
string sTargetDir = Request.MapPath(TARGET_DIR);
System.Diagnostics.Debug.Assert(Directory.Exists(sTargetDir));
StringBuilder objDisplay = new StringBuilder();
objDisplay.Append("<h3>You have just saved:</h3><ul>");
//Iterate through posted files (foreach does not work with empty file inputs)
for (int i = 0; i < Request.Files.Count; i++)
{
HttpPostedFile objFile = Request.Files[i];
//Make sure file input has content
if ((objFile.ContentLength > 0) && (objFile.FileName.Length > 0))
{
//Get target file path for save as
string sFileName = Path.GetFileName(objFile.FileName);
string sFilePath = Path.Combine(sTargetDir, sFileName);
FileInfo objFileInfo = new FileInfo(sFilePath);
//No business rule, i.e. we just want to avoid failure
if (objFileInfo.Exists)
{
objFileInfo.Attributes &= ~FileAttributes.ReadOnly;
objFileInfo.Delete();
}
//Save file
objFile.SaveAs(sFilePath);
//Append link
objDisplay.AppendFormat("<li><a href=\"{0}\">{1}</a></li>",
this.ResolveUrl(Path.Combine(TARGET_DIR, sFileName)), sFileName);
}
}
//Display in DIV
objDisplay.Append("</ul>");
litDisplay.Text = objDisplay.ToString();
}
在 Default.aspx.cs 的顶部添加以下语句:
using System.IO; //Directory, Path, FileInfo
using System.Text; //StringBuilder
按 F5 运行页面,单击标有“Click me”的 MultiUpload
控件添加文件,然后单击“Submit”按钮。响应应显示已上传文件的下载链接。
现在我们希望在选择文件时显示文件名。将以下脚本添加到页面 </body>
关闭标签之前。
<script type="text/javascript">
<!--
// Declare global variables for the various controls
var g_MultiUpload;
var g_Display = "<h3>You have selected:</h3><ul>";
//pageLoad function of ASP.NET Ajax Extensions framework
function pageLoad()
{
//Get a reference to the MultiUpload control
g_MultiUpload = $find("<%= MultiUpload.ClientID %>");
//Add en event handler for the browse event
if(g_MultiUpload)
g_MultiUpload.add_browse(onBrowse);
}
//pageUnload function of ASP.NET Ajax Extensions framework
function pageUnload()
{
if(g_MultiUpload)
g_MultiUpload.remove_browse(onBrowse);
}
//Event handler for the browse (click) event of the MultiUpload control
function onBrowse(sender, args)
{
g_Display += "<li>" + args.get_value() + "</li>";
$get("divDisplay").innerHTML = g_Display + "</ul>";
}
//-->
</script>
ASP.NET AJAX Extensions 提供了两个重要的 JavaScript 事件处理程序:
pageLoad
由框架在页面 DOM 和脚本加载并初始化时调用。这是一个获取控件引用和添加事件处理程序的理想位置。pageUnload
由框架在页面卸载时调用。建议在此阶段清除处理程序。
上面的脚本实现了 MultiUpload
控件的 browse
事件的处理程序。browse
事件处理程序会将所选文件的完整名称添加到显示在 divDisplay
DIV
中的无序列表中。
按 F5 运行项目,然后单击标有“Click me”的 MultiUpload
控件添加文件。现在页面应该显示已选择文件的列表。
我们现在希望与所选文件列表进行交互,特别是移除文件,但这将是另一篇文章的主题,题为使用 MultiUpload 和 ImageList 服务器控件进行专业的 文件上传。
关注点
此 MultiUpload
控件隐藏了动态创建文件输入 HTML 控件的复杂性,并消除了对已选择上传文件的演示的任何限制。对于更高级的开发人员,MultiUpload
控件的源代码可在 Codeplex、Google code 和 Sourceforge.NET 获取,并且有详细的注释。
历史
- 版本 1.0 - 日期:2007 年 12 月 19 日