3

Bloggerブログからコンテンツをインポートするためのコードをいくつか作成しました。すべてのHTMLコンテンツをダウンロードしたら、画像タグを調べて、対応する画像をダウンロードします。多くの場合、System.Drawing.Bitmap.FromStreamはArgumentExceptionをスローしています。ダウンロード元のURLは見栄えがよく、期待どおりに画像が表示されます(問題のある画像の1つのURLは次のとおりです:http://4.bp.blogspot.com/_tSWCyhtOc38/SgIPcctWRZI/AAAAAAAAAGg/2LLnVPxsogI/s1600- h / IMG_3590.jpg)。

    private static System.Drawing.Image DownloadImage(string source)
    {
        System.Drawing.Image image = null;

        // used to fetch content
        var client = new HttpClient();

        // used to store image data
        var memoryStream = new MemoryStream();

        try
        {
            // fetch the image
            var imageStream = client.GetStreamAsync(source).Result;

            // instantiate a system.drawing.image from the data
            image = System.Drawing.Bitmap.FromStream(imageStream, false, false);

            // save the image data to a memory stream
            image.Save(memoryStream, image.RawFormat);
        }
        catch (IOException exception)
        {
            Debug.WriteLine("{0} {1}", exception.Message, source);
        }
        catch (ArgumentException exception)
        {
            // sometimes, an image will link to a web page, resulting in this exception
            Debug.WriteLine("{0} {1}", exception.Message, source);
        }
        catch (AggregateException exception)
        {
            // sometimes, an image src will throw a 404
            Debug.WriteLine("{0} {1}", exception.Message, source);
        }
        finally
        {
            // clean up our disposable resources
            client.Dispose();
            memoryStream.Dispose();
        }

        return image;
    }

ArgumentExceptionがここでスローされる理由はありますか?

編集:プロキシの問題である可能性があることに気付いたので、web.configに次を追加しました。

<system.net>
  <defaultProxy enabled="true" useDefaultCredentials="true">
    <proxy usesystemdefault="True" />
  </defaultProxy>
</system.net>

ただし、そのセクションを追加しても違いはありません。

編集:このコードは、EFデータベース初期化子のコンテキストから呼び出されます。スタックトレースは次のとおりです。

Web.dll!Web.Models.Initializer.DownloadImage(string source)234行目C#Web.dll!Web.Models.Initializer.DownloadImagesForPost.AnonymousMethod__5(HtmlAgilityPack.HtmlNode tag)126行目+ 0x8バイトC#[外部コード] Web.dll !Web.Models.Initializer.DownloadImagesForPost(Web.Models.Post post)行119 + 0x34バイトC#Web.dll!Web.Models.Initializer.Seed(Web.Models.FarmersMarketContextコンテキスト)行320 + 0xbバイトC#[外部コード] App_Web_l2h4tcej.dll!ASP._Page_Views_Home_Index_cshtml.Execute()行28 + 0x15バイトC#[外部コード]

4

2 に答える 2

4

問題が見つかりました。場合によっては、Blogger が画像自体を参照するのではなく、画像をレンダリングする HTML ページを参照することが判明しています。したがって、その場合の応答は有効な画像ではありません。画像データを保存する前に応答ヘッダーをチェックするコードを追加したので、問題は解決しました。この問題に遭遇した他の人の利益のために、更新されたコードを次に示します。

    private static System.Drawing.Image DownloadImage(string source)
    {
        System.Drawing.Image image = null;

        // used to fetch content
        var client = new HttpClient();

        // used to store image data
        var memoryStream = new MemoryStream();

        try
        {
            // Blogger tacks on a -h to an image Url to link to an HTML page instead
            if (source.Contains("-h/"))
                source = source.Replace("-h/", "/");

            // fetch the image
            var response = client.GetAsync(source).Result;
            response.EnsureSuccessStatusCode();

            var contentType = response.Content.Headers.ContentType.MediaType;

            if (!contentType.StartsWith("image/"))
            {
                Debug.WriteLine(contentType);
                throw new ArgumentException("Specified source did not return an image");
            }

            var imageStream = response.Content.ReadAsStreamAsync().Result;

            // instantiate a system.drawing.image from the data
            image = System.Drawing.Bitmap.FromStream(imageStream, true, true);

            // save the image data to a memory stream
            image.Save(memoryStream, image.RawFormat);
        }
        catch (HttpRequestException exception)
        {
            // sometimes, we'll get a 404 or other unexpected response
            Debug.WriteLine("{0} {1}", exception.Message, source);
        }
        catch (IOException exception)
        {
            Debug.WriteLine("{0} {1}", exception.Message, source);
        }
        catch (ArgumentException exception)
        {
            // sometimes, an image will link to a web page, resulting in this exception
            Debug.WriteLine("{0} {1}", exception.Message, source);
        }
        finally
        {
            // clean up our disposable resources
            client.Dispose();
            memoryStream.Dispose();
        }

        return image;
    }
于 2012-07-10T15:15:56.867 に答える
1

あなたは別の問題を扱っています。偶然に修正したと思います。残念ながら、GDI+ の例外はあまり良くなく、多くの場合、実際の問題が何であるかを教えてくれません。

Image.FromStream() 実装でのあいまいなヒントの 1 つは、ストリームからビットマップをロードするときに、GDI+ がストリームの Seek() メソッドを使用することです。ただし、これはストリームがシークを許可している場合にのみうまく機能し、その CanSeek プロパティは true を返す必要があります。これは一般に、ネットワーク ストリームの場合には当てはまりません。任意のシークを許可するのに十分なバッファリングが提供されていません。

これは HttpClient.GetStreamAsync() の問題です。MSDN ライブラリのドキュメントには次のように書かれています。

このメソッドはストリームをバッファリングしません

あなたが書いた作業バージョンは HttpContent.ReadAsStreamAsync() を使用していますが、MSDN ライブラリのドキュメントには次のように書かれています:

返された Task オブジェクトは、すべてのコンテンツがバイト配列として書き込まれた後に完了します

ストリームの CanSeek プロパティが false であるため、最初のバージョンは機能しません。2 番目のバージョンは、シークを許可するバイト配列に応答全体が読み込まれるため機能します。一般的な解決策は、最初にストリームを MemoryStream に丸呑みすることです。

于 2012-07-10T16:21:50.357 に答える