如果你访问Asp.net ajax 论坛,你会发现有成百的人询问当把File控件放到UpdatePanel里时,并不能够产生具有AJAX上传的效果。这肯定是不能够产生AJAX效果的,因为XMLHTTPRequest对象在内部上传数据时不支持这个功能。在本文我将给大家演示一个具有AJAX效果的文件上传方式。技巧很简单,我将使用iframe框架来上传文件,这样就不会刷新页面,并且在页面 上传过程中,他还会粗略的显示进度,下面是运行的截图



下面让我们详细介绍一下执行过程。就从main页面开始吧

<fieldset>

<legend>Photo Upload Demo</legend>

<div id="divFrame">

<iframe id="ifrPhoto" scrolling="no" frameborder="0"hidefocus="true"style="text-align:center;vertical-align:middle;border-style:none;margin:0px;width:100%;height:55px"src="PhotoUpload.aspx"></iframe>

</div>

<div id="divUploadMessage" style="padding-top:4px;display:none"></div>

<div id="divUploadProgress" style="padding-top:4px;display:none">

<span style="font-size:smaller">Uploading photo...</span>

<div>

<table border="0" cellpadding="0" cellspacing="2" style="width:100%">

<tbody>

<tr>

<td id="tdProgress1">  </td>


<td id="tdProgress2">  </td>

<td id="tdProgress3">  </td>

<td id="tdProgress4">  </td>

<td id="tdProgress5">  </td>


<td id="tdProgress6">  </td>

<td id="tdProgress7">  </td>

<td id="tdProgress8">  </td>

<td id="tdProgress9">  </td>


<td id="tdProgress10">  </td>

</tr>

</tbody>

</table>

</div>

</div>
</fieldset>


正如你所看到的,我使用了一些div来显示或者隐藏上传页面的信息与进度,并且最为重要的是我在iframe的onload事件里绑定了initPhotoUpload方法,下面就看看iframe对应页面的内容

<form id="photoUpload" enctype="multipart/form-data" runat="server">

<div>

<input id="filPhoto" type="file" runat="server"/>

</div>

<div id="divUpload" style="padding-top:4px">

<input id="btnUpload" type="button" value="Upload Photo" />

</div>
</form>The iframe


在iframe页面里包含了一个上传控件和一个button提交按钮,现我们看一下initPhotoUpload 函数,他是怎么执行的
function initPhotoUpload()
{

_divFrame = document.getElementById('divFrame');

_divUploadMessage = document.getElementById('divUploadMessage');

_divUploadProgress = document.getElementById('divUploadProgress');

_ifrPhoto = document.getElementById('ifrPhoto');


var btnUpload = _ifrPhoto.contentWindow.document.getElementById('btnUpload');


btnUpload.onclick = function(event)

{

var filPhoto = _ifrPhoto.contentWindow.document.getElementById('filPhoto');


//Baisic validation for Photo

_divUploadMessage.style.display = 'none';


if (filPhoto.value.length == 0)

{

_divUploadMessage.innerHTML = '<span style=\"colorff0000\">Please specify the file.</span>';

_divUploadMessage.style.display = '';

filPhoto.focus();

return;

}


var regExp = /^(([a-zA-Z]|(\\{2}\w+)\$?)(\\(\w[\w].*))(.jpg|.JPG|.gif|.GIF|.png|.PNG|.bmp|.BMP)$/;


if (!regExp.test(filPhoto.value)) //Somehow the expression does not work in Opera

{

_divUploadMessage.innerHTML ='<span style=\"colorff0000\">Invalid file type. Only supportsjpg, gif, png and bmp.</span>';

_divUploadMessage.style.display = '';

filPhoto.focus();

return;

}


beginPhotoUploadProgress();

_ifrPhoto.contentWindow.document.getElementById('photoUpload').submit();

_divFrame.style.display = 'none';

}
}

一旦加载iframe框架,我们就执行一些变量,这些变量都是以_为前缀来作为DOM的元素。我们同样添加了对iframe里button提交事件的引用。在click事件里,首先验证上传文件是否为空,我们还验证图片的类型,一段这些验证通过,我们将调用beginPhotoUploadProgress 方法来处理上传文件的过程,下面是beginPhotoUploadProgress

function beginPhotoUploadProgress()
{

_divUploadProgress.style.display = '';

clearPhotoUploadProgress();

_photoUploadProgressTimer = setTimeout(updatePhotoUploadProgress, PROGRESS_INTERVAL);
}

function clearPhotoUploadProgress()
{

for (var i = 1; i <= _maxLoop; i++)

{

document.getElementById('tdProgress' + i).style.backgroundColor = 'transparent';

}


document.getElementById('tdProgress1').style.backgroundColor = PROGRESS_COLOR;

_loopCounter = 1;
}

function updatePhotoUploadProgress()
{

_loopCounter += 1;


if (_loopCounter <= _maxLoop)

{

document.getElementById('tdProgress' + _loopCounter).style.backgroundColor = PROGRESS_COLOR;

}

else

{

clearPhotoUploadProgress();

}


if (_photoUploadProgressTimer)

{

clearTimeout(_photoUploadProgressTimer);

}


_photoUploadProgressTimer = setTimeout(updatePhotoUploadProgress, PROGRESS_INTERVAL);
}


你可能已经看到,我们基本的想法是使用timer(window.setTimeout)来显示上传的进度,下载我们看看服务器的代码

private const string SCRIPT_TEMPLATE = "<" + "script " +"type=\"text/javascript\">window.parent.photoUploadComplete('{0}',{1});" + "<" + "/script" + ">";

private void Page_Load(object sender, EventArgs e)
{

if (IsPostBack)

{

//Sleeping for 10 seconds, fake delay, You should not it try at home.

System.Threading.Thread.Sleep(10 * 1000);

UploadPhoto();

}
}

private void UploadPhoto()
{

string script = string.Empty;


if ((filPhoto.PostedFile != null) && (filPhoto.PostedFile.ContentLength > 0))

{

if (!IsValidImageFile(filPhoto))

{

script = string.Format(SCRIPT_TEMPLATE, "The uploaded file is not a valid image file.", "true");

}

}

else

{

script = string.Format(SCRIPT_TEMPLATE, "Please specify a valid file.", "true");

}


if (string.IsNullOrEmpty(script))

{

//Uploaded file is valid, now we can do whatever we like to do, copying it file system,

//saving it in db etc.


//Your Logic goes here


script = string.Format(SCRIPT_TEMPLATE, "Photo uploaded.", "false");

}


//Now inject the script which will fire when the page is refreshed.

ClientScript.RegisterStartupScript(this.GetType(), "uploadNotify", script);
}

private static bool IsValidImageFile(HtmlInputFile file)
{

try

{

using (Bitmap bmp = new Bitmap(file.PostedFile.InputStream))

{

return true;

}

}

catch (ArgumentException)

{

//throws exception if not valid image

}


return false;
}



在服务器上,我们同样执行了一些基本的验证,另外还我们还在客户端生成一些脚本,这些脚本将调用main页面里的photoUploadComplete 函数,他用来显示上传是成功还是失败
下面是photoUploadComplete 代码
function photoUploadComplete(message, isError)
{

clearPhotoUploadProgress();


if (_photoUploadProgressTimer)

{

clearTimeout(_photoUploadProgressTimer);

}


_divUploadProgress.style.display = 'none';

_divUploadMessage.style.display = 'none';

_divFrame.style.display = '';


if (message.length)

{

var color = (isError) ? '#ff0000' : '#008000';


_divUploadMessage.innerHTML = '<span style=\"color:' + color + '\;font-weight:bold">' + message + '</span>';

_divUploadMessage.style.display = '';


if (isError)

{

_ifrPhoto.contentWindow.document.getElementById('filPhoto').focus();

}

}
}