I’m excited to announce the April 2013 release of the Ajax Control Toolkit. For this release, we focused on improving two controls: the AjaxFileUpload and the MaskedEdit controls.
You can download the latest release from CodePlex at http://AjaxControlToolkit.CodePlex.com or, better yet, you can execute the following NuGet command within Visual Studio 2010/2012:
There are three builds of the Ajax Control Toolkit: .NET 3.5, .NET 4.0, and .NET 4.5.
A Better AjaxFileUpload Control
We completely rewrote the AjaxFileUpload control for this release. We had two primary goals.
First, we wanted to support uploading really large files. In particular, we wanted to support uploading multi-gigabyte files such as video files or application files.
Second, we wanted to support showing upload progress on as many browsers as possible. The previous version of the AjaxFileUpload could show upload progress when used with Google Chrome or Mozilla Firefox but not when used with Apple Safari or Microsoft Internet Explorer. The new version of the AjaxFileUpload control shows upload progress when used with any browser.
Using the AjaxFileUpload Control
Let me walk-through using the AjaxFileUpload in the most basic scenario. And then, in following sections, I can explain some of its more advanced features.
Here’s how you can declare the AjaxFileUpload control in a page:
<ajaxToolkit:ToolkitScriptManager runat="server" />
<ajaxToolkit:AjaxFileUpload
ID="AjaxFileUpload1"
AllowedFileTypes="mp4"
OnUploadComplete="AjaxFileUpload1_UploadComplete"
runat="server" />
The exact appearance of the AjaxFileUpload control depends on the features that a browser supports. In the case of Google Chrome, which supports drag-and-drop upload, here’s what the AjaxFileUpload looks like:
Notice that the page above includes two Ajax Control Toolkit controls: the AjaxFileUpload and the ToolkitScriptManager control. You always need to include the ToolkitScriptManager with any page which uses Ajax Control Toolkit controls.
The AjaxFileUpload control declared in the page above includes an event handler for its UploadComplete event. This event handler is declared in the code-behind page like this:
protected void AjaxFileUpload1_UploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e) {
// Save uploaded file to App_Data folder
AjaxFileUpload1.SaveAs(MapPath("~/App_Data/" + e.FileName));
}
This method saves the uploaded file to your website’s App_Data folder. I’m assuming that you have an App_Data folder in your project – if you don’t have one then you need to create one or you will get an error.
There is one more thing that you must do in order to get the AjaxFileUpload control to work. The AjaxFileUpload control relies on an HTTP Handler named AjaxFileUploadHandler.axd. You need to declare this handler in your application’s root web.config file like this:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxRequestLength="42949672" />
<httpHandlers>
<add verb="*" path="AjaxFileUploadHandler.axd" type="AjaxControlToolkit.AjaxFileUploadHandler, AjaxControlToolkit"/>
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<add name="AjaxFileUploadHandler" verb="*" path="AjaxFileUploadHandler.axd" type="AjaxControlToolkit.AjaxFileUploadHandler, AjaxControlToolkit"/>
</handlers>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4294967295"/>
</requestFiltering>
</security>
</system.webServer>
</configuration>
Notice that the web.config file above also contains configuration settings for the maxRequestLength and maxAllowedContentLength. You need to assign large values to these configuration settings — as I did in the web.config file above — in order to accept large file uploads.
Supporting Chunked File Uploads
Because one of our primary goals with this release was support for large file uploads, we added support for client-side chunking. When you upload a file using a browser which fully supports the HTML5 File API — such as Google Chrome or Mozilla Firefox — then the file is uploaded in multiple chunks.
You can see chunking in action by opening F12 Developer Tools in your browser and observing the Network tab:
Notice that there is a crazy number of distinct post requests made (about 360 distinct requests for a 1 gigabyte file). Each post request looks like this:
http://localhost:24338/AjaxFileUploadHandler.axd?contextKey={DA8BEDC8-B952-4d5d-8CC2-59FE922E2923}&fileId=B7CCE31C-6AB1-BB28-2940-49E0C9B81C64
&fileName=Sita_Sings_the_Blues_480p_2150kbps.mp4&chunked=true&firstChunk=false
Each request posts another chunk of the file being uploaded. Notice that the request URL includes a chunked=true parameter which indicates that the browser is breaking the file being uploaded into multiple chunks.
Showing Upload Progress on All Browsers
The previous version of the AjaxFileUpload control could display upload progress only in the case of browsers which fully support the HTML5 File API. The new version of the AjaxFileUpload control can display upload progress in the case of all browsers.
If a browser does not fully support the HTML5 File API then the browser polls the server every few seconds with an Ajax request to determine the percentage of the file that has been uploaded. This technique of displaying progress works with any browser which supports making Ajax requests.
There is one catch. Be warned that this new feature only works with the .NET 4.0 and .NET 4.5 versions of the AjaxControlToolkit. To show upload progress, we are taking advantage of the new ASP.NET HttpRequest.GetBufferedInputStream() and HttpRequest.GetBufferlessInputStream() methods which are not supported by .NET 3.5.
For example, here is what the Network tab looks like when you use the AjaxFileUpload with Microsoft Internet Explorer:
Here’s what the requests in the Network tab look like:
GET /WebForm1.aspx?contextKey={DA8BEDC8-B952-4d5d-8CC2-59FE922E2923}&poll=1&guid=9206FF94-76F9-B197-D1BC-EA9AD282806B HTTP/1.1
Notice that each request includes a poll=1 parameter. This parameter indicates that this is a polling request to get the size of the file buffered on the server. Here’s what the response body of a request looks like when about 20% of a file has been uploaded:
Buffering to a Temporary File
When you upload a file using the AjaxFileUpload control, the file upload is buffered to a temporary file located at Path.GetTempPath(). When you call the SaveAs() method, as we did in the sample page above, the temporary file is copied to a new file and then the temporary file is deleted.
If you don’t call the SaveAs() method, then you must ensure that the temporary file gets deleted yourself. For example, if you want to save the file to a database then you will never call the SaveAs() method and you are responsible for deleting the file. The easiest way to delete the temporary file is to call the AjaxFileUploadEventArgs.DeleteTemporaryData() method in the UploadComplete handler:
protected void AjaxFileUpload1_UploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e) {
// Save uploaded file to a database table
e.DeleteTemporaryData();
}
You also can call the static AjaxFileUpload.CleanAllTemporaryData() method to delete all temporary data and not only the temporary data related to the current file upload. For example, you might want to call this method on application start to ensure that all temporary data is removed whenever your application restarts.
A Better MaskedEdit Extender
This release of the Ajax Control Toolkit contains bug fixes for the top-voted issues related to the MaskedEdit control. We closed over 25 MaskedEdit issues. Here is a complete list of the issues addressed with this release:
· 17302 MaskedEditExtender MaskType=Date, Mask=99/99/99 Undefined JS Error
· 11758 MaskedEdit causes error in JScript when working with 2-digits year
· 18810 Maskededitextender/validator Date validation issue
· 23236 MaskEditValidator does not work with date input using format dd/mm/yyyy
· 23042 Webkit based browsers (Safari, Chrome) and MaskedEditExtender
· 26685 MaskedEditExtender@(ClearMaskOnLostFocus=false) adds a zero character when you each focused to target textbox
· 16109 MaskedEditExtender: Negative amount, followed by decimal, sets value to positive
· 11522 MaskEditExtender of AjaxtoolKit-1.0.10618.0 does not work properly for Hungarian Culture
· 25988 MaskedEditExtender – CultureName (HU-hu) > DateSeparator
· 23221 MaskedEditExtender date separator problem
· 15233 Day and month swap in Dynamic user control
· 15492 MaskedEditExtender with ClearMaskOnLostFocus and with MaskedEditValidator with ClientValidationFunction
· 9389 MaskedEditValidator – when on no entry
· 11392 MaskedEdit Number format messed up
· 11819 MaskedEditExtender erases all values beyond first comma separtor
· 13423 MaskedEdit(Extender/Validator) combo problem
· 16111 MaskedEditValidator cannot validate date with DayMonthYear in UserDateFormat of MaskedEditExtender
· 10901 MaskedEdit: The months and date fields swap values when you hit submit if UserDateFormat is set.
· 15190 MaskedEditValidator can’t make use of MaskedEditExtender’s UserDateFormat property
· 13898 MaskedEdit Extender with custom date type mask gives javascript error
· 14692 MaskedEdit error in “yy/MM/dd” format.
· 16186 MaskedEditExtender does not handle century properly in a date mask
· 26456 MaskedEditBehavior. ConvFmtTime : function(input,loadFirst) fails if this._CultureAMPMPlaceholder == “”
· 21474 Error on MaskedEditExtender working with number format
· 23023 MaskedEditExtender’s ClearMaskOnLostFocus property causes problems for MaskedEditValidator when set to false
· 13656 MaskedEditValidator Min/Max Date value issue
Conclusion
This latest release of the Ajax Control Toolkit required many hours of work by a team of talented developers. I want to thank the members of the Superexpert team for the long hours which they put into this release.