Monday, December 25, 2006

Uploading files to the server like GMail and Yahoo Mail


Recently I got to work on a project which needed file uploading just like in GMail and Yahoo Mail. Before proceeding further, I would like to mention that it is not possible to use AJAX to do file uploading to ther server as JavaScript can execute only in the browser and does not have access to the file system. So the technique we employed here is the the hidden IFrame .


To make this work we need JavaScript and any server side script. For the demo, I will be using ASP.NET with C# on the server side.


Let us delve in to the code without further delay.


Step 1: In your web application, create two aspx files UploadTest.aspx and UploadFile.aspx.

Step 2: Add this HTML code inside form tag to UploadTest.aspx

<table id="tblAttach">

<tr>


<!--- This td displays the link Attach File-->


<td id="td_upload_attach" style="DISPLAY: block;></td>


<!--This td displays the attaching message while the file is uploading to ther server-->


<td id="td_upload_attaching" style="DISPLAY: none"> </td>

<!--This td displays the attached file-->

<td id="td_upload_fileName" style="DISPLAY: none"></td>


<!--This td displays the Remove Link-->


<td id="td_upload_remove" style="DISPLAY: none"></td>

</tr>

</table>


Step 3: Update the first td to add an image and Attach File link and hidden IFrame. Clicking on Attach File link will call the javascript function AttachFile() (discussed later).



The hidden IFrame's source is set UploadFile.aspx that we created above.


<td style="DISPLAY: block;" id="td_upload_attach">


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


<tr>


<td width="16"><img src="paperclip.gif" width="16" height="16"></td>


<td nowrap align="left" class="blackFormText2"><a href="#" tabindex="12" class="blackFormText2" onclick="AttachFile();">Attach File</a></td> </tr> </table>


<iframe id="iFrameUpload" style="DISPLAY: none;" width="50" height="50" align="top" marginWidth="1" marginHeight="1" frameBorder="no" scrolling="no" src="UploadFile.aspx"> </iframe>


</td>


Step 4: Update the second td to add code that displays a rotating icon and a message attaching... while the file is uploading to the server.


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


<tr>


<td width="16"><img src="loading_small.gif" width="16" height="16"></td>


<td nowrap class="blackFormText" style="WHITE-SPACE:nowrap"><span id="span_upload_attaching">Attaching...</span></td>


</tr>


</table>


Step 5: Update the third td to add an image and the attached file name.


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


<tr>


<td width="16"><img src="attached.gif" width="14" height="16"></td> <td nowrap class="blackFormText2"><span id="span_upload_fileName"></span></td> </tr>


</table>


Step 6: Update the fourth td to add a remove image and a link to remove the attached file.


<td id="td_upload_remove" style="DISPLAY: none">


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


<tr>


<td width="16"><img src="remove.gif" width="14" height="16"></td>


<td nowrap class="blackFormText2"><a tabindex="12" href="#" class="blackFormText" onclick="RemoveFile();">Remove File</a> </td>


</tr>


</table>


</td>

Step 7: Now, let us discuss the javascript needed to accomplish our task. Add javascript script block inside the head section of the web form. Add two variable fileId and fileName;

<Script language="javascript">

var fileId=-1;

var fileName="";

</Script>


Step 8: Add the function AttachFile() inside the javascript block. When the user clicks the Attach File link, this function is called.


function AttachFile()


{


var uploadFrame=window.frames["iFrameUpload"].document;


uploadFrame.forms[0].txtFileToUpload.click();


if(uploadFrame.forms[0].txtFileToUpload.value!='')


{


var filePath=uploadFrame.forms[0].txtFileToUpload.value;


var fileNameIndexStart=filePath.lastIndexOf("//");


var fileName=filePath.substring(fileNameIndexStart+1,filePath.length);


document.getElementById('td_upload_attach').style.display='none';


document.getElementById('span_upload_attaching').innerHTML=


'attaching... '+fileName;


document.getElementById('td_upload_attaching').style.display='block';


uploadFrame.forms[0].submit();


}


}


Step 9: Add the function AttachFile_Callback(). This function is called by the UploadFile.aspx after attaching the file. Any errors reported by the UploadFile.aspx, are displayed to ther user.

Error Ids are set on the server side when an error is encounterd. (Discussed on Step 17)


function AttachFile_Callback(errorId,id,name)


{


if(errorId.length>0)


{


document.getElementById('td_upload_attach').style.display='block';


document.getElementById('td_upload_attaching').style.display='none';


switch(errorId)


{ case "1": window.parent.alert("Please select a file to upload");


break;


case "2": window.parent.alert("The uploaded file is empty");


break;


case "3": window.parent.alert("The uploaded file is too big. The file size cannot be greater than 5 MB.");


break;


case "4": window.parent.alert("Sorry, an unexpected error occurred uploading the file.");


break;


}


}


else if(id!="-1")


{


fileId=id; //set the file Id; fileName=name;


var spanFileName=document.getElementById('span_upload_fileName');


if(spanFileName!=null)


{ spanFileName.innerHTML=name; }


ShowUploadLink(false);


}


}



Step 10: Add the function RemoveFile(). This shows the attach file link again. I have not added code to remove the file on the server. If necessary you can add that here. You can pass the id of the file that we put in the global variable fileId to the server.


function RemoveFile() { ShowUploadLink(true); }


Step 11: Add the function ShowUploadLink(). This is a helper function to show and hide <td>s in the table.


function ShowUploadLink(flag)


{


var tdAttach=document.getElementById('td_upload_attach');


var tdAttaching=document.getElementById('td_upload_attaching');


var tdFileName=document.getElementById('td_upload_fileName');


var tdRemove=document.getElementById('td_upload_remove');


if(flag)


{


tdAttach.style.display='block'; tdAttaching.style.display='none';


tdFileName.style.display='none'; tdRemove.style.display='none';


}


else


{ tdAttach.style.display='none'; tdAttaching.style.display='none';


tdFileName.style.display='block'; tdRemove.style.display='block';


var spanFileName=document.getElementById('span_upload_fileName');


if(spanFileName!=null)


{ spanFileName.innerHTML=fileName; }


}


}



Step 12:


Now let us add code to the UploadFile.aspx. Add an input of type file.


<table width="100%" border="0" cellpadding="6" cellspacing="0" bgcolor="#e1ecf2" summary="This table is for layout">
<tr>
<td valign="top">
<input class="blueFormText" id="txtFileToUpload" title="File to Upload"
tabindex="200" type="file" size="30" name="filMyFile" runat="server" style="WIDTH: 275px; HEIGHT: 22px">
</td>
</tr>
</table>


Step 13:


Add three hidden variables to the web form.


<INPUT id="hidFileName" type="hidden" runat="server" NAME="hidFileName" class="blueFormText"> <INPUT type="hidden" runat="server" id="hidFileId" NAME="hidFileId" class="blueFormText" value=-1> <INPUT id="hidErrorId" type="hidden" runat="server">


Step 14:


To the body tag of the web form add onload event.


<body MS_POSITIONING="GridLayout" onload="CheckFileId();">


Step 15:


Add the javascript function that is called by onload event. This function calls AttachFile_Callback function we added above when ever this page is loaded in the browser.


<script language="javascript">

function CheckFileId()

{

var hidErrorId=document.getElementById('hidErrorId');

var hidFile=document.getElementById('hidFileId');

var hidFileName=document.getElementById('hidFileName');

window.parent.AttachFile_Callback (hidErrorId.value,hidFile.value,hidFileName.value); }

</script>


Step 16:


In the code behind of the UploadFile.aspx, in Page_Load(), I check if the page is posted back and call the UploadFile function that takes cared of adding the file to the database.


private void Page_Load(object sender, System.EventArgs e)
{
if(Page.IsPostBack)
UploadFile();
}


Step 17:


Add code for UploadFile server side function. The function checks for erorrs like 0 length, more than 5 MB and unexpected errors. If no errors file is put into the database.


private void UploadFile()
{
//check if the user selected a file.
if(txtFileToUpload.PostedFile.FileName.Trim() == null txtFileToUpload.PostedFile.FileName.Trim().Length == 0)
{
hidErrorId.Value="1";
return;
}
int intDocLen = txtFileToUpload.PostedFile.ContentLength;
if(intDocLen==0)
{
hidErrorId.Value="2";
return;
}
if(intDocLen>5000000)
{
//Response.Write("Please limit the file size to 5MB.");
hidErrorId.Value="3";
return;
}
try
{
string fileName=System.IO.Path.GetFileName(txtFileToUpload.PostedFile.FileName);
int fileLength=txtFileToUpload.PostedFile.ContentLength;
string fileType=txtFileToUpload.PostedFile.ContentType;
byte[] fileBin=new byte[fileLength];
System.IO.Stream stream = txtFileToUpload.PostedFile.InputStream;
stream.Read(fileBin,0,fileLength);
string connstr=util.WebConfigReader.GetAppSetting(model.Constants.CONNECTION_STRING_KEY); //change connection string
SqlConnection connection = new SqlConnection(connstr);
string sql="INSERT Into FileTable(FileName,Filetype,FileBin)Values(@FileName,@FileType,@FileBin);SELECT SCOPE_IDENTITY();"
SqlCommand insertCommand = new SqlCommand(sql,connection);


SqlParameter fileNameParam = new SqlParameter("@FileName", SqlDbType.VarChar);
fileNameParam.Value = fileName;
insertCommand.Parameters.Add(fileNameParam);

SqlParameter fileTypeParam = new SqlParameter("@FileType", SqlDbType.VarChar);
fileTypeParam.Value = fileType;
insertCommand.Parameters.Add(fileTypeParam);

SqlParameter fileBinParam = new SqlParameter("@FileBin", SqlDbType.Image);
fileBinParam.Value = fileBin;
insertCommand.Parameters.Add(fileBinParam);

connection.Open();
string fileId = insertCommand.ExecuteScalar().ToString();;
connection.Close();

hidFileId.Value=fileId;

hidFileName.Value=fileName;
}
catch(Exception ex)
{

hidErrorId.Value="4";
}
}

Digg It! Add to del.icio.us Stumble This

0 Comments: