(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Uploading and downloading images from WCF in Silverlight

(19 votes)
Gill Cleeren
>
Gill Cleeren
Joined Nov 14, 2007
Articles:   1
Comments:   0
More Articles
27 comments   /   posted on Mar 09, 2010
Tags:   wcf , upload , download , gill-cleeren
Categories:   Data Access , Line-of-Business
This article is also available in print (Word, PDF) and e-reader formats (MOBI, EPUB).
Download all formats, including source code for $0.99.  Add to Cart

This article is compatible with the latest version of Silverlight.

Uploading and downloading images using a WCF service with Silverlight

Quite often, when browsing the web, we encounter a situation where we are required to upload a file. When I want to register myself on a forum, I often get the question if I want to upload an avatar. Or when using a social networking site such as Facebook, I can upload pictures of me doing something that probably no one is interested in. The point I’m trying to make here is that when developing in Silverlight, we’ll also come in a situation where we want our users to upload files such as images to the server. Next to uploading, users may want to download files such as images, which are stored as a physical file on the server as well.

In both cases, WCF can help us out, allowing us to create services that are capable of working with an uploaded file as well as processing a requested file for download. In this article, I’ll be showing a sample Silverlight application where users can upload and download images from using a WCF service. The interface is very simple; a screenshot is shown below.

Picture1

Included with this article is the sample code, which can be downloaded here. We’ll be using this code to show how the upload and download process works.

Uploading a file to the server

We’ll start by looking at the upload process. We need to write code both on the server side and on the client side.

Server-side: a WCF servoce

To allow a Silverlight application to send files to the server-side and store these on the file system of the server, we’ll start by creating a WCF service. In the sample code, this service is named PictureService. In the service contract, IPictureService, we define a method called Upload, which accepts an instance of PictureFile.

[ServiceContract]
public interface IPictureService
{
    [OperationContract]
    bool Upload(PictureFile picture);
}

The PictureFile class is defined as DataContract; it defines two fields namely the filename and the contents of the file. The latter is stored as a byte stream. Both these properties are attributed with the DataMemberAttribute, meaning that both will travel over the wire when send from and to the service.

[DataContract]
public class PictureFile
{
    [DataMember]
    public string PictureName { get; set; }
 
    [DataMember]
    public byte[] PictureStream { get; set; }
}

Now that we have defined the contract for the service, let’s take a look at the implementation. The logic here relies on System.IO. Basically, the Silverlight client application will upload a file as a stream of bytes (using an instance of the above defined class PictureFile). This stream of bytes is to be converted to a file on the server. The following code does just that: using a BinaryWriter, we grab the sent bytes and save them as a file. The location of the upload directory is stored here in the web.config.

[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class PictureService : IPictureService
{
    public bool Upload(PictureFile picture)
    {
        FileStream fileStream = null;
        BinaryWriter writer = null;
        string filePath;
 
        try
        {
            filePath = HttpContext.Current.Server.MapPath(".") + 
                       ConfigurationManager.AppSettings["PictureUploadDirectory"] + 
                       picture.PictureName;
 
            if (picture.PictureName != string.Empty)
            {
                fileStream = File.Open(filePath, FileMode.Create);
                writer = new BinaryWriter(fileStream);
                writer.Write(picture.PictureStream);
            }
 
            return true;
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            if (fileStream != null)
                fileStream.Close();
            if (writer != null)
                writer.Close();
        }
    }
}

By default, WCF only accepts messages with a maximum length of 65536 bytes. This is however, not enough for sending normal files to the server. We should therefore make some configuration changes to our service so that the larger uploads are accepted. To do so, I’m specifying a custom binding configuration for the basic HTTP binding. Here, I’m allowing uploads of 2.000.000 bytes, meaning 2MB, you can of course specify another value here.

<bindings>
    <basicHttpBinding>
        <binding name="PictureBinding" maxReceivedMessageSize="2000000" maxBufferSize="2000000">
            <readerQuotas maxArrayLength="2000000" maxStringContentLength="2000000"/>
        </binding>
    </basicHttpBinding>
</bindings>

Because this WCF service is to be connected to from Silverlight, the binding itself should of course be a BasicHttpBinding and not a wsHttpBinding which is the default for WCF.

At this point, our service has all it needs to start accepting uploads from Silverlight. Let’s turn our attention to the client now.

Client side: the Silverlight application

The first thing we should do is letting our Silverlight application know about the PictureService by adding a service reference to the service within the Silverlight project. Here I set the namespace to PictureService.

Picture2

Visual Studio creates for us a proxy. Included in the client proxy is a client side copy of the PictureFile class.

To allow the user of the application to upload a file from the local file system, we use the OpenFileDialog class. Within Silverlight, this class gives us a read-only stream to a local file. Apart from reading the contents of the file, Silverlight can’t perform other actions on the file such as deleting or renaming. Using the OpenRead method, we get access to the above mentioned stream which we can then read out using the Read method into a byte array.

OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "JPEG files|*.jpg";
if (openFileDialog.ShowDialog() == true)
{
    Stream stream = (Stream)openFileDialog.File.OpenRead();
    byte[] bytes = new byte[stream.Length];
    stream.Read(bytes, 0, (int)stream.Length);
 
    string fileName = openFileDialog.File.Name;
}

We’re can now try uploading the file. We therefore create a new instance of the PictureFile class, passing in a name for the file and the byte array.

PictureService.PictureFile pictureFile= new FileUpAndDownload.PictureService.PictureFile();
pictureFile.PictureName = fileName;
pictureFile.PictureStream = bytes;

All that’s left now is creating a proxy instance. As with all other service communication within Silverlight, service communication works asynchronously. Therefore, we define a callback which will be invoked when the upload is finished.

PictureService.PictureServiceClient client = new FileUpAndDownload.PictureService.PictureServiceClient();
client.UploadCompleted += new EventHandler
    <FileUpAndDownload.PictureService.UploadCompletedEventArgs>(client_UploadCompleted);
client.UploadAsync(pictureFile);

In the callback, we can check if the service interaction went OK or if there where any errors.

void client_UploadCompleted(object sender, FileUpAndDownload.PictureService.UploadCompletedEventArgs e)
{
    if (e.Error == null)
    {
        if (e.Result)
        {
            ResultTextBlock.Text = "Upload succeeded :)";
        }
        else
        {
              ResultTextBlock.Text = "Upload failed :(";
        }
    }
}

With that, we are ready to try our upload process. The image below shows the upload working.

Picture3

Let’s now look at how we can download files.

Downloading files from the server

When it comes to downloading images, we could in most cases solve things by simply using a link to the original file and sending this link back to the client Silverlight application. However, in some cases, this link can’t be created. Take for example the case where images are stored within a database. Or another possibility here is that images are stored on a non-publicly available folder on the server. In both these cases, we need to send the byte information to the client using a service again. In the client Silverlight application, we can then recreate the file and use it within our app. Let’s look at the code to do this.

Service changes

For this sample, we’ll allow the user to enter the name of the picture he or she wishes to download, so we’ll pass in a string as argument for a new method, quite logically named Download, on our WCF service. In the service contract, I added the following code:

[OperationContract]
PictureFile Download(string pictureName);

As we can see here, this operation defines that we are sending to the client an instance of the PictureFile class (the same class as we used for the upload process). The file that will thus be sent to the client, will be sent as a byte array. In the implementation code, we check if the file exists first. If it does, we use a BinaryReader to read the contents of the file, create he PictureFile instance and return it.

public PictureFile Download(string pictureName)
{
    FileStream fileStream = null;
    BinaryReader reader = null;
    string imagePath;
    byte[] imageBytes;
 
    try
    {
        imagePath = HttpContext.Current.Server.MapPath(".") +             
        ConfigurationManager.AppSettings["PictureUploadDirectory"] + 
        pictureName + ".jpg";
        
        if (File.Exists(imagePath))
        {
            fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
            reader = new BinaryReader(fileStream);
 
            imageBytes = reader.ReadBytes((int)fileStream.Length);
 
            return new PictureFile() { PictureName = pictureName, PictureStream = imageBytes };
        }
        return null;
    }
    catch (Exception)
    {
        return null;
    }
}

The service’s configuration code does not need to be changed for this new operation.

Changes to the Silverlight client

Within the Silverlight client, update the web service reference. Visual Studio will update the proxy class, making the new Download method available. Upon clicking the button, we’ll launch a request to the service asynchronously, passing in the filename.

private void DownloadButton_Click(object sender, RoutedEventArgs e)
{
    PictureService.PictureServiceClient client = 
        new FileUpAndDownload.PictureService.PictureServiceClient();
    client.DownloadCompleted += 
        new EventHandler<FileUpAndDownload.PictureService.DownloadCompletedEventArgs>(client_DownloadCompleted);
    client.DownloadAsync(FileNameTextBox.Text);
}

Upon completion of the service call, the callback method is invoked. If no errors occur, we receive a PictureFile instance, containing the bytes of the requested file. Here we know that the file is in fact an image, so we use it to display the picture in an Image control.

BitmapImage image = new BitmapImage();
if (e.Error == null)
{
    if (e.Result != null)
    {
        ImageDownloadService.ImageDownload imageDownload = e.Result;
        MemoryStream stream = new MemoryStream(imageDownload.Image);
        image.SetSource(stream);
        ResultImage.Source = image;
    }
    else
    {
        ErrorTextBlock.Text = "No image with that name exists";    
    }
}

Summary

To send files from and to a service from within a Silverlight application, we can use a WCF service, which accepts a byte array, optionally wrapped in a class like we did here with the PictureFile class. In this example, we looked at how to do this with images; however, the method is similar for other file types.

Gill Cleeren is Microsoft Regional Director (www.theregion.com), MVP ASP.NET, INETA speaker bureau member and Silverlight Insider. He lives in Belgium where he works as .NET architect at Ordina. Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and trainings on new as well as existing technologies, such as Silverlight, ASP.NET and WPF. He also leads Visug (www.visug.be), the largest .NET user group in Belgium. He’s the author of the upcoming book called Silverlight 4 Data and Services Cookbook. You can find his blog at www.snowball.be.


Subscribe

Comments

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Sharker on Mar 10, 2010 07:06
    Where can i download the source code, can u email it to me, shamrat231@hotmail.com. By the way is it possible to send the uploaded image as attachment to email in WCF service? thx. Any help appreciated
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Gill Cleeren on Mar 10, 2010 09:09

    The link for the download can be found in the article. For your convenience, here it is: http://www.silverlightshow.net/storage/Uploading%20and%20downloading%20from%20WCF.zip

    If I understand your question correctly, you want to send the uploaded image from WCF by mail? If so, then the answer is yes.

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by manoj on Mar 18, 2010 14:46
    nice concept
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by rio on Apr 19, 2010 18:59

    dear Sir

    is it possible to upload and download images using a database, not a class. if it would be possible could you give us a WCF sample code on how to save images in a database. Thank you so much

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Brajesh verma on May 20, 2010 08:40

    Dear sir,

    I am not able to upload a file over that 16 kb. Please provide the code for maximum size file storing in database.

    I did the maximum size setting in web.config file but still not progress.

    Please suggest me the proper way or setting in config file i am stuck in this

    thanks

    Brajesh verma

    brijmylife@gmail.com

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Girish G. Naik on May 21, 2010 09:09
    Interesting work. Nice explanation.
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Georgi on Jun 04, 2010 14:01
    Just Wonderful 10x a lot :)
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Shrek2 on Jul 12, 2010 21:20
    How can you store an image outside the application boundary ?
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Luck on Sep 21, 2010 18:54

    Hi, thanks for the great article.  I'm trying to test your example out but am running into some problems.  I've created a "Silverlight-enabled WCF Service" in VS2010.  However, when I type in the "filePath = HttpContext.Current.Server.MapPath(".") +..." statement, there's no HttpContext in Intellisense.  

    A quick Google search informs me that there is no HttpContext in WCF?? 

    Could you please help clarify this?

    Many thanks in advance!

    Luck

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Helianthus87 on Oct 03, 2010 22:41
    Great article! It saved me alot work. Thats all i need and as simple as possible.
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by distinct on Oct 17, 2010 08:57
    Can silverlight be used to personalizie an ecard?
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Balaji on Dec 09, 2010 15:14

    Hi ,

    This demo of uploading ang downloading helping me lot in the similar way i need to upload and download any files and files should support  1 GB for uploading and downoading

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Arati on Dec 16, 2010 19:46

    but i m sorry Balaji

     i m not able to upload  and download the images in database.

    its giving the message like images uploaded successfully but when i m typing that image name to get it back its say no image exists and even image is not getting stord in database

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Matteo on Jan 27, 2011 18:08
    Thank you very much
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by ednsinf on Feb 15, 2011 18:15

    Excelent post. Very usefull... Thanks!!!!

  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by threekhanz on Feb 17, 2011 13:45
    Very usefull............... although i was not developing Silverlight application, but it solve me WCF releated problem.
    Thanks, Alot............., May Allah Bless you.
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by fay on May 11, 2011 10:47
    s it possible to upload and download images using a database, not a class. if it would be possible could you give us a WCF sample code on how to save images in a database. Thank you so much
  • -_-

    RE: Uploading and downloading images from WCF in Silverlight


    posted by Mark Pearson on May 25, 2011 14:03
    how did you get round crossdomain problems
  • skumar

    Re: Uploading and downloading images from WCF in Silverlight


    posted by skumar on Sep 17, 2011 12:31

    Hai sir,

       I worked the above program, but i am not able to insert and upload the image in silvelight through wcf service ADO.NET entity , plz give me the solution ( coding and example program )

  • markaarnold

    Re: Uploading and downloading images from WCF in Silverlight


    posted by markaarnold on Sep 18, 2011 21:56

    Gill - I've also read about this solution in your Silverlight Data Services Cookbook.  Can you comment on the steps needed to convert this technique to "streaming" the data between client and service?  Of course you'd have some binding changes, but I'm more concerned with code changes.  

    Also, do you have any comments on adapting this to net.tcp on an intranet?  I'd like the maximum transfer performance but I wonder if there are code changes required or hidden issues beyond simply changing the binding config.

    Thanks!
    Mark

  • bitjunky

    Re: Uploading and downloading images from WCF in Silverlight


    posted by bitjunky on Sep 19, 2011 23:02
    Thank you for the sample project. I found a lot how info on this that I could not get to work. Your sample project help save me alot of trial and error.
  • bitjunky

    Re: Uploading and downloading images from WCF in Silverlight


    posted by bitjunky on Sep 20, 2011 19:07
    Thank you for the sample project. I found a lot how info on this that I could not get to work. Your sample project help save me alot of trial and error.
  • CesarAmezcua

    Re: Uploading and downloading images from WCF in Silverlight


    posted by CesarAmezcua on Oct 05, 2011 06:36

    Muchas Gracias, Funciono Perfecto!! Saludos Mexico

  • blogan

    Re: Uploading and downloading images from WCF in Silverlight


    posted by blogan on Oct 27, 2011 17:16

    I hope this blog is still active...

    Downloaded the source - converted to VS 2010 with no errors...

    Defaulted to Silverlight 3 and .NET 4.0 framework... following error occured at runtime.

    Tried Silverlight Version 4 and .Net 3.5 - (all permuntations).. same error?

    Unrecognized element 'message' in service reference configuration. Note that only a subset of the Windows Communication Foundation configuration functionality is available in Silverlight.

     

    Any insights?

    My REAL issue is another application I have developed wish seem NOT to properly handle MaxReceiveMessageSize... seems no matter what I do - I always get the 65535 exceeded error...

    Thanks for any assistance.

    Bob

  • Imanloo

    Re: Uploading and downloading images from WCF in Silverlight


    posted by Imanloo on Nov 01, 2011 06:57

    Dear Gill Cleeren

    I tried to Upload picture in my project and folow your souce step by step

    and returns error the remote server returned anerror NotFound

    error cames from generated code by system

     

    public bool EndUpload(System.IAsyncResult result) {

               object[] _args = new object[0];

               bool _result = ((bool)(base.EndInvoke("Upload", _args, result)));

               return _result;}

     

    may you please help me?

    if so please email it via imanloo@yahoo.com

    thabk you very much

  • Devendra

    Re: Uploading and downloading images from WCF in Silverlight


    posted by Devendra on Jan 07, 2012 23:51

    Hi,

    This is so nice , I want to upload a video in my video folder How can I do ....

  • christroch

    Re: Uploading and downloading images from WCF in Silverlight


    posted by christroch on Feb 17, 2012 15:44

    any solution on how to get over the 64K exceeded error?

    i tried the MaxReceiveMessageSize parameter...

Add Comment

Login to comment:
  *      *