0 votes

C# - Le contrôle WebBrowser semble mettre en cache les captures d'écran

J'utilise le contrôle WebBrowser dans une application ASP.NET MVC 2 (ne jugez pas, je le fais dans une section d'administration qui ne sera utilisée que par moi), voici le code :

public static class Screenshot
    {
        private static string _url;
        private static int _width;
        private static byte[] _bytes;

        public static byte[] Get(string url)
        {
            // This method gets a screenshot of the webpage
            // rendered at its full size (height and width)
            return Get(url, 50);
        }

        public static byte[] Get(string url, int width)
        {
            //set properties.
            _url = url;
            _width = width;
            //start screen scraper.
            var webBrowseThread = new Thread(new ThreadStart(TakeScreenshot));
            webBrowseThread.SetApartmentState(ApartmentState.STA);
            webBrowseThread.Start();
            //check every second if it got the screenshot yet.
            //i know, the thread sleep is terrible, but it's the secure section, don't judge...
            int numChecks = 20;
            for (int k = 0; k < numChecks; k++)
            {
                Thread.Sleep(1000);
                if (_bytes != null)
                {
                    return _bytes;
                }
            }
            return null;
        }

        private static void TakeScreenshot()
        {
            try
            {
                //load the webpage into a WebBrowser control.
                using (WebBrowser wb = new WebBrowser())
                {
                    wb.ScrollBarsEnabled = false;
                    wb.ScriptErrorsSuppressed = true;
                    wb.Navigate(_url);
                    while (wb.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); }
                    //set the size of the WebBrowser control.
                    //take Screenshot of the web pages full width.
                    wb.Width = wb.Document.Body.ScrollRectangle.Width;
                    //take Screenshot of the web pages full height.
                    wb.Height = wb.Document.Body.ScrollRectangle.Height;
                    //get a Bitmap representation of the webpage as it's rendered in the WebBrowser control.
                    var bitmap = new Bitmap(wb.Width, wb.Height);
                    wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));
                    //resize.
                    var height = _width * (bitmap.Height / bitmap.Width);
                    var thumbnail = bitmap.GetThumbnailImage(_width, height, null, IntPtr.Zero);
                    //convert to byte array.
                    var ms = new MemoryStream();
                    thumbnail.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                    _bytes = ms.ToArray();
                }
            }
            catch(Exception exc)
            {//TODO: why did screenshot fail?
                string message = exc.Message;
            }
        }

Cela fonctionne bien pour la première capture d'écran que je fais, mais si j'essaie de faire d'autres captures d'écran de différentes URL, il enregistre les captures d'écran de la première url pour la nouvelle url, ou parfois il enregistre la capture d'écran d'il y a 3 ou 4 url. Je crée une nouvelle instance de WebBrowser pour chaque capture d'écran et je m'en débarrasse correctement avec le bloc "using". Avez-vous une idée de la raison pour laquelle il se comporte de cette façon ?

Merci, Justin

0voto

Julien Lebosquain Points 20894

Vous utilisez un champ statique pour stocker l'URL actuelle, de sorte que plusieurs requêtes (et donc plusieurs fils) ont une chance de naviguer vers la même URL puisque vous ne synchronisez aucun accès. Vous devriez soit utiliser une file d'attente synchronisée qui traitera une demande de capture d'écran après l'autre, soit envisager de rendre votre classe entière non statique afin de pouvoir en instancier une par demande.

D'ailleurs, utilisez un AutoResetEvent ou un autre mécanisme de signalisation pour effectuer l'attente, plutôt que de dormir dans une boucle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X