Brilbroeder
Brilbroeder

Reputation: 55

RestSharp - Download / Use image in WPF/Silverlight

I'm trying to use RestSharp to download an image from a WCF/Rest service. The result should be saved in a file and displayed in a Image control an a WPF/SL page.

    private void GetImage()
    {
        RestClient _Client = new RestClient(BASE_URI);
        RestRequest request = new RestRequest("/api/img/{FileName}");
        request.AddParameter("FileName", "dummy.jpg", ParameterType.UrlSegment);
        _Client.ExecuteAsync<MemoryStream>(
        request,
        Response =>
        {
            if (Response != null)
            {
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = Response.Data;
                String fn = String.Format(@"c:\temp\{0}.jpg", Guid.NewGuid().ToString());
                System.IO.File.WriteAllBytes(fn,Response.Data.ToArray());
                bitmapImage.EndInit();
                img.Source = bitmapImage;
            }
        });
    }

When I look in fiddler the image got downloaded correctly BUT no image is saved and nothing is displayd. There is no exception thown. ANy suggestions ?


UPDATED

A part of the problem turns out that RestSharp is not returning the expected memorystream. Moving to another methed and accessing the raw data in byte[] format solves part of the problem, saving the picutere to disk.

    private void GetImage()
    {
        RestClient _Client = new RestClient(BASE_URI);
        RestRequest request = new RestRequest("/api/img/{FileName}");
        request.AddParameter("FileName", "dummy.jpg", ParameterType.UrlSegment);
        _Client.ExecuteAsync(
        request,
        Response =>
        {
            if (Response != null)
            {
                byte[] imageBytes = Response.RawBytes;
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = new MemoryStream(imageBytes);
                bitmapImage.CreateOptions = BitmapCreateOptions.None;
                bitmapImage.CacheOption = BitmapCacheOption.Default;
                bitmapImage.EndInit();

                JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                Guid photoID = System.Guid.NewGuid();
                String photolocation = String.Format(@"c:\temp\{0}.jpg", Guid.NewGuid().ToString());
                encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
                using (var filestream = new FileStream(photolocation, FileMode.Create))
                encoder.Save(filestream);

                this.Dispatcher.Invoke((Action)(() => { img.Source = bitmapImage; }));
                ;
            }
        });
    }

Although calling this.dispatcher.Invoke I still get the error : The calling thread cannot acces this object because a different thread owns it.

Upvotes: 3

Views: 3741

Answers (2)

Clemens
Clemens

Reputation: 128106

As the BitmapImage is created in another thread than the UI thread, you also have to call Freeze to make it accessible in the UI thread.

Although not strictly necessary here, it is good practise to always dispose of any IDisposable objects, including MemoryStream. Therefore you will also have to set the BitmapImage.CacheOption property to OnLoad.

using (var memoryStream = new MemoryStream(imageBytes))
{
    bitmapImage.BeginInit();
    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
    bitmapImage.StreamSource = memoryStream;
    bitmapImage.EndInit();
    bitmapImage.Freeze();
}

The frozen BitmapImage is accessible in the UI thread:

Dispatcher.Invoke((Action)(() => img.Source = bitmapImage));

Upvotes: 4

Ameen
Ameen

Reputation: 2586

Are you checking for exceptions using the debugger? If an exception is thrown on a background task, it won't be rethrown on the caller code unless you access Task.Result or use the await operator.

My guess is that you don't have access to the location of C: you are writing to. That block of code seems unnecessary anyway though, you should be able to directly set the source of the image to the stream you have without writing it to disk. Try commenting the writing to drive piece of code out and see if that solves the issue.

Upvotes: 0

Related Questions