Why don't file uploads work during async postbacks?

As many people have noticed in their AJAX-enabled pages, file uploads do not work when doing an async postback. To my knowledge there's no way to support this scenario due to the browser's security restrictions. To understand why the upload doesn't work it's important to understand how async postbacks are performed and how that's different from how the browser performs a regular postback.

When the browser performs a regular postback it has the benefit of being actual code with no security restrictions running on the client computer. When you submit a form it creates a web request with all the form fields. When it encounters an <input type="file"> it examines the file the user chose, reads it from disk, and adds it to the web request.

When the AJAX JavaScript code is running in the browser it can do the first part about creating a request with all the form fields. However, when it gets to <input type="file"> fields it doesn't have the necessary security permissions to read those files from disk. Imagine what would happen it it could read those files: You could create a page that when visited will upload the user's c:\passwords.txt to a remote server! And we all know that every user has a file called passwords.txt on their C: drive. I bet just now you renamed it so my evil code couldn't run :)

So what's the workaround? Well, quite simply, the workaround is to do anything that doesn't involve a file upload during an async postback. Here are some solutions:

  1. Have a dedicated "Upload" button that does a regular postback instead of an async postback. You can achieve this using several techniques: Have the button be outside all UpdatePanels; have the button be the target of an UpdatePanel's PostBackTrigger; or call ScriptManager.RegisterPostBackControl() on it.
  2. Have a dedicated file upload page that doesn't have any UpdatePanels. Many web sites already do this anyway.

And now you might wonder, "why don't ASP.NET AJAX and the UpdatePanel handle this better?" We did give this a fair bit of thought and we decided that doing nothing was the best solution. One option we had was to throw some error from JavaScript if we detected any filled out <input type="file"> tags. But what if you wanted to do an async postback that had nothing to do with the file upload? Or perhaps only detect file uploads in certain regions of the document? That would involve even more expensive DOM tree walks that are already causing some performance degradation with UpdatePanels.

In conclusion, if you want a secure browser, you're not going to get file upload functionality from UpdatePanels. If you don't want a secure browser, please get your head checked. If you want to do file uploads, just use one of the two solutions I provided.

PS: This is the first blog post I've written using Windows Live Writer. I used to use the editor built in to Community Server and was extremely unhappy with it. Live Writer is so easy to use not only for writing and formatting text, but even for adding images to the post. It even creates a nice looking thumbnail automatically with many customization options.

17 Comments

  • My c:\passwords.txt file just says "U l33t HAXXOR!!1111oneoneone"

    You know just to throw them off. What they don't realize is that IS my password. Muahahah.

  • How does gmail support the async file uploads?

  • I think gmail uses the iframe trick..Its how lot of people did async operations before the XMLhttpRequest object was supported in all browsers.

  • Our company just uses iframes. but we also have our own ajax framework.

  • The iFrame trick is the only way you can do it, however I do believe their are so IE hacks to make it happen with pure Ajax but users have to have security settings set at the very lowest

  • Hi Jody,
    I just read your post and I think there's one key point that's being missed. For an AJAX request (e.g. an UpdatePanel's async postback), how do you craft the POST request that contains those bytes? You have to detect the tag, get its value (all this is possible), and then *read the file from disk*.

    That last part is obviously impossible. That's where my "insecure browser" comment came in as well as the C:\passwords.txt. If JavaScript running in the browser could read arbitrary files under default Internet security zone settings then it could just grab your passwords.txt file and transmit them to http://www.example.org/h4x0r.aspx . But it can't do that, and that's why UpdatePanel can't do it either.

    AJAX requests use the XmlHttpRequest object, which in addition to other settings, has a request body that you can set. For POST requests the request body contains the form fields, including textbox values, dropdown list selections, and uploaded file content.

    Unless you use a trick such as a hidden IFRAME, which ends up not being an XmlHttpRequest, but a regular browser request, there's no way to craft the response through JavaScript. The problem with UpdatePanel using the IFRAME trick is that it wouldn't be compatible at all with existing ASP.NET pages, which is contrary to the goal of UpdatePanel. (And no, I'm not saying UpdatePanel is 100% compatible, but it tries!)

    - Eilon

















































  • protected void Button1_Click(object sender, EventArgs e)

    {

    Label1.Text = FileUpload1.FileName;

    }

  • Hi Jody,
    The example you link to is using IE-only functionality that requires that you disable some security settings (hence the insecure browser thing I mentioned, and in fact the article mentions it as well under &quot;Security and System Consideration&quot;).
    During regular posts all file uploads happen in the same connection as the post itself. There is no separate data stream, TCP connection, HTTP request, or anything. Even if UpdatePanel could somehow split the request into two, it wouldn&#39;t be compatible with regular postbacks since they only use one request. The server would have to somehow combine two requests into one and that&#39;s begging for a bug farm.
    Now if you really want a treat, Jeffrey Zhao has a great series of articles on how to trick UpdatePanel into allowing file uploads during async posts. He uses some clever techniques that ASP.NET AJAX enables to reroute the requests. Please note that I haven&#39;t run the sample, and direct all questions about it to Jeffrey&#39;s site.
    Thanks,
    Eilon

  • Someone may help me on the same problem but using the Infragistic UltraWebTab and the File Upload control? ,it seems that the fileUpload control does not work with the following configuration from the WEBTAB:

    AsyncOptions EnableLoadOnDemand="True" ResponseContext="IncludeSelectedTab".

  • Hi Elion,

    I see why it's not possible to upload files with AJAX, but why is it possible to upload files with Flash? It seems to me that Flash shouldn't have security permissions to access file system. Is there something I'm missing?

    Thanks,
    Victor

  • Hi Victor, that's a great question. While I'm not familiar with Flash's implementation for accessing the file system, I can describe how Silverlight 1.1 allows access to the file system.

    In Silverlight 1.1 you can't directly access the file system, however, you can invoke the "Open File" common dialog and then the Silverlight runtime gives the developer a stream to read from the file. The developer won't know the exact file details and has no write access. The developer cannot trick it into opening any file other than the user selected through the dialog. For more info, as well as an example, check out the Silverlight QuickStarts:

    http://www.silverlight.net/QuickStarts/Other/Upload.aspx

    If I had to guess, I'd imagine that Flash has similar limitations, but you'd have to consult their documentation to see for sure.

    Thanks,
    Eilon

  • Flash is all Client side.
    It uses an async way to communicate with other server side languages.

    I don't think Flash can really access your file system unless you grant privileges.

  • Drew, Flash is a "signed" ActiveX control. It literally has "COMPLETE" access to your machine. Whether Flash allows delegates its privilege to Javascript through scripting [and whether it implements IObjectSafety amongst others] is another matter altogether [I haven't tried].

    Elion, Even the regular HTML &lt;input&gt; file=".." &lt;/input&gt; opens a file dialog. So it should not matter. So, we can live with that.

    ArindSoft has a async file upload control that claims to solve this problem of async upload. Whether they're using an hidden IFRAME, I'm not sure.

    Thanks,
    Vyas

  • In page load even add something like this:

    ScriptManager1.RegisterPostBackControl(uploadButton)

    ScriptManager1 // instance of ScriptManager
    uploadButton // button that trigger the upload (like a command button or a linkButton) something like that


  • IIts easy enough to create the PostBack trigger to make the appropriate button to a full postback if all you are using in a normal form, but what do you do when you are using a FormView or other such template based control? How do you handle it then since you cannot create the proper trigger now?





  • I have faced the same problem for uploading file with ajax update panel but

    i just added the trigger fot the ImageButton "imgbtnAddCustomAppln" as shown in abaove line and my code started working
    I have used First option from above two options ....thnx have a great fun

  • thanks man by i used "PostBackTrigger" trigger and then i can upload the image

Comments have been disabled for this content.