Salah satu permasalahan pada ASP.NET AJAX Update Panel adalah tidak dapat melakukan asynchronous communication pada proses upload file. Hal ini disebabkan karena pada dasarnya object XMLHttpRequest (XHR) tidak dapat mengirimkan sebuah file dengan alasan keamanan. Pada beberapa situs seperti Google Mail dan Community Server tetap dapat melakukan upload file tanpa me-refresh seluruh halaman.
Solusi Alternatif
Saah satu alternatif cara untuk melakukan upload tanpa harus me-refresh seluruh halaman adalah menggunakan IFrame yang tersembunyi (hidden IFrame). Pada halaman utama disisipkan sebuah iframe yang berisi sebuah halaman kosong dan pada form target halamannya diarahkan ke halaman kosong yang ada di dalam iframe tersebut. Dengan cara ini hanya bagian IFrame saya yang akan melakukan komunikasi dengan server tanpa mempengaruhi keseluruhan halaman.
Langkah langkah trik ini adalah sebagai berikut.
- Tambahkan hidden IFrame pada halaman dan set sembunyikan dengan style="display:none".
<iframe name="hiddenFrame" src="blank.htm" mce_src="blank.htm" style="display:none"></iframe>
- Buat file blank.htm pada sollution.
File ini dibutuhkan untuk memastikan bahwa IFrame masih dalam lingkup domain yang sama dengan halaman utama. Jika file blank.htm berada di luar domain (misal default blank.htm yang ada di komputer lokal) maka akan ada penolakan hak akses terhadap eksekusi script di luar domain. - Tambahkan kontrol FileUpload ke dalam form
<asp:FileUpload ID="fileUpload1" runat="server" />
- Buat fungsi submitForm yang berfungsi melakukan submit terhadap hidden IFrame.
// Fungsi memiliki dua parameter yang berisi referensi element IFrame
// dan element ID control FileUpload
function submitForm(frameName,upload){
// Diasumsikan bahwa halaman utama adalah default.aspx
document.forms[0].action="default.aspx"
// Inti dari trik ini adalah mengeset target form ke hidden IFrame
document.forms[0].target=frameName;
// setTimeout digunakan untuk mengupdate dokumen dengan thread yang terpisah,
// jika tidak maka dokumen tidak akan baru terupdate setelah download selesai.
window.setTimeout(function(){
var uploadE=document.getElementById(upload);
uploadE.parentElement.appendChild(document.createTextNode(uploadE.value));
uploadE.parentElement.replaceChild(uploadE.cloneNode(true),uploadE);
},100);
document.forms[0].submit();
}
- Buat tombol dan tambahkan attribute onclick untuk memanggil fungsi submitForm yang telah dibuat sebelumnya.
<button onclick="javascript:submitForm('hiddenFrame','<%= fileUpload1.ClientID %>')">Upload</button>
- Tambahkan web kontrol label yang akan diisi dengan jam pertama kali halaman dimuat,
<asp:Label ID="lblTime" runat="server" />
- Pada code behind, saat Page_Load set label dengan jam berjalan dan cek jika ada file yang diupload, simpan ke dalam server.
protected void Page_Load(object sender, EventArgs e)
{
lblTime.Text = DateTime.Now.ToLongTimeString();
if (fileUpload1.HasFile)
{
fileUpload1.SaveAs(Server.MapPath("App_Data/") + fileUpload1.FileName);
}
}
- Selesai
Dari langkah-langkah tersebut di atas, secara lengkap kode dapat dilihat sebagai berikut.
File default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HiddenIFrameUpload._Default" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"> <title>Untitled Page</title></head><body> <asp:Label ID="lblTime" runat="server" /> <iframe name="hiddenFrame" src="blank.htm" style="display:none"></iframe> <form id="form1" runat="server" enctype="multipart/form-data" > <div id="uploadContainer"> <asp:FileUpload ID="fileUpload1" runat="server" /> <button onclick="javascript:submitForm('hiddenFrame','<%= fileUpload1.ClientID %>')">Upload</button> </div> </form> <script type="text/javascript"> function submitForm(frameName,upload){ document.forms[0].action="Default.aspx" document.forms[0].target=frameName; window.setTimeout(function(){ var uploadE=document.getElementById(upload); uploadE.parentElement.appendChild(document.createTextNode(uploadE.value)); uploadE.parentElement.replaceChild(uploadE.cloneNode(true),uploadE); },100); document.forms[0].submit(); } </script></body></html>
File default.aspx.cs
using System;
using System.Web;
namespace HiddenIFrameUpload
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
lblTime.Text = DateTime.Now.ToLongTimeString();
if (fileUpload1.HasFile)
{
fileUpload1.SaveAs(Server.MapPath("App_Data/") + fileUpload1.FileName);
}
}
}
}
HiddenIFrameUpload.zip (5.88 kb)