ExtJS and ASP.Net Part 5- Asynchronous File Upload

When talking about file upload, we know that we have asp.net fileupload control, the file upload is done through a post back, this does not quite fit into our ajax web applications in terms of following deficiencies:
1.It is an asp.net server control, very hard to style
2.It is done through post back, if we want it done in ‘ajax’ way?
3.If we want to upload several files at the same time?
4.If we want to provide a progress bar to indicate the progress?

You would have thought it should be simple to do file upload in ajax way on the bases that ajax is everywhere nowadays, and most of javascript frameworks have simplified ajax interfaces to send and receive.

Here is surprise one: you can not upload file through ajax itself, as underneath of ajax is XMLHttpRequest which in essence is a javascript object, you can not access file through javascript as it is not allowed for security reasons.

Saying that does not mean we can not do file upload in ajax style which is asynchronous. I had used a jquery based upload widget called ajaxupload with success, compared with jquery ajaxupload ExtJS one is simpler.

Basically the theory behind those widgets is same, to create controls on fly like a hidden iframe, form with upload as the method, and trigger the form submit through code.

On the server end, here comes the second surprise, we would have thought that we can use wcf to serve file download and file upload requests, and there are some examples on the internet talking about wcf in file streaming… and it turns out to be not necessary, a standard aspx page will do the tricks. I understand that wcf streaming is useful when it is hosted in other environment like an exe or a windows service, and also the client could be anything but a web page. In that perspective wcf streaming might be the only option, but here we only care about web application, server is always a web server.

The examples of ExtJs file upload were very often given in php, and I saw one talking about asp.net MVC, here I would like to give an example in traditional aspx page, it is not an easy journey, I will let you know all the possible traps you might encounter along the way.

1.The Ext component I am using is Ext.ux.form.FileUploadField

It is in ux namespace, so it is not in the ext-all.js, you have to download it sepatately together with its css: fileuploadfield.css

       Ext.onReady(function () {
            // upload example     
            var fp = new Ext.form.FormPanel({
                renderTo: 'div1',
                fileUpload: true,
                width: 500,
                frame: true,
                title: 'File Upload Form',
                autoHeight: true,
                bodyStyle: 'padding: 10px 10px 0 10px;',
                labelWidth: 50,
                items: [
                {
                    xtype: 'fileuploadfield',
                    id: 'form-file',
                    emptyText: 'Select a file',
                    fieldLabel: 'file',
                    name: 'uploadfile'

                }
                ],
                buttons: [
                { text: 'Upload',
                    handler: function () {
                        if (fp.getForm().isValid()) {
                            fp.getForm().submit({
                                url: 'Upload.aspx',
                                // waitMsg: 'Uploading your file...',

                                // or using a progress bar 
                                success: function (form, action) {

                                    alert("OK:" + action.result.message);

                                },
                                failure: function (form, action) {
                                    alert("Error:" + action.result.message);
                                }

                            });
                        }
                    }
                }
                ]


            });

 });
fileupload

fileupload

From the example given from Ext website, we have three uses, one is called basic which is just the control: a text box and button, another is a button only, the third one is FileUploadFiled in formpanel, I would say the first two examples are very misleading, the controls are rendered in the page, ’browse’ button can populate the selected file to the text box, but that is all, I confirmed this through a look of source code as well, there is no way to hookup or to write an event that is going to send file to server, at least I do not know. Only the third example is meaningful and viable, the reason is apart from getting the file name, wrapping it into a hidden frame and post to server etc all these hard work is done actually by Ext.form.FormPanel.

2. Some points about the above :

2.1.fileUpload must be set to true, in this way it tells Extjs it is uploading file, please create hidden frame and form etc .. for me.

2.2.Please be alerted a form is going to be created even though it is hidden. As we have talked in part 3, aspx page, especially master page they have already had a ‘form’ and they must have it for post back mechanism to work, I guess(pure speculation) in asp.net MVC web pages are essentially html file, like templates in php, they can do their duties with or without ‘form’. Fortunately you can have multiple forms in one page, the taboo is just do not embed form in form, you will get html file run time error, you can get away from this by rendering EXT control outside aspx server form tag.

2.3. Items has one fileupload control

2.4. Within the button handler, to initiated uploading, and url is a simple aspx, not a svc

2.5. As an alternative to waiting message, you can implement a progress bar to indicate the file upload progress using my generic Extjs progress bar

3.Markup Upload.aspx:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
 <asp:Literal ID="Literal1" runat="server"></asp:Literal>
</body>
</html>

and Upload.aspx.cs

public partial class Upload : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
         
        HttpContext context = HttpContext.Current;

     
        if (context.Request.Files.Count > 0)
        {

            StreamReader file = new StreamReader(context.Request.Files[0].InputStream);

            string line;
            while ((line = file.ReadLine()) != null)
            { 

                // process the line or save it to local on server

                // some code to update the progress as well
            }

        }

        // prepare response
        MessageOb result = new MessageOb();

        result.success = true;

        result.message = "message brah....";

        Literal1.Text = JSONHelper.Serialize<MessageOb>(result);
       

    }
}


public class MessageOb
{
    public bool success { get; set; }
    public string message { get; set; }

}


public class JSONHelper
{
    public static string Serialize<T>(T obj)
    {
        System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
        MemoryStream ms = new MemoryStream();
        serializer.WriteObject(ms, obj);
        string retVal = Encoding.UTF8.GetString(ms.ToArray());
        return retVal;
    }

    public static T Deserialize<T>(string json)
    {
        T obj = Activator.CreateInstance<T>();
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
        System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
        obj = (T)serializer.ReadObject(ms);
        ms.Close();
        return obj;
    }
}

It is standard c# stuff, checking upload file from Request.Files collection. The tricky part is how to send response, due to certain expectation of ExtJs upload form, we have to author the response in their way.

3.1.Do not have any other mark-ups in the upload page, as it is not necessary, this page does not have any visual representation, in this sense it is just like a web service. The message actually needs to be embedded in the body of html as a JSON string.

3.2.So to satisfy above requirement, first to use a literal to render the JSON string,

3.3.Second to serialize our response object in JSON through my JSONHelper.

3.4.The server response object retrievable in client callback: action.result.

Tags:

This entry was posted on Wednesday, August 11th, 2010 at 11:49 pm and is filed under ASP.NET, Javascript. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

17 Responses to “ExtJS and ASP.Net Part 5- Asynchronous File Upload”

  1. evony like says:

    Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I’ll be subscribing to your feed and I hope you post again soon.

  2. Thank you for your insightful comments. I hope to visit your website soon.

  3. Mark Gresham says:

    Gracias por la punta!

    Voy a añadir su blog a mi lista!

  4. I got to this article through Facebook (a friend of mine posted it). After reading, I then clicked “Like” and also shared it myseld.

  5. Hi!
    Thank you for giving some very useful info on the topic.

    I am saving your website and for sure definitely check back often.

  6. ExtJS and ASP.Net Part 5- Asynchronous File Upload…

    When talking about file upload, we know that we have asp.net fileupload control, the file upload is done through a post back, this does not quite fit into our ajax web applications in terms of following deficiencies: 1.It is an asp.net server control, …

  7. Rags says:

    Hi ,i did tried above code but for some reason the file uploaded are corrupted. I uploaded excel file and the data inside file were all corrupted. Not sure which part is not correct.

    Anyways thanks for insight.

    • CleanCodeNZ says:

      Hi Rags:

      In my example I used StreamReader which is a text reader, you might want to try BinaryReader to handle none-text data.

  8. DucK says:

    Thanks for this simple example ! I have one “stupid” question, how can i know if the file was successfully uploaded ? also do i have to declare Literal1 as a Literal ? beacause it doesn’t recoginze it !

    • CleanCodeNZ says:

      In page_load method, you will process file steam, if there is any problem about file stream, you will know if file was uploaded successfully.
      Do not know what you mean by not being recognized, have an inspection of action.result. there are a lot going on over there to pass messages back from server to client control.

      • DucK says:

        Here is the error that I get now: “Uncaught Ext.JSON.decode(): You’re trying to decode an invalid JSON String: “

        • CleanCodeNZ says:

          Hi Duck:
          It looks to me the string Ext is trying to decode is not valid JSON. Returning of message in the blog was meant for FileUpload ext control at the time(3.x) so there might be a change in Ext4.

  9. DucK says:

    Thanks for the answer, I think that the problem is that I didn’t add (using System.Runtime.Serialization.Json) reference, i fugured this out when i put your code in a new solution (not by integrating it directly to my current project like I did in the first time), but the problem is that it doesn’t recognize Json ( .NET 4.5, ExtJS 4.1).

  10. Denisa says:

    how can i pass parameters when i submit the form?

    • CleanCodeNZ says:

      Hi:
      You will have to look into FormPanel to find out how to embed other form controls, not just a file select. On server side I think it should be same you can try to retrieve post back parameters from HttpContext.Form[…]. This is just theory you need to check out as it might not be possible for you post back form fields when it is a file post back. As for for file post back the content-type header is different.

Leave a Reply

*