Uploading Files from Flex to Your .NET Server

When writing RIAs in Flex, you may find it useful to allow users to upload files to the server. While Flex simplifies this functionality with the FileReference class (a part of the Flash Player), there is not much documentation on how to handle the upload request on the server. This article will show you how to do exactly that if you have a .NET back end, using an ASHX handler file.

First, let’s go over sending the request with the FileReference class. FileReference instances provide the function browse(), which opens an operating system file selection dialog for the user and fires an Event.SELECT event when the user selects a file. Let’s start by letting the user browse files.

private var uploadFile:FileReference = new FileReference();    
 
private function uploadClickHandler():void { 
    uploadFile.addEventListener(Event.SELECT, fileSelectHandler); 
    uploadFile.browse(); 
}

We handle the selection event with a function called fileSelectHandler. To actually upload the file once it is selected, fileSelectHandler will use the upload() function of the FileReference, which takes a URLRequest object pointing to the script to handle the uploaded file. For this example, we’ll have a local script called UploadHandler.ashx handle the file.

private function fileSelectHandler(event:Event):void { 
    uploadFile.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, uploadCompleteHandler); 
    uploadFile.upload(new URLRequest("http://localhost/UploadHandler.ashx")); 
}

The FileReference fires the event DataEvent.UPLOAD_COMPLETE_DATA when the upload is complete. You can set a listener for this to receive the server’s response when the handler script finishes executing. The data property of the corresponding DataEvent contains the response in the form of a string.

private function uploadCompleteHandler(event:DataEvent):void { 
    responseText.text = event.data; 
}

Now that the request has been sent, the server has to grab the file and save it. We can do this using an ASHX handler, which is similar to an ASPX page without the corresponding HTML form and overhead of the Page class. To implement the handler, you must write a class that implements the IHttpHandler interface. This interface requires implementing the function ProcessRequest and a getter for the property IsReusable. We set IsReusable to true since we don’t use any instance variables and our implementation is safe for multiple requests, both concurrently and sequentially.

ProcessRequest is a function that is passed an HttpContext and is where we will handle the upload request. The context that is passed in has a Request field which contains data about the incoming HTTP request, including the Files field which contains any files passed in the request. Files is a collection of HttpPostedFile objects which we will use to retrieve the file posted by our FileReference. For this example handler, we will simply make sure that a file has been sent, save all uploaded files locally in a directory we retrieve from Web.config, and return a status message as our response.

Update: Enumerating through context.Request.Files returns the string keys of the files in the collection, not the HttpPostedFile objects themselves. The example has been updated with the correct method for looping through the files uploaded.

public void ProcessRequest (HttpContext context) { 
    if (context.Request.Files.Count == 0) 
    { 
        context.Response.Write("Error: No files sent for upload"); 
        return; 
    }    
 
    string dir = WebConfigurationManager.AppSettings["UploadDirectory"];    
 
    foreach(string fileKey in context.Request.Files)
    {
        HttpPostedFile file = context.Request.Files[fileKey];
        file.SaveAs(Path.Combine(dir, file.FileName));
    }
 
    context.Response.Write("Uploaded "); 
    context.Response.Write(context.Request.Files.Count); 
    context.Response.Write(" file" + (context.Request.Files.Count == 1 ? "" : "s") + "."); 
}

You can write the server response by using the functions of context.Response. This response will automatically be returned once the handler finishes processing. In this example, we will simply return a string indicating how many files were uploaded.

As you can see, uploading files in Flex and handling them in .NET is actually quite simple. With some extra code in ProcessRequest, it is easy to create handlers that can rename and place uploaded files, as well as ensure authentication and perform any other necessary server-side business logic.

Here are the complete code examples used in this post, or you can download them here.

– Upload.mxml:

 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">    
 
    <mx:Script> 
    <!--[CDATA[     
 
        private var uploadFile:FileReference = new FileReference();     
 
        private function uploadClickHandler():void { 
            uploadFile.addEventListener(Event.SELECT, fileSelectHandler); 
            uploadFile.browse(); 
        }     
 
        private function fileSelectHandler(event:Event):void { 
            uploadFile.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, uploadCompleteHandler); 
            uploadFile.upload(new URLRequest("http://localhost/UploadHandler.ashx")); 
        }     
 
        private function uploadCompleteHandler(event:DataEvent):void { 
            responseText.text = event.data; 
        }     
 
    ]]--> 
    </mx:Script>
 
    <mx:Panel x="10" y="10" width="250" height="200" layout="absolute"> 
            <mx:Button label="Upload" click="uploadClickHandler()" x="82" y="128" /> 
            <mx:TextArea x="10" y="10" width="210" height="110" id="responseText" />
    </mx:Panel>
</mx:Application>

– UploadHandler.ashx:

<!--WebHandler Language="C#" Class="UploadHandler"-->  
 
using System.Web; 
using System.IO;  
 
public class UploadHandler : IHttpHandler { 
    public void ProcessRequest (HttpContext context) { 
        if (context.Request.Files.Count == 0) 
        { 
            context.Response.Write("Error: No files sent for upload"); 
            return; 
        }  
 
        string dir = WebConfigurationManager.AppSettings["UploadDirectory"];    
 
        foreach(string fileKey in context.Request.Files)
        {
            HttpPostedFile file = context.Request.Files[fileKey];
            file.SaveAs(Path.Combine(dir, file.FileName));
        }  
 
        context.Response.Write("Uploaded "); 
        context.Response.Write(context.Request.Files.Count); 
        context.Response.Write(" file" + (context.Request.Files.Count == 1 ? "" : "s") + "."); 
    }  
 
    public bool IsReusable { 
        get { 
            return true; 
        } 
    } 
}

13 Responses to “Uploading Files from Flex to Your .NET Server”

  1. Faisal Abid Says:

    Thanks for that. :D keep up the good work

  2. Mike Chambers » Blog Archive » Handling Flash File Uploads with .NET Says:

    […] Sosnovtsev has posted a really useful blog post over on the atellis labs site. The post shows how to upload files from Flash to a .NET backend. The example includes both ActionScript and .NET / C# code […]

  3. Nate Says:

    Awesome!! I haven’t found a really good flex/.NET website. I hope you keep up the good bloggin and solve my problem!

  4. Eric Says:

    nice

  5. Paul Says:

    I’m getting an I/O Error 2038 when i try to use this sample… running the ashx on a localhost iis. what could be wrong?

  6. Denis Sosnovtsev Says:

    You need to make sure you do two things. First of all, this example saves files to a directory specified in the Web.config file. Make sure that in your Web.config, in the section, you put in:

    Once you have that, you need to make sure that your machine’s ASP.NET account has write access to the folder which you’re trying to save to. To do this, find the folder that you specified, right click it and go to “Properties”. Under the “Security” tab, hit “Add…” and in the text area write “NameOfYourComputer\ASPNET” where, obviously, NameOfYourComputer is actually the name of your computer. Once you add the ASP.NET machine user, select it in the list of user names in the “Security” tab, and make sure that you allow it Write permissions for this folder.

    Try that and if you still have problems, post again!

  7. Denis Sosnovtsev Says:

    Hmm, comments don’t like XML tags. Ok, for the first part, make sure you put:

    add key=”UploadDirectory” value=”The directory you want to save to.” /

    in the appSettings section of you Web.config.

  8. Michael Says:

    Thanks for this. This is the only example I could find of doing this with Flex + .NET.

    Like another poster, I too am experiencing Error 2038.

    I have created a directory c:\uploadpath and in the C# file done the following:
    string dir = “c:\uploadpath”;

    This should bypass the need for the WebConfigurationManager (which doesn’t work for me; I’m using the Express version, perhaps that’s why that class is unavailable).

    I have removed as much security as I know how from the uploadpath directory - I have added the user “Everyone” in the security tab, gave them full control, and ensured that the directory was not read-only.

    I have installed the C# handler, and can invoke it directly with the URL http://localhost/UploadHandler.ashx. uploader is a application directory. I get “Error: No files sent for upload” as expected when this invoked from the browser.

    However, when I invoke this from your sample Flex application, I still get the 2038 error. I have also attempted to use this with a subdir in the wwwroot directory (again, permissions on the floor) to no avail.

    I am not sure if this is helpful, but when running under debug, the trace is:
    Error #2044: Unhandled IOErrorEvent:. text=Error #2038: File I/O Error.
    at Upload$iinit()[C:\Documents and Settings\Michael\My Documents\Flex Builder 2\Demo\Upload.mxml:7]
    at _Upload_mx_managers_SystemManager/create()
    at mx.managers::SystemManager/mx.managers:SystemManager::initializeTopLevelWindow()[C:\dev\flex_201_gmc\sdk\frameworks\mx\managers\SystemManager.as:2289]
    at mx.managers::SystemManager/mx.managers:SystemManager::docFrameHandler()[C:\dev\flex_201_gmc\sdk\frameworks\mx\managers\SystemManager.as:2214]

    Any ideas? Thanks again for this wonderful article. I am tantalizingly close.

    P.S. - the zip file you provided seems to have slightly outdated source files, as the symbols don’t match.

  9. Bernie Says:

    This works for me:
    —————–

    using System;
    using System.Web;
    using System.IO;
    using System.Web.Configuration;

    public class UploadHandler : IHttpHandler {

    public void ProcessRequest(HttpContext context)
    {

    if (context.Request.Files.Count == 0)
    {
    context.Response.Write(”Error: No files sent for upload”);
    return;
    }

    string dir = context.Server.MapPath(WebConfigurationManager.AppSettings[”UploadDirectory”]);

    HttpPostedFile file = context.Request.Files[0];
    file.SaveAs(dir + Path.GetFileName(file.FileName));

    context.Response.Write(”Uploaded “);
    context.Response.Write(Path.GetFileName(file.FileName));
    }

    public bool IsReusable
    {
    get
    {
    return true;
    }
    }
    }
    ———————-
    in web.config

  10. Denis Sosnovtsev Says:

    Sorry that I’ve been away for a while, but I’ve figured out the problem everyone’s been having. Since the FileReference class can only send one file at a time, I usually just use context.Request.Files[0] to retrieve the file, but for the sake of the example I put in a foreach loop to enumerate through all uploaded files and save all of them just in case more than one was sent (i.e. if a future Flex/Flash Player class does allow you to send multiple files simultaneously). Unfortunately, I didn’t test it fully and as it turns out, there’s some unexpected behavior.

    context.Request.Files is an HttpFileCollection object, and using it’s indexer you can access the HttpPostedFile objects it contains by index ( Files[index] ) or by key ( Files[keyString] ). However, the HttpFileCollection enumerator returns the keys you can use to access the files rather than the files themselves, which I find to be a pretty unexpected behavior.

    Anyways, I updated the examples with the fix, as well as fixed the symbols in the MXML file (thanks for the heads up, Michael), and this time I guarantee it’ll work. To make the example work either access the first posted file through context.Request.Files[0] or use the new loop I’ve provided in the updated examples.

    Thanks for the comments, sorry for not catching that the first time round, and let me know if the updates work out for you!

  11. Xia Says:

    When I run this example, it worked well for small files. But for larger ones, it kept having IO errors. Is there any file size limit for uploading?

  12. Denis Sosnovtsev Says:

    The problem is that by default, ASP .NET accepts a maximum request size of 4 MB. However, this is easily changed with a setting in your Web.config file.

    In the system.web node of your Web.config file, add an element called httpRuntime with an attribute called maxRequestLength. Set maximumRequestLength to the max size request you wish to accept, in KB. So the default setting is 4096 for 4 MB. Microsoft recommends not setting this higher than ~ 10-20 MB or, if uploads are infrequent ~100 MB.

    That should solve your problem, thanks for the comment!

  13. leung Says:

    It’s there a possibility to pass an parameter through the ASHX file ?
    I already succeed to upload my file to a map , but now i want to upload an file in an different map.
    example : A map that i had choose in a tree.

    can somebody help me , because i already searching a long time for this problem.

Leave a Reply