Introducing the Open Source AjaxSafeUpload control for ASP.NET
Newest release is version 1.1.1 - see Testing the AjaxSafeUpload control for testing and bugfixes on the way to this first full feature complete release.
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).
Multiple="true" enables upload of multiple files!
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 (if using database for storage), works with DotNetNuke, mojoPortal and Umbraco (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!
- 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.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.
- New in v1.0.0: Feature complete - server side checks passes nice error messages back to the user, both with and without legacy mode. (Plus misc. bugfixes for even more browser compatibility.)
- New in v1.1.1: Languages now supported: English, Danish, Norwegian, Swedish, German, Polish, Dutch. Also includes minor bugfixes.
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)
- Optionally: One new table created in a MySQL or MS SQL Server 2005/2008 database with select, update and delete rights for the website.
- High or medium trust hosting.
- 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 all client-side checks are repeated server side too, to ensure the only the right kind of files passes through to your program. The checks for images include checking if it really is a valid image, and optionally recreating it scaled (so any meta information is ignored). But in addition to this, I would also highly recommend to do "something" with all other kinds of 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.
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, plus bugfixes and improvements of the above code is by me: © 2011, 2012 Allan Kindberg Nielsen, http://www.kindbergs.dk/ajax-safe-uploader.aspx
(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.)
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.
Version 1.0.0 - feature complete and used in production environments!
I have myself been using it since v0.9.9 in a production environment.
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.)
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.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)
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
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.
(If you don't want to pass the old file around, you could also pass a zero length byte to
RestoreFilesForEditing, but then your code should be very careful to not delete the old file when the postback returns the same zero-length file, signaling that it was not changed.)
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.
No longer used in v0.10.0.
ImgDbSizeLimit - max size of resized images that can be stored in database (only for verification - see the FAQ)
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 - 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
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
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.