Why it always throws an ObjectDisposedException?

Albert Gao picture Albert Gao · May 30, 2013 · Viewed 11.2k times · Source

Due to the fact that the windows phone can't handle gif, I write a little method, but it seems that it has a little error.
The code below always throws a exception when it runs to (JPG and PNG part)bitimg.SetSource(e.Result);
As it said, does it mean that I can't use the e.Result because it is disposed? But how could this happen, the method hasn't stop, why will the compiler dispose it?

Why and how to solve it?

Error Info:

{System.ObjectDisposedException: Cannot access a disposed object. Object name: 'MS.Internal.InternalMemoryStream'. at MS.Internal.InternalMemoryStream.Seek(Int64 offset, SeekOrigin origin) at ImageTools.IO.Gif.GifDecoder.Decode(ExtendedImage image, Stream stream) at xicihutong.ViewModel.RichTextBoxBindingBehavior.<>c__DisplayClass7.b__4(Object s, OpenReadCompletedEventArgs e) at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e) at System.Net.WebClient.OpenReadOperationCompleted(Object arg)}

image.Loaded += (s1, e1) =>
{
    WebClient wc = new WebClient();
    wc.AllowReadStreamBuffering = true;
    wc.OpenReadCompleted += (s, e) =>
    {
        if (e.Error == null && !e.Cancelled)
        {
            //Check the type of the Image
            ImageTypeCheck.ImageType incomingIMGType = ImageTypeCheck.getImageType(e.Result);

            BitmapImage bitimg = new BitmapImage();
            bitimg.CreateOptions = BitmapCreateOptions.BackgroundCreation;

            switch (incomingIMGType)
            {
                //handle GIF for windows phone
                case ImageTypeCheck.ImageType.Gif:
                    Decoders.AddDecoder<GifDecoder>();
                    Encoders.AddEncoder<JpegEncoder>();
                    GifDecoder gif = new GifDecoder();
                    JpegEncoder jpg = new JpegEncoder();
                    ImageTools.ExtendedImage extImg = new ImageTools.ExtendedImage();
                    gif.Decode(extImg, e.Result);
                    using (MemoryStream stream = new MemoryStream())
                    {
                        jpg.Encode(extImg, stream);
                        bitimg.SetSource(stream);
                        image.Source = bitimg;
                    }
                    break;
                case ImageTypeCheck.ImageType.Bmp:
                case ImageTypeCheck.ImageType.Null:
                    break;
                case ImageTypeCheck.ImageType.Jpg:
                case ImageTypeCheck.ImageType.Png:
                    try
                    {
                        bitimg.SetSource(e.Result);
                        image.Source = bitimg;
                    }
                    catch (Exception ex)
                    {
                        App.print(ex.Message);
                    }
                    break;
            }
        }
    };
    wc.OpenReadAsync(new Uri(item, UriKind.Absolute), wc);

}

==================================

using System.IO;

namespace xicihutong.DataServiceAgent
{
    class ImageTypeCheck
    {
        /// <summary>
        /// define
        /// </summary>
        public enum ImageType
        {
            Null,Png,Jpg,Gif,Bmp
        }


        public static ImageType getImageType(Stream stream)
        {
            ImageType type = ImageType.Null;

            byte[] header = new byte[8];
            stream.Read(header, 0, 8);

            //Check if PNG then do something;
            //Check if JPG then do something;
            //Check if GIF then do something;

            stream.Close();

            return type;
        }
    }
}

Answer

Kevin Gosse picture Kevin Gosse · May 30, 2013

As you pointed yourself, the ImageTypeCheck.getImageType method is closing the stream.

How were you supposed to find the issue?

  1. The error message clearly indicates that the stream has been disposed. All that left was finding the culprit.
  2. The callstack shows that the ImageTools.IO.Gif.GifDecoder.Decode was being called when the error was thrown. So it happened before that.
  3. Luckily, there's only one method using the stream before the GifDecoder, and that is ImageTypeCheck.getImageType

To fix the issue, just remove the stream.Close from the ImageTypeCheck.getImageType method, and replace it with a Seek to go back to the beginning of the stream (the GifDecoder expects the stream to be positioned at the start of the picture).

stream.Seek(0, SeekOrigin.Begin);