Ajax Control Toolkit May 2012 Release

I’m happy to announce the May 2012 release of the Ajax Control Toolkit. This newest release of the Ajax Control Toolkit includes a new file upload control which displays file upload progress. We’ve also added several significant enhancements to the existing HtmlEditorExtender control such as support for uploading images and Source View.

You can download and start using the newest version of the Ajax Control Toolkit by entering the following command in the Library Package Manager console in Visual Studio:

Install-Package AjaxControlToolkit

Alternatively, you can download the latest version of the Ajax Control Toolkit from CodePlex:

http://AjaxControlToolkit.CodePlex.com

The New Ajax File Upload Control

The most requested new feature for the Ajax Control Toolkit (according to the CodePlex Issue Tracker) has been support for file upload with progress. We worked hard over the last few months to create an entirely new file upload control which displays upload progress.

clip_image002

Here is a sample which illustrates how you can use the new AjaxFileUpload control:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="01_FileUpload.aspx.cs" Inherits="WebApplication1._01_FileUpload" %>
<html>
<head runat="server">
    <title>Simple File Upload</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <ajaxToolkit:ToolkitScriptManager runat="server" />

    <ajaxToolkit:AjaxFileUpload
        id="ajaxUpload1"
        OnUploadComplete="ajaxUpload1_OnUploadComplete"
        runat="server"  />


    </div>
    </form>
</body>
</html>

The page above includes a ToolkitScriptManager control. This control is required to use any of the controls in the Ajax Control Toolkit because this control is responsible for loading all of the scripts required by a control.

The page also contains an AjaxFileUpload control. The UploadComplete event is handled in the code-behind for the page:

namespace WebApplication1
{
    public partial class _01_FileUpload : System.Web.UI.Page
    {
        protected void ajaxUpload1_OnUploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
        {
            // Generate file path
            string filePath = "~/Images/" + e.FileName;

            // Save upload file to the file system
            ajaxUpload1.SaveAs(MapPath(filePath));
        }
    }
}

The UploadComplete handler saves each uploaded file by calling the AjaxFileUpload control’s SaveAs() method with a full file path.

Here’s a video which illustrates the process of uploading a file:

clip_image003

Warning: in order to write to the Images folder on a production IIS server, you need Write permissions on the Images folder. You need to provide permissions for the IIS Application Pool account to write to the Images folder. To learn more, see:

http://learn.iis.net/page.aspx/624/application-pool-identities/

Showing File Upload Progress

The new AjaxFileUpload control takes advantage of HTML5 upload progress events (described in the XMLHttpRequest Level 2 standard). This standard is supported by Firefox 8+, Chrome 16+, Safari 5+, and Internet Explorer 10+. In other words, the standard is supported by the most recent versions of all browsers except for Internet Explorer which will support the standard with the release of Internet Explorer 10.

The AjaxFileUpload control works with all browsers, even browsers which do not support the new XMLHttpRequest Level 2 standard. If you use the AjaxFileUpload control with a downlevel browser – such as Internet Explorer 9 — then you get a simple throbber image during a file upload instead of a progress indicator.

Here’s how you specify a throbber image when declaring the AjaxFileUpload control:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="02_FileUpload.aspx.cs" Inherits="WebApplication1._02_FileUpload" %>
<html>
<head id="Head1" runat="server">
    <title>File Upload with Throbber</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <ajaxToolkit:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />

    <ajaxToolkit:AjaxFileUpload
        id="ajaxUpload1"
        OnUploadComplete="ajaxUpload1_OnUploadComplete"
        ThrobberID="MyThrobber"
        runat="server"  />


        <asp:Image
            id="MyThrobber"
            ImageUrl="ajax-loader.gif"
            Style="display:None"
            runat="server" />

    </div>
    </form>
</body>
</html>

Notice that the page above includes an image with the Id MyThrobber. This image is displayed while files are being uploaded.

I use the website http://AjaxLoad.info to generate animated busy wait images.

Drag-And-Drop File Upload

If you are using an uplevel browser then you can drag-and-drop the files which you want to upload onto the AjaxFileUpload control. The following video illustrates how drag-and-drop works:

clip_image004

Remember that drag-and-drop will not work on Internet Explorer 9 or older.

Accepting Multiple Files

By default, the AjaxFileUpload control enables you to upload multiple files at a time. When you open the file dialog, use the CTRL or SHIFT key to select multiple files.

clip_image005

If you want to restrict the number of files that can be uploaded then use the MaximumNumberOfFiles property like this:

<ajaxToolkit:AjaxFileUpload
    id="ajaxUpload1"
    OnUploadComplete="ajaxUpload1_OnUploadComplete"
    ThrobberID="throbber"
    MaximumNumberOfFiles="1"
    runat="server"  />

In the code above, the maximum number of files which can be uploaded is restricted to a single file.

Restricting Uploaded File Types

You might want to allow only certain types of files to be uploaded. For example, you might want to accept only image uploads. In that case, you can use the AllowedFileTypes property to provide a list of allowed file types like this:

<ajaxToolkit:AjaxFileUpload
    id="ajaxUpload1"
    OnUploadComplete="ajaxUpload1_OnUploadComplete"
    ThrobberID="throbber"
    AllowedFileTypes="jpg,jpeg,gif,png"
    runat="server"  />

The code above prevents any files except jpeg, gif, and png files from being uploaded.

Enhancements to the HTMLEditorExtender

Over the past months, we spent a considerable amount of time making bug fixes and feature enhancements to the existing HtmlEditorExtender control. I want to focus on two of the most significant enhancements that we made to the control: support for Source View and support for uploading images.

Adding Source View Support to the HtmlEditorExtender

When you click the Source View tag, the HtmlEditorExtender changes modes and displays the HTML source of the contents contained in the TextBox being extended. You can use Source View to make fine-grain changes to HTML before submitting the HTML to the server.

For reasons of backwards compatibility, the Source View tab is disabled by default. To enable Source View, you need to declare your HtmlEditorExtender with the DisplaySourceTab property like this:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="05_SourceView.aspx.cs" Inherits="WebApplication1._05_SourceView" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head id="Head1" runat="server">
    <title>HtmlEditorExtender with Source View</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <ajaxToolkit:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />

    <asp:TextBox
        id="txtComments"
        TextMode="MultiLine"
        Columns="60"
        Rows="10"
        Runat="server" />

    <ajaxToolkit:HtmlEditorExtender
        id="HEE1"
        TargetControlID="txtComments"
        DisplaySourceTab="true"
        runat="server"  />

    </div>
    </form>
</body>
</html>

The page above includes a ToolkitScriptManager, TextBox, and HtmlEditorExtender control. The HtmlEditorExtender extends the TextBox so that it supports rich text editing.

Notice that the HtmlEditorExtender includes a DisplaySourceTab property. This property causes a button to appear at the bottom of the HtmlEditorExtender which enables you to switch to Source View:

clip_image006

Note: when using the HtmlEditorExtender, we recommend that you set the DOCTYPE for the document. Otherwise, you can encounter weird formatting issues.

Accepting Image Uploads

We also enhanced the HtmlEditorExtender to support image uploads (another very highly requested feature at CodePlex). The following video illustrates the experience of adding an image to the editor:

clip_image007

Once again, for backwards compatibility reasons, support for image uploads is disabled by default. Here’s how you can declare the HtmlEditorExtender so that it supports image uploads:

<ajaxToolkit:HtmlEditorExtender
    id="MyHtmlEditorExtender"
    TargetControlID="txtComments"
    OnImageUploadComplete="MyHtmlEditorExtender_ImageUploadComplete"
    DisplaySourceTab="true"
    runat="server" >
    <Toolbar>
        <ajaxToolkit:Bold />
        <ajaxToolkit:Italic />
        <ajaxToolkit:Underline />
        <ajaxToolkit:InsertImage />
    </Toolbar>
</ajaxToolkit:HtmlEditorExtender>

There are two things that you should notice about the code above. First, notice that an InsertImage toolbar button is added to the HtmlEditorExtender toolbar. This HtmlEditorExtender will render toolbar buttons for bold, italic, underline, and insert image.

Second, notice that the HtmlEditorExtender includes an event handler for the ImageUploadComplete event. The code for this event handler is below:

using System.Web.UI;
using AjaxControlToolkit;

namespace WebApplication1
{
    public partial class _06_ImageUpload : System.Web.UI.Page
    {

        protected void MyHtmlEditorExtender_ImageUploadComplete(object sender, AjaxFileUploadEventArgs e)
        {
            // Generate file path
            string filePath = "~/Images/" + e.FileName;

            // Save uploaded file to the file system
            var ajaxFileUpload = (AjaxFileUpload)sender;
            ajaxFileUpload.SaveAs(MapPath(filePath));

            // Update client with saved image path
            e.PostedUrl = Page.ResolveUrl(filePath);
        }
    }
}

Within the ImageUploadComplete event handler, you need to do two things:

1) Save the uploaded image (for example, to the file system, a database, or Azure storage)

2) Provide the URL to the saved image so the image can be displayed within the HtmlEditorExtender

In the code above, the uploaded image is saved to the ~/Images folder. The path of the saved image is returned to the client by setting the AjaxFileUploadEventArgs PostedUrl property.

Not surprisingly, under the covers, the HtmlEditorExtender uses the AjaxFileUpload. You can get a direct reference to the AjaxFileUpload control used by an HtmlEditorExtender by using the following code:

void Page_Load()
{
    var ajaxFileUpload = MyHtmlEditorExtender.AjaxFileUpload;
    ajaxFileUpload.AllowedFileTypes = "jpg,jpeg";
}

The code above illustrates how you can restrict the types of images that can be uploaded to the HtmlEditorExtender. This code prevents anything but jpeg images from being uploaded.

Summary

This was the most difficult release of the Ajax Control Toolkit to date. We iterated through several designs for the AjaxFileUpload control – with each iteration, the goal was to make the AjaxFileUpload control easier for developers to use. My hope is that we were able to create a control which Web Forms developers will find very intuitive.

I want to thank the developers on the Superexpert.com team for their hard work on this release.

Discussion

  1. Wendi Dyer says:

    I sure hope this works like demonstrated. If so, the ajaxfileuploader will save my project, since the form has need of five(5) muliple fileuploaders. I did not want to limit my users to just one file per asyncfileupload browse click. However, the 3-4 mouse clicks per file to upload more that one was too tedious for most users. I have just downloaded and installed the 5/2012 stable version 4.1.5116.0 but cannot find what you are describing as “AjaxFileUpload” when reloading the Ajax Control Toolkit.

  2. Stilgar says:

    The best release of Ajax Control Toolkit in years!

    Can you give more details on how the uploader control communicates with the server. It seems like the file is posted to te page’s URL and the whole page lifecycle will run. Is there support for providing a handler to accept the file or any other options regarding communication with the server.

    • @Stilgar, That’s correct — the AjaxFileUpload control does not use a handler, it posts back to the same page. We wanted to make it super easy for Web Forms developers to use the control. In order to handle the posted file, you simply write a handler for the Ajax File Upload UploadComplete event.

      We did add a property named AjaxFileUpload.IsInFileUploadPostback so that you could avoid running code when a page is created in response to processing a file postback. Otherwise, like the UpdatePanel, the AjaxFileUpload executes the entire page lifecycle when you post a file.

  3. Wendi Dyer says:

    Okay, AjaxControlToolkit.4.1.60501 Has been loaded and reloaded.
    Still no “ajaxfileUpload” control shows up in the toolbox before or after choosing items. The only item with “fileupload” is the asyncfileupload control. Is there another newer version?

    • @Wendi — The 4.1.60501 version of the correct version (6th year, May 01). Are you sure that you updated the reference to the Ajax Control Toolkit assembly in your Visual Studio project? I just tested on my machine (using both the 3.5/4.0 versions of the Ajax Control Toolkit) and the new AjaxFileUpload control is appearing correctly in my toolbox (with a little icon of a gear).

      You might want to try opening the bin folder for your project, delete the AjaxControlToolkit.dll assembly, and then add the reference to the AjaxControlToolkit.dll again.

  4. Alex says:

    Great work Stephen. Really like the new FileUpload control. Something I noticed, and I may be overlooking a configuration, is that if I do a Server.Transfer form another page to the page that contains the AjaxFileUpload control, it doesn’t work. If I make the page containing the FileUpload control the start page, it works beautifully. I suspect it has something to do with the URL not changing in the Transfer. Is there a way to compensate for that? Thanks for all your efforts.

  5. Wendi Dyer says:

    Hi Stephen, finally I was able to gt the proper version of the ajax toolkit to load all of the controls.
    Does this version have a particular version of the .net framework , or browser version or anything like that to display and run properly. I made a test project copied your code translated into VB.

    One project displays a double asyncfileupload control, the other only display the the select part of the ajaxfileupload as screen shot on your blog. (i.e. the drag an drop part). The crtl/shift key does not select multiple files; such that I can creat the filelist of three files as long as I click the select file button, as pending, the click the upload and it seems to work.

    Thank you for your response. I have been trying to find/create a workable solution to the multiple file upload for several months now. I am very excited about this new control. I believe I need to play with it a little more, and maybe I can get it to do what I want it to.

    • @Wendi — Glad you got it to work. Yes, unfortunately, the design time experience for the Ajax File Upload needs to be improved — right now, the AjaxFileUpload looks like two file uploads widgets. But, this less than ideal design time experience should have no effect on its runtime functionality.

      You can only select multiple files using CTRL/SHIFT on browsers that support multiple file uploads — right now, that means every browser except IE9. The IE10 browser will support multiple file uploads.

  6. Ben says:

    Hi Stephen, thank you for this awesome piece of work !

    When will the sources be available on codeplex?

    By the way, http://AjaxLoad.com is not available anymore, the new URL is http://AjaxLoad.info

    • @Ben — We are working to get all of the source code updated on the CodePlex site by tomorrow. Thanks for the correction on the AjaxLoad.info URL (corrected inline)

  7. Matt says:

    Stephen,

    Thank you for this information.

    Do you have any advice on how best to style the AjaxFileUpload control in the browser?

    For example, the default styling uses a mixture of HTML markup, inline styles and a CSS stylesheet loaded via a WebResource.axd. I cannot see a way to: (a) disable the inline styles; (b) configure the fixed markup; (c) disable the CSS stylesheet.

    It would seem the only option I have is to try and override the default styles through a custom CSS stylesheet. This is difficult, because the default stylesheet loaded from the WebResource.axd is dynamically appended to the bottom of the HTML head element.

    Any help would be appreciated.

    Thanks,
    Matt

    • @Matt — Yes, I agree, styling the AjaxFileUpload control could be made easier. Right now, you need to use CSS styles and override its default appearance. Can you please submit a bug for this at http://ajaxcontroltoolkit.codeplex.com/workitem/list/basic

      It would be great if you could include some recommendations for how you would like to be able to modify the appearance of the control. For example, if you could suggest some style properties to add to the control.

  8. Brian says:

    Is there a change history so we know what bugs have been fixed in other controls since the last release?

  9. Wendi Dyer says:

    Thanks for the Browser info. I guess I will have to wait to use this Cool and badly needed control.
    Our Department is currently stuck at IE8 due to other 3rd party apps (for example SAP’s GUI).

    P.S. Trying to use the cascadingdropdown control and found out I could not use it at this time either due to the Integer parameter requirement. Oh well back to the drawing board. Thanks.

  10. Kevin says:

    I’m getting the following error at runtime after following your first couple steps:

    “The Controls collection cannot be modified because the control contains code blocks”

    AjaxControlToolkit.ScriptObjectBuilder.RegisterCssReferences(Control control) in C:UsersStephenDocumentsReposSuperexpertAjaxControlToolkitServerAjaxControlToolkitExtenderBaseScriptObjectBuilder.cs:328

    And by the way, my username is not Stephen, so I don’t even know where that’s caming from.

    • Kevin says:

      I should note that I’m using ASP.Net 4.0, and have implemented Routing. Could routing be causing this issue? I see on the CodePlex site that someone has mentioned it’s not working on a page reached by Server.Transfer.

    • Kevin says:

      I just tried it without routing, and I still have the same issue…

  11. Hai says:

    Stephen,

    Great stuff! I just upgraded from the asp.net file upload control to use this ajaxified version. The only issue that I’m having is I’m trying to capture input from a text box upon the UploadComplete event and my text box value always shows up as empty even though it has a value in it. This worked before the conversion and I’ve tried every trick I could think of to get this to work. The only time I can get a value is when I force the page to postback. I’m using an aspx with update panel (with master page) which has an embedded user control in it and I’ve even tried to remove the update panel. The reason I’m trying to capture this input is I want the user to be able to enter a name for the image to be saved to my database instead of a file server. Any help would be appreciated. VS2010, .net Framwork 4.0 C#

  12. RvdH says:

    Is it just me or is the new AjaxFileUpload control far from finished? (read: buggy)
    - The MaximumNumberOfFiles property is ignored on both Firefox en Chrome
    - Uploading does not work on IE versions < IE10 (tested with IE9)

  13. Phil says:

    Stephen, great to have an update to the HtmlEditorExtender. Will it now handle paste from MS Word?

    Thanks again

  14. Frank says:

    How do I refresh a GridView/ListView that list all files upon completion of all (or each) file uploads.

    Uploading files and displayding success/fail works perfectly.

    I tried to bind the GridView.DataBind() in OnUploadComplete event and also add asp:AsyncPostBackTrigger with UploadComplete of the AjaxFileUpload event to the GridView, no luck on either one.

    Maybe there is an event that I can use with AjaxFileUpload.IsInFileUploadPostback, so at the end of all uploads, IsInFileUploadPostback will be false and I can do GridView.DataBind() there.

  15. Alo says:

    MaximumNumberOfFiles is ignored in Firefox and Chrome.