Amit's Blog

Sharing Thoughts and Learning

  Home  |   Contact  |   Syndication    |   Login
  43 Posts | 1 Stories | 163 Comments | 19 Trackbacks

News

About Me?
Read it in
Blog Statistics
Proud Member of

Archives

Post Categories

Articles

Book Review

I Visit.

OpenSource Project(s)

If you visit Asp.net Ajax Forum, you will find hundreds of request on File Upload Control that it does not give Ajax version of the page when it is placed in an UpdatePanel. Certainly, it is not possible, as the XMLHTTPRequest object that is used internally to post the form does not support file upload. In this post I will show you how to create Ajax like version of the file upload. The trick is very simple, I will use an Iframe to upload the file so the whole page does not get refreshed and when the post is in progress it will show a dummy progress. The following shows you the screenshots of the solutions:

Initial In Progress Complete

Now lets discuss the implementation part, starting with the Main page markup.

<fieldset>
    <legend>Photo Upload Demo</legend>
    <div id="divFrame">
        <iframe id="ifrPhoto" onload="initPhotoUpload()" 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">&nbsp; &nbsp;</td> <td id="tdProgress2">&nbsp; &nbsp;</td> <td id="tdProgress3">&nbsp; &nbsp;</td> <td id="tdProgress4">&nbsp; &nbsp;</td> <td id="tdProgress5">&nbsp; &nbsp;</td> <td id="tdProgress6">&nbsp; &nbsp;</td> <td id="tdProgress7">&nbsp; &nbsp;</td> <td id="tdProgress8">&nbsp; &nbsp;</td> <td id="tdProgress9">&nbsp; &nbsp;</td> <td id="tdProgress10">&nbsp; &nbsp;</td> </tr> </tbody> </table> </div> </div> </fieldset>

As you see that we are using few divs to show and hide the upload form and the progress bar. The important thing is we are binding the initPhotoUpload in the frame load event. Now let us check the iframe source page markup.

<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 source page contains only a file upload control and a button to post the form. Now lets get back to the main page initPhotoUpload function and lets check how it is implemented:

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=\"color:#ff0000\">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=\"color:#ff0000\">Invalid file type. Only supports jpg, gif, png and bmp.</span>';
            _divUploadMessage.style.display = '';
            filPhoto.focus();
            return;
        }

        beginPhotoUploadProgress();
        _ifrPhoto.contentWindow.document.getElementById('photoUpload').submit();
        _divFrame.style.display = 'none';
    }
}

Once the iframe is loaded we are setting few module level variables (All module level variables are prefixed with _ (underscore) character in this example) to DOM elements, we are also getting the reference of the Upload button which is in the iframe and creating its click handler. In the click handler first we are doing few basic validation such as the file upload control is not empty or the file that is specified has a valid image file extension. Once the validation qualifies then we are calling the beginPhotoUploadProgress function (discussed next) and submitting the iframe form. The beginPhotoUploadProgress function is the first of three functions which are used to show the dummy progress bar. Let us see how these functions are written:

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);
}

As we can see we are basically using the timer (window.setTimeout) to show the dummy progress in these functions. Now lets see what happens in the server side when the iframe page posts.

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;
}

In the server side we are first doing some basic validation such as the file upload control has file and the file is a valid image file. Once the validation is done we are injecting some javascript which will be executed when the page is loaded in the browser. The javascript calls the main page photoUploadComplete function which shows the success/failure or the validation message of the upload. Lets see the javascript function photoUploadComplete of the main page.

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();
        }
    }
}

The function simply hides the progress bar and shows the upload control then it shows the message in colored text which is sent from the server.

I hope you can easily implment it in Ajax UpdatePanel, if not please let me know, I will show it in next post.

Download : Complete Solution

kick it on DotNetKicks.com

posted on Wednesday, August 01, 2007 3:36 AM

Feedback

# re: Create An Ajax Style File Upload 8/2/2007 3:28 AM Chandan
I am looking for this for a long time. Thanks very much.

# re: Create An Ajax Style File Upload 8/3/2007 1:58 PM subgurim
There's a control that does exactly this, and you only need to drag and drop it: the FileUpload AJAX [http://en.fileuploadajax.subgurim.net/]

# re: Create An Ajax Style File Upload 8/3/2007 2:00 PM Timothy
Looks great :-)
I'm just not sure if iframe isn't deprecated for the next (x)html release?

# re: Create An Ajax Style File Upload 8/3/2007 11:48 PM Justin.Th
Your regular expression test is a bit wierd, if you just care about the extension why not just use:

var regExp = /\.(jpe?g|gif|png|bmp)$/i;

note how the dot is escaped (it isn't in the article) and case-insensitivity is turned on with the i modifier... haven't tested but i think thats right from memory anyway :)

# re: Create An Ajax Style File Upload 8/4/2007 12:48 AM Kazi Manzur Rashid
Thanks Justin, it works like a charm in all browsers.

# re: Create An Ajax Style File Upload 8/22/2007 8:19 AM Eric
Is it possible to stick this in a modal popup?

# re: Create An Ajax Style File Upload 8/23/2007 8:11 AM no file to download
i couldn't download the complete solution. when i clicked the link, it takes me to different site but there's nothing to download. i would appreciate if someone can send me the file at gkeeara@yahoo.com.au. Cheers...........

# re: Create An Ajax Style File Upload 8/23/2007 8:55 PM Kazi Manzur Rashid
Hi, Sorry thr GWB does not allow to host file, thats why I have to upload it in an external site. To Download the file click the "Complete Soulution" in the bottom of the post, My shared folder of Box.net will be open in a new window. Then click the Main.aspx and PhotoUpload.aspx.

# re: Create An Ajax Style File Upload 8/24/2007 9:28 AM Jim Welch
Will this work, if the iframe is included within a form and the user clicks Submit button instead of the Upload Photo button to submit other info?

I've been looking for something similar to GMail's functionality for a while and I've found a bunch, but none that works both ways (standalone like this, and if included within a form and user clicks submit to upload all attachment(s) and form data.)

It would also be nice if it automatically began uploading like GMail does without the user needing to click Upload button. And if the file is still being uploaded and the user clicks Submit, then it works just like a normal fileupload control and is handled by the page.

# re: Create An Ajax Style File Upload 8/31/2007 12:49 AM Peter
Is there a size limitation for uploading a file?

# re: Create An Ajax Style File Upload 8/31/2007 1:22 AM Kazi Manzur Rashid
You can increase it from the web.config httpRuntime->maxRequestLength. Checkout this setting in http://msdn2.microsoft.com/en-us/library/e1f13641(vs.71).aspx

# re: Create An Ajax Style File Upload 9/11/2007 3:07 AM Timpn
Man you don't even know how long I've waited for this since disabling my own Movable Type widget (that doesn't work since Haloscan bypasses that code).

THANK YOU!

# multiple fileupload 9/13/2007 3:46 PM Xolon
First of all, nice piece of coding!

Secondly;

I'm trying to figure out how i could put this in a User Control so its usuable mutiple times on a page. But the javascript it preventing me from getting it right (i'm not a big javascripthero).

Has somebody got any idea how i could get it to work?

# re: Create An Ajax Style File Upload 10/9/2007 9:26 PM anonymous
why you think XMLHTTPRequest can't be used for file uploads? There are some problems with encoding binary streams, but it can be solved, imho.

# re: Create An Ajax Style File Upload 10/18/2007 5:14 AM danitzel
I need some help.

I need to send $_files[][] by GET.

HOW CAN I TOOK THAT INFO OR HOW CAN I SEND

# re: Create An Ajax Style File Upload 10/23/2007 2:49 AM Brad Broerman
Question I have been trying to solve is: How can I set up an iframe file upload without it putting an entry in the browser's history (i.e. back button)??

If anyone has an answer, please email me!

# re: Create An Ajax Style File Upload 10/28/2007 2:23 PM Sajjad
amazing,

# re: Create An Ajax Style File Upload 11/10/2007 2:34 AM rospy
thanx, that was great and looks really nice.

I managed to wrap it in a .NET user control with some modificiations, and now it can be used in an Ajax-enabled .NET as a common server control:

<cc:fileUpload runat=server width=50 _buttonText="Upload File" />
..etc etc with some other properties.

Do you mind if I post the code somewhere? of course i will link to your article



# re: Create An Ajax Style File Upload 11/10/2007 2:38 AM Kazi Manzur Rashid
Certainly, I won't mind but do not forget to share the code.

# re: Create An Ajax Style File Upload 11/15/2007 8:23 AM Ben
Hmm, looks what I was looking for, just need some clarification. Did you try it to get together with an HttpModule to be able to upload any file in chunks (the goal is to prevent a DOS attack)? I saw few AJAX fileupload custom web controls, but unfortunately none of them could fit in my AJAX enabled web app, the client side scripts are messing up my system:(
Will come back with some news on my solution shortly.Cheers

# re: Create An Ajax Style File Upload 11/18/2007 7:06 PM Max
Rospy - When are you going to post your version? Sounds just like what I'm looking for.

# re: Create An Ajax Style File Upload 11/25/2007 3:36 PM mkm
thank u, this sample was useful but ican not put it in UpdatePanel. can u help me?

# re: Create An Ajax Style File Upload 11/26/2007 11:18 AM mkm88
Hi,thanks 4 help.
but i can not put it in UpdatePanel. i have javascript error in page Load. please help ineed it as soon as possible.


# re: Create An Ajax Style File Upload 12/5/2007 1:15 PM Noman
i need the user control version. please help

# re: Create An Ajax Style File Upload 12/20/2007 10:57 AM Richard
Rospy - did you post the code for the control somewhere else?

# re: Create An Ajax Style File Upload 12/22/2007 6:46 PM Prasanna Kumar T E K
Hi,

thanks for the code...i want to know ..where the uploaded file save and cen we set the target...i dont know much about .net

# re: Create An Ajax Style File Upload 12/24/2007 1:25 PM Mina Alphonce
thanks a million
i've been looking for this a long time.
its works perfect for me

# re: Create An Ajax Style File Upload 1/24/2008 3:46 AM Goran
Hello !!

Your article is perfect. Thank you!!!
I combined your article and article "Building a Gmail Style File Uploading System using ASP.NET 2.0" (http://aspalliance.com/1441_Building_a_Gmail_Style_File_Uploading_System_using_ASPNET_20.all)

Why do you want to put into an UpdatePanel, mkm and mkm88? You have it in an iframe already...






# re: Create An Ajax Style File Upload 2/2/2008 5:23 PM Ashraf
Iam unable to make this technique work in Firefox...
can anybody guide me on how to make this work in both or all the browsers.Atleast right now I just want to know the exact catch in making this work in Firefox...
Thanx and regards
ashraf

# re: Create An Ajax Style File Upload 2/13/2008 6:19 PM balakrishnan
Thank u Friend

# re: Create An Ajax Style File Upload 2/14/2008 11:16 PM Andy Bradford
Unfortunately I get an error on the line

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

the error is 'Access is denied' with IE7. Firfox doesn't cause any problems. It only happens when a file is uploaded, when it initialises on page load its fine


# re: Create An Ajax Style File Upload 2/17/2008 9:14 AM cw
FileUpload control don't work in Ajax even if I run ScriptManager1.RegisterPostBackControl !

For detaisl please access: http://forums.asp.net/t/1218628.aspx

Thanks!

# re: Create An Ajax Style File Upload 2/25/2008 7:49 PM Robert
Progress indicators that lie are really frustrating, from a user's perspective. The best thing would be to use a spinning wheel or something that doesn't give a false indication of how long it's gonna take.

# re: Create An Ajax Style File Upload 2/27/2008 3:52 PM f
e

# re: Create An Ajax Style File Upload 3/4/2008 11:46 PM sheensjac
Hi
I have tried your code,but somehow it is not working properly for me.The progress bar is going on non stop and the file is not getting uploaded.That is server side code is not getting executed(Photoupload.aspx).Iam not sure where i have gone wrong.so can anyone pls help me to resolve this.

thanks in advance

# re: Create An Ajax Style File Upload 3/6/2008 1:53 PM mkm906
Thanks for the nice tip. It took me two days to get this working. But when I tested in firefox, it failed.

Right now I am using this ajax upload control:

http://ajaxuploader.com/Demo/


# re: Create An Ajax Style File Upload 3/6/2008 8:23 PM fajr
i have a problem to imlpement this code

i'm interested on it but it doesn't work with me there was error
said:

linq doesn't exist



what does that mean?????

please any help ??

# re: Create An Ajax Style File Upload 3/11/2008 11:02 PM B
Hi Kazi,

The "Download Complete Solution" link at the bottom of your post which goes to "http://www.box.net/shared/d72om3h1g2" is not working, I get a page cannot be displayed error.

Please let me know if there is somewhere else I can get download the solution.

Thank You!!

# re: Create An Ajax Style File Upload 4/5/2008 6:23 AM Daniella
I tryed your code and it runs right in IE but in Firefox shows an error:
Error: btnUpload has no properties

And the FF error console shows the error is here, at the first {:


btnUpload.onclick = function(event)
{
var filPhoto = _ifrPhoto.contentWindow.document.getElementById('filPhoto');
//hides content
_divUploadMessage.style.display = '';
// Shows loader gif animation
_divUploadMessage.innerHTML = '<img alt=\"\" src=\"/img/ajax-loader.gif\">';
// Submit form
_ifrPhoto.contentWindow.document.getElementById('photoUpload').submit();
_divFrame.style.display = 'none';
}

Some body could help me?! Thanks!! ;)

# re: Create An Ajax Style File Upload 4/15/2008 3:15 PM samir
when file getz uploaded on server side the function updatePhotoUploadProgress(message, isError) wont execute.
it gives object expected error.
plzz help...

# re: Create An Ajax Style File Upload 4/26/2008 11:09 PM AI-experts
thanks a lot !!!!!
i've been looking for this a long time.
its works perfect for me
tank u all


# re: Create An Ajax Style File Upload 5/7/2008 2:27 PM Halil İbrahim TÜRKOĞLU
Thank you very much for this and later solutions. I was looking for this one, for a longer time.

Thank you very much again.


Post Feedback

Title:
Name:
Email: (never displayed)
Url:
Comments: 
Please add 6 and 2 and type the answer here: