April 2013 Release of the Ajax Control Toolkit

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:

clip_image002

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:

clip_image003

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:

clip_image005

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:

clip_image007

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:

clip_image009

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.

Discussion

  1. Ray Kuhnell says:

    Considering the fact that file storage in the cloud is getting so cheap, I’m glad to see that there is a focus on supporting uploads of large files. This will be a welcome addition to our current file manager. I’m excited to start tinkering with the new version. Great job!

  2. WoW its really amazing…! Now we can upload large files with showing upload progress in all browsers support. Its really very helpful and also drag and drop option included for chrome or firefox…! Really superb. Thank you …!

  3. Saadie says:

    Thanks for the update, does AjaxFileUpload raise an event in case when upload is complete when one is uploading multiple files. I know it does when an individual file upload is complete but is there any event for when all the uploads are complete?

  4. Brian Potter says:

    There seems to be a problem with the file upload control. When I try and use it on a site that requires the user to log in (our internal business management site) an error is thrown by the doneAndUploadNextFile function in the javascript (“error raising upload complete event and start new upload”). Looking at the netwotk traffic the response to the POST request is a DirectoryNotFoundException looking for the users AppData\Local\Temp\_AjaxFileUpload folder. The control works fine if I disable the authentication requirement on the site.

    • @Brian – one of the developers on our Superexpert team just tried to reproduce this issue without success. He enabled forms authentication, logged in, and uploaded a file using the AjaxFileUpload control without any issues. If you can create a minimal repro website, and open an issue at http://ajaxcontroltoolkit.codeplex.com/workitem/list/basic then we can investigate it.

      • Paul John van den Aerdenhout says:

        Hi Brian, I got the same problem after updating to the new kit. As Stephen explained erlier, you need to register the AjaxFileUploadHandler.axd handler. After doing so, my problem was solved.

  5. Esben says:

    – IE10 has support for the HTML5 File API. Do you use the HTML5 File API in IE10?
    – What about the label (button) texts can they now be set? (not everyone speaks English)
    – Is there now a way to set a parameter that you can get on the AjaxControlToolkit.AjaxFileUploadEventArgs? If you have a drop down box where the user can choose where to upload the file.

    • @Esben — great questions!

      – we ran into problems with the Desktop version (not the Metro version) of IE10 when using the HTML5 approach. Therefore, we treat IE10 as not fully supporting the HTML5 File API and we use server polling to show progress.

      – All text is contained in resource files. We did not translate into multiple languages, but you can add additional languages by creating the language specific resource files.

      – Yes, you can pass context parameters to the AjaxFileUploadEventArgs — use the AjaxFileUpload ContextKeys dictionary to pass data.

    • Esben says:

      Thanks Stephen! I hope IE(11) File API will be added in a future version 🙂

  6. Michael Teper says:

    Stephen, looking at the upload control, it seems it can only be used for uploading the file, and cannot be used in combination with a form (i.e. set a few controls, select file(s) for upload, submit). Is this true? If so, that’s a very limiting design choice and makes the control far less useful that I was hoping.

    -Michael

    • @Michael – yes, the AjaxFileUpload is async. It would be hard (impossible?) to display progress if we did not make it async. Also, we could not break the file into multiple chunks.

      • Michael Teper says:

        True, but as we discussed on Twitter, you can keep it async and still do a post at the end of upload.

  7. Ming says:

    Thanks you for update AjaxControlToolkit.

    I use this since asp.net 2.0.
    Nowadays, every people talking MVC, and stay away webforms.

    But i think webforms still work great and modern in web application.

  8. David says:

    Is the file upload control supported on web farms?

    • @David – In this release, the AjaxFileUpload is not supported in Web Farms because the uploaded file is written to a temporary file on disk. We are working on Web Farm support in the next release.

  9. Jim says:

    install-package ajaxcontroltoolkit

    oh so simple… and yet here I am 2hrs later still looking at:
    ASP.NET AJAX client-side framework failed to load” error

    if this thing doesn’t work with a ‘web project’, or ’empty web sites’ or whatever you need to tell people – ^#%#$@