65.9K
CodeProject 正在变化。 阅读更多。
Home

MultiUpload,一个更智能的 AJAX 文件上传服务器控件

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.27/5 (9投票s)

2007 年 12 月 19 日

GPL3

4分钟阅读

viewsIcon

77587

downloadIcon

1195

一个受 Google Mail 文件附件选择启发而创建的 ASP.NET 服务器控件,实现了 ASP.NET AJAX Extensions 1.0。

MultiUpload2 in run mode

引言

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 启用网站,并添加对包含 MultiUploadMultiUpload2 服务器控件的 Memba.WebControls.XP.dll 的引用。Memba.WebControls.XP.dll 是 Memba Velodoc XP Edition 的一部分。源代码可在上述下载位置找到。

MultiUploadMultiUpload2 暴露相同的属性和方法。只有实现方式不同。

  1. MultiUpload 是我们基于锚点标签实现此控件的第一次尝试。单击锚点标签会触发一个不可见的输入控件的 Click 事件。不幸的是,Firefox 中文件输入控件不实现 Click 方法,因此此控件仅在 Internet Explorer 中有效。
  2. 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>

表单还包含一个 divdivDisplay),其中包含一个 ASP.NET LiterallitDisplay)和一个 ASP.NET 提交按钮(btnSubmit)。

您可能需要在页面顶部使用以下语句注册标签前缀

<%@ Register Assembly="Memba.WebControls.XP" 
    Namespace="Memba.WebControls" TagPrefix="mbui" %>

为了使文件上传正常工作,您需要进行两项重要设置:

  1. <form> 标签上定义 enctype="multipart/form-data"
  2. 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 控件现在应该看起来像这样:

MultiUpload2 in design mode

现在页面已经设计好,我们需要代码来保存已发布的 文件。双击“提交”按钮 (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 控件的源代码可在 CodeplexGoogle codeSourceforge.NET 获取,并且有详细的注释。

历史

  • 版本 1.0 - 日期:2007 年 12 月 19 日
© . All rights reserved.