Introducing the Open Source AjaxSafeUpload control for ASP.NET
Newest release is version 0.10.1 - see Testing the AjaxSafeUpload control for changes, known problems and test progress towards making version 1.0.0.
The downloadable source code and demo project is at the bottom of this page - or it can be downloaded from my AjaxSafeUpload project on SourceForge, which also contains a bug tracking system.
What is it?
- A control that can replace the old
asp:FileUpload control (possibly without changing the code behind).
What new does it offer?
- Complete styling of the upload button with HTML and CSS, and styling of a list of uploads with CSS. The list of files and upload progress indicator is fairly compact, since you are probably doing other stuff on your page that is much more important than displaying fancy graphics for an uploader.
- Can be localized / translated (comes with English and Danish).
- Property
Multiple="true" enables upload of multiple files!
- Property
AllowedFileCategory gives different texts and upload handling for images, documents and other general files. When the image category is used the uploaded images will automatically be resized for use on the internet (that is: users can upload a 16MB jpg from their expensive digital camera, but it will be saved in much lower resolution).
- It can be put inside an asp:UpdatePanel and does not require full postback!!! This allows you to use the AjaxSafeUpload control on a form with validation controls - uploaded files are remembered between postbacks, so the user can correct his input without losing the uploaded file(s).
- Can be initialized with previously uploaded files. This allows you to use it for editing files that was uploaded earlier - users can upload and remove files from the list, without really changing anything before your program handles your own save or cancel buttons.
- Works with ASP.NET 3.5 and 4.0, works with Web Applications as well as the older websites model, works in web gardens/farms (note: not yet tested), works with DotNetNuke (and probably other CMS systems too), also works when the web applications is in a subdirectory, and most likely it will work with the ASP.NET websites you have programmed!
- Does not use Flash - only JavaScript and easily styled HTML.
- Provides fairly high security against misuse!
- New in v0.9.5: When compiled in debug mode you get informative error messages in the response, so you can see what when wrong when uploading a file. Uploads will also be delayed a few seconds to give you possibility to see and style the design of the progress indicator despite testing locally.
- New in v0.9.5: New security model - uploads will not be accepted unless they match an active control on one of your pages and match the type of files that control wants, and you can on each control specify the dimensions that uploaded images should be scaled to, and the max size of uploads.
- New in v0.9.6: Control will nicely degrade to informative text if uploading of files is impossible due to no JavaScript or uploading not supported (iPhone & iPad does not support uploading files on websites).
- New in v0.9.9: Added legacy mode for displaying the browser's native upload control for those (few) browsers where styling simply did not work.
- New in v0.10.0: Session state + file alternative that does not require a database table, but is still just as secure as before.
- New in v0.10.0: File storage even for the database model when the file is bigger than what you want in your database, and late loading of binary data (so that all the files does not have to be loaded into memory just to render a list of file names and sizes in partial postbacks with validation errors).
- New in v0.10.0: Even more customization to your desires.
- Roadmap for coming v1.0.0: JavaScript for legacy mode browsers upgraded with full checks and error messages (the only thing missing for calling it a full version 1).
How does it look?
This is a screen shot from the demonstration website (v0.9.6):

It shows the ugly red button (which you are supposed to style with HTML and CSS) and a list of attachments, with a Remove link (which you are supposed to style with CSS) for removing already uploaded files. The "Failed*" message has been changed to give the most likely cause (image too big) but in this example the cause of the failure is actually that it contains a blacklisted extension in the filename.
A styled version could look like this:

That second example also shows the control in "document" mode (different text).
Who is it for?
ASP.NET programmers who are writing custom websites or custom modules for CMS systems.
It is meant as a tool for programmers - I have no way of helping non-programmers with changing other programmers work, and the control does require styling by a programmer/designer before it is really usable.
What are the minimum requirements?
- ASP.NET 3.5.
- jQuery (tested with version 1.6.2)
- One new table created in a MySQL or MS SQL Server 2005/2008 database with select, update and delete rights for the website.
- High trust hosting (not yet tested in medium trust, but could work).
- Some dll's and some other files installed in some folders of your website

- Styling by a designer/programmer to fit the rest of your website.
- An asp:ScriptManager (or the alternate from the toolkit) on your (master) page
Are there security risks?
As uploaded files are stored in a table that is not used for anything else than a temporary memory, there is no way for hackers to upload files into the file system of your website. So no risk of ruining your running website and no risk for hosting hidden files that hackers could use to attack others.
Of course, this security comes at the expense of additional load on the database, which is used to store these files. Temporary files are automatically removed from the database after 24 hours.
New in v0.9.5/6:
When an user enters a page with a visible upload control, a record will be written to the database to allow uploads for that specific user/page/control, and only uploads matching certain criteria - for example an attempt to upload an file with an .exe ending if a document (Word, PDF, etc.) is expected will be rejected by the upload handler. And an attempt to upload anything else than a picture when a picture is expected will result in .NET failing to convert the file to a Bitmap - which happens to all images before they are stored.
Note that despite checks both client side (which is always unreliable) and in the upload handlers themselves, you should always call the method CheckIfValidFileExtension() server side in a CustomValidator or OnClick event, in order to re-verify that no files with wrong extensions have been injected. I would also highly recommend to do "something" with the uploaded files before trusting them - for example you could convert all documents to PDF files (throwing those files away that gives an exception during conversion).
Of course, if you tell the control to allow any user to upload any file, and you in your own code just saves that unknown file somewhere on your website where a hacker could call and execute its containing code on the server, then you have yourself made a big security hole!
New in v0.10.0:
Now it is also possible for uploaded files to be stored in the file system, but they are placed in a 'hidden' location and with a ".config" ending, which means that IIS should never allow them to be downloaded or otherwise (mis)used by anything outside the control itself.
Credits
The JavaScript file (which does the real magic of making the upload button and Ajax file uploads) is mostly from http://valums.com/ajax-upload/ © 2010 Andrew Valums
Original .NET code for receiving the uploaded files is from Syed BASHAR - http://www.codeproject.com/KB/aspnet/AspNetHandlerAjaxUpload.aspx
MS-Ajax-safe (UpdatePanel) idea and implementation as a standard control for ASP.NET is by me: © 2011 Allan Kindberg Nielsen, http://www.kindbergs.dk/ajax-safe-uploader.aspx
License
As the JavaScript core is licensed under GNU GPL and GNU LGPL 2, I am licensing my Visual Studio solution with all the files created or modified by myself as Open Source under the same licenses.
(Note: That covers all the included files except MySQL database dll, which you should download from dev.mysql.com if you want to use MySQL instead of SQL Server.)
Browser/platform goals
As I am developing websites both for computers, phones and tablets, I want this control to cover all major browsers on those platforms - if the platform supports uploading files at all.
Note: iPad and iPhone does not support uploading files in websites - you need to write an app for them if you need to upload pictures!
Why does the button say "attach" instead of "upload"?
Well, I am a programmer and you are a programmer - but our target audiences for our websites are probably people who do not know the difference between upload and download, plus due to the Ajax nature of the control, they have actually not yet done any change by sending the file.
The way this control works is more like an email program, where you can attach a file, but you still need to write some text and press a "Send" button before any real action happens.
So it is my hope that "Attach a document" communicates better - and if you disagree you are still free to change the text.
Known limitations
Version 0.10.0 - almost production ready!
I have myself been using v0.9.9 in a production environment, but the new "Legacy mode" is still very basic. If you disable it by setting LegacyMode="No" then you will only be using features that are fairly well tested - and users of those few browsers that need the legacy mode will be asked to use a different browser.
I expect that I will rewrite the Legacy mode to work more and more like the styled version with respect to error messages, but it will not be a high priority (I need to do some other projects first).
See the FAQ in the support forum for configuring max allowed upload size and other configuration stuff that are you probably have to do.
Be aware that the control might be memory hungry - if you allow someone to upload a 500MB video, then the control will try to load all those 500MB into memory all at once! (For a paid project I might redesign the control to better handle this case, but until then it is mostly for all the regular small files people wants to upload to a website, like images and Word/PDF documents. If you need to handle really big files right now, try a look at the NeatUpload control instead of mine.)
Oh yeah, the control does require JavaScript to be on, but if not then a text will be displayed asking people to turn it on in order to upload files. (I experimented with a Flash uploader too, but when Flash is blocked you usually don't see any alternate texts, and Flash cannot be easily styled as this HTML control can be.)
Installation instructions
Download the Visual Studio 2010 solution. It consists of both the source code and a web application for testing the AjaxSafeUpload component inside an UpdatePanel with validators.
From v0.9.6 it also includes a folder "deployment_bin" which contains precompiled dlls in all possible variations.
From v0.10.0 the default project is the session based solution that does not require any test database - but there is also included a test database for SQL Server 2008 Express.
When you open the solution please note that there are 3 versions of "release" and 3 versions of "debug" - one version is for compiling with MySQL support, one is for compiling with Session state support, and the last is for compiling with SQL Server support.
There are also two .sql files with scripts to create the needed table - connect to the right database and execute the script matching your database. Note: v0.9.5 and v0.10.0 introduced new fields that you need to add if you tried the original code.
For the database versions: Edit the connection string in the web.config file to point to your test database - either the ajaxSafeUploadMySqlConn or the ajaxSafeUploadMSSQLServerConn, depending on which database you have chosen to compile.
For using the control in your own project, you again need setup your database or use the session state based version, and then copy these files to your web application:
\bin\Kindbergs.Controls.dll
\bin\Kindbergs.Controls.DAL.dll (Note: different file depending on chosen database)
\bin\MySql.Data.dll (if MySQL is used - download latest dll from dev.mysql.com)
\bin\da\Kindbergs.Controls.resources.dll (Danish translation)
\controls\AjaxSafeUpload.ascx
\controls\upload\FileUpload.ashx
\controls\upload\asu_fileuploader.css
\controls\upload\asu_button.template
\controls\upload\asu_list.template
\controls\upload\asu_fileuploader.js
\controls\upload\ImgUpload.ashx
\controls\upload\LegacyUpload.aspx
\controls\upload\loading.gif
\controls\upload\web.config
On the page where you want to use the control add this at the top (just below the @page directive):
<%@ Register Src="~/controls/AjaxSafeUpload.ascx" TagPrefix="kma" TagName="AjaxSafeUpload" %>
Do a compile to let Visual Studio recognize the new stuff (ensure that all the added files are part of your project, and for Web Applications you should right-click on "References", select "Add reference" and select the "Kindbergs.Controls.dll" in the bin directory). Then insert the new control like this example:
<kma:AjaxSafeUpload ID="afuPicture" runat="server" Multiple="true" AllowedFileCategory="WebAndCameraImages" />
See the demonstration project for examples of validation before using files.
Interacting with the control in your code
Besides properties similar to the asp:FileUpload control (which only handles one file) take a look at these new properties:
public int FileCount
public List<string> ListOfFileName
public List<byte[]> ListOfFileBytes
public bool HasFile
Ok, the last one was not new, but it is true if there are one or more files uploaded, and false otherwise.
V0.10.0 added this new alternate property that replaces ListOfFileName and ListOfFileBytes:
public UploadedFile[] Files
This new property is an array of a class that for each item contrains the file name, size, the byte[] of the uploaded file and other new properties and methods for storing the files.
There are methods like these:
public bool CheckIfValidFileExtension()
public void RestoreFilesForEditing(Dictionary<string, byte[]> dictFilenameBytes)
Basically, once the user clicks your save button (and validation is passed), it is up to you to take these filenames and byte[] arrays and store them where you need them - in your database (other tables), in files, sending them by email or whatever you desire. And later on, if the user wants to edit the files he previously uploaded, then you call RestoreFilesForEditing() to give the byte[] from your own tables back to the AjaxSafeUpload control - which will again store them in the temporary table.
AllowedFileCategory - can be set to any of: WebAndCameraImages, CommonDocuments, CorporateDocuments, AnyFile, AnyNotBlacklistedFile. It is a quick way of selecting texts, allowed extensions and (for the image category) a special uploader that automatically resizes the images.
New properties introduced in v0.9.5:
ImgWidthRange - specify as "100-500" if you want pictures resized to fit between 100 and 500 pixel.
ImgHeightRange - same as for height. The aspect ratio of the picture will be preserved if you give flexible ranges.
ImgDbSizeLimit - max size of resized images that can be stored in database (only for verification - see the FAQ) No longer used in v0.10.0.
UploadSizeLimit - max allowed upload size.
In v0.9.5 the styling of the button and the list has also been moved to two separate files: asu_button.template and asu_list.template - so there should no more be any reason for editing the ascx control directly (and in future versions I might remove that file completely).
New properties introduced in v0.9.6:
AsuTheme - default is "asu", but if you change it to "mine" then the control will look for mine_button.template, mine_list.template and mine_fileuploader.css in the "~/controls/upload" folder - so this way you can have multiple upload buttons that each are styled differently.
IncludeCssLink - set to "false" if you don't want the control to load its own stylesheet. But only do it if you copied all the needed styles to your own master stylesheet!
v0.9.6 was also modified so that initialization/security records will only be written to the database if the control is visible - that means: it you are crazy enough to put it inside an edit template of a list control such as GridView, then only the one single row that is in edit mode will actually prepare the table for receiving uploads.
Other new properties introduced in v0.9.9 and v0.10.0:
ButtonText - allows you to give a different text of the button. The list title will be changed to a simple "Attached:" when you specify a custon button text (unless you also specify ListTitle).
ListTitle - allows you to give a different text of the list title shown above the list of uploaded files.
ListEmptyText - allows you to give a different text to display when no files are uploaded.
NameMaxLength - filenames that are longer than this number of letters will be shortened.
NameEndLength - when shortening filenames this amount of letters will be preserved from the end (so that file extension is visible). Must be smaller than NameMaxLength - 4.
LegacyMode - set to Auto, Yes or No. Use "Yes" for testing the look of the legacy mode in any browser, or use "No" to disable it if it seams too basic in its functionality for you. Default is "Auto" that will only use legacy mode when needed. If LegacyMode is disabled then those browsers that does not work with the styled buttons will not be able to upload files (they will see a message asking them to use a different browser).
CustomExtensions - for example set to "zip, rar, 7z" if you only want to allow uploads with those extensions. Note that AllowedFileCategory is still used - this property just overrides the build in lists of extensions.
ImgNoScaling - set to true if you don't want the image upload handler to resize images. It will ensure that uploaded images are stored exactly as uploaded (for example the .NET methods for saving gif files are very poor, so if you want high res gif files it is better that you do the resizing yourself after accepting the uploaded file and only when needed.) Note: For security reasons the image upload handler still tries to load the uploaded image into a Bitmap, just to verify that it really was an image, but additional meta data will be preserved.
New methods in v0.10.0:
SaveAs(string pathAndName) - saves the uploaded file to the file system. If the file name starts with "~/" then MapPath is called to get a physical path.
SaveAs(string destPath, string destFileName) - same as above, the path and filename is just split up, and if the destPath is missing a final "\" it will automatically be added.
CleanupQuick() - instead of waiting for cleanup after 24 hours, you can call this method after processing the uploaded files, so that the associated temporary files and/or database records gets instantly deleted. (By "quick" I mean that is does not go looking for additional records to clean up - the cleanup of stuff older than 24 hours only happens as the last step of uploading any new file.)
Note that there is also a class called Kindbergs.ImageUtils which contains functions for scaling images and for storing files/bitmaps/byte[] as image files or byte[] using any of the 5 supported image save formats in ASP.NET: jpg, png, gif, bmp & tif.
If you are using the Image category you can take the Files array and cast each item to the UploadedImage class to get direct access to SaveImage(...) methods.
New web.config settings in v0.10.0:
<add key="asu_BlobDbLimitKb" value="1024" /> - specify this if you want big files (or any file) stored in the files system instead of in the database. The value is the size in kilobyte that is the limit to store in the database - use "0" if you always want files stored on disk.
<add key="asu_TempLocation" value="~/App_Data/asu_temp/"/> - this value specifies the location where temporary files are stored. You can also give an absolute path to a location outside your website (ensure that the website IIS process has write access to that location).
<add key="asu_SecretFileKey" value="1234"/> - added as the first part of the file name when stored in the temp location. It must be unique for your application (if you do not include this line, then an unique hash value will be generated based on your machinekey value). Be aware that any ".config" file that starts with this value will automatically be deleted after 24 hours!
That is the end of this 'short' introduction - refer to the FAQs in the Support forum for more information.