WP8 Некоторые изображения не загружаются с помощью HttpClient

Я создаю приложение WP8, которое загружает изображения с помощью HttpClient в фоновой задаче. Моя проблема в том, что некоторые изображения не загружаются независимо от того, сколько времени я жду их завершения. Максимальный размер изображения составляет несколько мегабайт.

Код, который я использую для загрузки изображений:

    internal static async Task<bool> Download_Wallpaper(string image_url, string file_name, string destination_folder_name)
    {
        try
        {
            using (var client = new HttpClient())
            {

                // 12MB max images
                client.Timeout = TimeSpan.FromSeconds(5);
                client.MaxResponseContentBufferSize = DeviceStatus.ApplicationMemoryUsageLimit / 2;
                //client.Timeout = TimeSpan.FromSeconds(5);

                byte[] image_byte_arr;
                try
                {
                    /*  var requestMessage = new HttpRequestMessage( HttpMethod.Get, image_url );
                        var responseMessage = await client.SendAsync((requestMessage));
                        // byte array of image
                        image_byte_arr = await responseMessage.Content.ReadAsByteArrayAsync();
                        */
                    // byte array of image
                    image_byte_arr = await client.GetByteArrayAsync(image_url);
                }
                // Could not download
                catch (OutOfMemoryException X)
                {
                    GC.Collect();
                    return false;
                }

                var folder = await StorageFolder.GetFolderFromPathAsync(destination_folder_name);
                // Create file
                StorageFile file = await folder.CreateFileAsync(file_name, CreationCollisionOption.ReplaceExisting);
                using (var write_stream = await file.OpenStreamForWriteAsync())
                {
                    write_stream.Write(image_byte_arr, 0, image_byte_arr.Length);
                }
                Console.WriteLine(DeviceStatus.ApplicationCurrentMemoryUsage);
                return true;
            }
        }
        catch (HttpRequestException X)
        {
            Console.WriteLine(X);
            return false;
        }
        catch (OutOfMemoryException X)
        {
            GC.Collect();
            return false;
        }
        catch (Exception X)
        {
            Console.WriteLine(X);
            return false;
        }
    }

Это пример изображения, которое не загружается: https://upload.wikimedia.org/wikipedia/commons/9/95/Tracy_Caldwell_Dyson_in_Cupola_ISS.jpg

По моему опыту, все изображения викимедиа по какой-то причине не загружаются.

Я не вижу способа отслеживать процесс загрузки с помощью HttpClient. Есть ли способ сделать это?

Изменить: кажется, что установка времени ожидания не имеет никакой функции. Исключение HttpRequestException не выдается через 5 секунд.

Edit2: я попробовал другой подход, предложенный anonshankar. При таком методе код застрял бы на строке:

byte[] img = response.Content.ReadAsByteArrayAsync();

Вот и приходит HttpResponse, но почему-то байты не могут быть прочитаны, сколько бы времени я ему не уделял. Как такое вообще могло произойти? Трудная часть — получить ответ, чтение байтов должно быть простым.

Опять же, это происходит только с некоторыми изображениями, большинство из них загружаются корректно. Один пример упомянут выше.

Я изменил код загрузчика изображений, чтобы время ожидания истекло через несколько секунд. Вот мой окончательный код:

    internal static async Task<bool> Download_Wallpaper(string image_url, string file_name, string destination_folder_name)
    {
        try
        {
            using (var client = new HttpClient())
            {

                // prevent running out of memory
                client.MaxResponseContentBufferSize = DeviceStatus.ApplicationMemoryUsageLimit / 3;

                byte[] image_byte_arr = null;


                using (CancellationTokenSource cts = new CancellationTokenSource())
                {

                    var task = Task.Factory.StartNew(() =>
                    {
                        try
                        {
                            image_byte_arr = client.GetByteArrayAsync(image_url).Result;
                        }
                        catch (AggregateException X)// Handling read errors, usually image is too big
                        {
                            Console.WriteLine(X.Message);
                            foreach (var v in X.InnerExceptions)
                                Console.WriteLine(v.Message);
                            image_byte_arr = null;
                        }
                    }, cts.Token);

                    bool finished_in_time = task.Wait(TimeSpan.FromSeconds(5));

                    if (!finished_in_time)// Timeout
                    {
                        cts.Cancel();
                        task.Wait();
                        return false;
                    }
                    else if (image_byte_arr == null)// Read error
                    {
                        return false;
                    }

                }

                var folder = await StorageFolder.GetFolderFromPathAsync(destination_folder_name);
                // Create file
                StorageFile file = await folder.CreateFileAsync(file_name, CreationCollisionOption.ReplaceExisting);
                using (var write_stream = await file.OpenStreamForWriteAsync())
                {
                    write_stream.Write(image_byte_arr, 0, image_byte_arr.Length);
                }
                Console.WriteLine(DeviceStatus.ApplicationCurrentMemoryUsage);
                return true;
            }
        }
        catch (HttpRequestException X)
        {
            Console.WriteLine(X);
            return false;
        }
        catch (OutOfMemoryException X)
        {
            GC.Collect();
            return false;
        }
        catch (Exception X)
        {
            Console.WriteLine(X);
            return false;
        }
    }

Любые предложения по улучшению приветствуются, и я до сих пор не понимаю, почему метод HttpContent.ReadAsByteArrayAsync() зависает.


person VSZM    schedule 23.06.2014    source источник


Ответы (1)


Просто попробуйте это snippet, которое сработало для меня.

HttpClient client = new HttpClient();

HttpResponseMessage response = await client.GetAsync("give the url");

byte[] img = response.Content.ReadAsByteArray();

InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();

DataWriter writer = new DataWriter(randomAccessStream.GetOutputStreamAt(0));

writer.WriteBytes(img);

await writer.StoreAsync();

BitmapImage b = new BitmapImage();

b.SetSource(randomAccessStream);

pic.Source = b; //(pic is an `<Image>` defined in the `XAML`

Надеюсь, поможет!

person Kulasangar    schedule 24.06.2014
comment
Привет. Вы уверены, что это код WP8? Я спрашиваю, потому что в WP8 нет метода ReadAsByteArray() для HttpContent. Плюс класс BitmapImage нельзя использовать в фоновом потоке, только в потоке пользовательского интерфейса. В любом случае, я ранее пробовал очень похожий код, но не работал лучше. - person VSZM; 25.06.2014