Large file upload using Silverlight, ASP.Net and WCF, Part 1

February 14, 2009 16:53 by Rob

In this article I would like to show you how I created a reusable ASP.Net component to handle large uploads using Silverlight 2.

The solution contains of 3 components:

  • A Silverlight control that allows the user to browse for files (this page)
  • A WCF service that receives the file data
  • An ASP.Net control that raises an event when the file has been uploaded.

I will discuss them one at a time. The code blocks are screenshots, but don’t worry because I attached the file below.

Edit: After posting this, somebody pointed out that Tim Heuer has a surprisingly similar screencast called Silverlight 2: OpenFileDialog and File Upload. The big difference is that Tim doesn’t support very large uploads.

The Silverlight Control

Using Visual Studio 2008, create a new Silverlight application,delete the standard Page, and add a control named ‘UploadControl’.

image

The control will look like this.

image

This control contains 2 buttons, a progress bar and a display message. The buttons are on top of each other and so are the progress bar and the message.

The magic of this control is in its code behind though. When the upload button is clicked i show a file selection dialog. After a file is selected, some housekeeping is done and a new instance of an UploadState class is initialized.

image

You will notice that 3 events are wired up:

  • One event is raised when the upload is completed
  • Another event is raised each time a block of data is transferred
  • And finally one event may be raised when the user has clicked the cancel button.

The rest of the event handling in this class is rather trivial. The UploadState class is where all the magic happens.

After creation and initialization of the UploadState instance I will start the upload:

image

This section of code needs some explanation, but before I do that, I need to tell you how to achieve large uploads.

Large Upload Intermezzo

IIS, Web services and pages don’t like large requests. Requests tend to time out and no progress can be shown. There have been lots and lots of solutions using ISAPI handlers, background processes and other weird solutions that all have their pros and cons.On Asp.Net forums there is actually a thread about large uploads which at time of writing consists of a massive 182 posts.

The approach presented here may not be unique, but I think it is a great alternative. The steps for large uploads in this solution are as follows:

  • The client requests an upload token from the server. I like Guid’s, to a Guid it is.
  • After the client has received the upload token (or handle as I call it), i can begin to send chunks of data to the server, 8kb at a time. Every chunk is a new http request so timeouts aren’t likely to occur.
  • The server will collect the chunks.The token is sent with the data chunk to the server knows what file the data belongs to.Since the chunks are numbered it can reassemble the entire file.
  • After the last chunk is sent, the client informs that all chunks have been sent.
  • The server receives the completion signal and will assemble all the chunks back into a single file.The server then sends an ‘All Ok’ back to the client.
  • The client has received word that the file has been stored on the server. The file can now be retrieved using all sorts of methods.

Back to Silverlight…

The Silverlight Control, continued

Here’s the ‘StartUpload’ method again.

image

Of course you know that all WCF communication in Silverlight must be asynchronous. This is what happens here. A WCF client is obtained, and a service call to ‘GetHandle’ is executed. The anonymous delegate is fired when a handle is obtained. After the block number and progress values are initialized, the first block is pushed.

Blocks are pushed using the PushBlock method. This method will read a chunk of data from the client’s file and send it asynchronously to the WCF service:

image

Problem with asynchronous calls is that it is impossible to use a standard while loop to enumerate all the blocks. But we can make another call to ‘PushBlock’ when this block is sent, using the anonymous method: (sender, e) => { PushBlock(); }

After every chunk is sent, the remote server is informed:

image

When the server has acknowledged the Complete method, the Completed event is raised from the UploadState class to the control in this method:

image

Again, more housekeeping. The final bit is at the end, where the FileID property is set and the FileUploaded event is raised. The FileUploaded event is a top-level event written for the client of the upload control. You can use this upload control in another Silverlight control, or you can expose it to the Html object model. In my project, i did it using the following code in  App.Xaml

image

The RegisterScriptableObject essentially exposes the UploadControl instance as an object named ‘uploadControl’ in JavaScript. We’ll come back to that later when I wrap the control into and ASP.Net component.

On the next part, I will dive into the implementation of the WCF service.

That’s it for now, keep tight. I need a break.

Rob.


Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Comments

Praveen

February 23, 2009 07:20

Please implement the wcf service.

Praveen in