Как использовать System.Windows.Forms.WebBrowser в веб-приложении? - PullRequest
1 голос
/ 13 июля 2009

Я нашел код winform здесь: http://www.wincustomize.com/articles.aspx?aid=136426&c=1

И он прекрасно работает как winform. Но я хочу запустить код в веб-приложении.

  1. Я добавляю ссылки на System.Windows.Forms и Microsoft.mshtml.dll в C: \ Program Files \ Microsoft.NET \ Первичные сборки взаимодействия \ в мое веб-приложение.

  2. Я копирую WebPageBitmap.cs в свое веб-приложение.

  3. Я копирую Main.) Program.cs в мое веб-приложение как Button_Click ().

  4. Когда я нажимаю кнопку в моем веб-приложении. Возникает ошибка:

Элемент управления ActiveX '8856f961-340a-11d0-a96b-00c04fd705a2' не может быть создан, поскольку текущий поток не находится в однопоточной квартире.

Как я могу использовать System.Windows.Forms.WebBrowser в веб-приложении для получения эскиза веб-сайта?

public partial class Capture01 : System.Web.UI.Page
{
    public delegate void WebBrowserDocumentCompletedEventHandler(object sender, WebBrowserDocumentCompletedEventArgs e);

    [STAThread]
    protected void Button1_Click(object sender, EventArgs e)
    {           
        int width = 1024;
        int height = 900;

        int thumbwidth = width;
        int thumbheight = height;           

        string fileName = "image01.jpg";
        string url = "http://www.iweixtest.cn/WE/Site/1647/index.aspx";          
        thumbwidth = 150;
        thumbheight = 100;

        //WebPageBitmap webBitmap = new WebPageBitmap(args[0], width, height, false, 10000);
        WebPageBitmap webBitmap = new WebPageBitmap(url, width, height, false, 10000);
        if (webBitmap.IsOk)
        {
            webBitmap.Fetch();
            Bitmap thumbnail = webBitmap.GetBitmap(thumbwidth, thumbheight);
            //thumbnail.Save(args[1], ImageFormat.Jpeg);
            thumbnail.Save(fileName, ImageFormat.Jpeg);
            thumbnail.Dispose();
        }
        else
        {
            MessageBox.Show(webBitmap.ErrorMessage);
        }       
    }
}

WebPageBitmap.cs

namespace GetSiteThumbnail
{
    /// <summary>
    /// Thanks for the solution to the "sometimes not painting sites to Piers Lawson
    /// Who performed some extensive research regarding the origianl implementation.
    /// You can find his codeproject profile here:
    /// http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=39324
    /// </summary>
    [InterfaceType(1)]
    [Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
    public interface IHTMLElementRender2
    {
        void DrawToDC(IntPtr hdc);
        void SetDocumentPrinter(string bstrPrinterName, ref _RemotableHandle hdc);
    }

    /// <summary>
    /// Code by Adam Najmanowicz
    /// http://www.codeproject.com/script/Membership/Profiles.aspx?mid=923432
    /// http://blog.najmanowicz.com/
    /// Some improvements suggested by Frank Herget
    /// http://www.artviper.net/
    /// </summary>
    class WebPageBitmap
    {
        private WebBrowser webBrowser;
        private string url;
        private int width;
        private int height;
        private bool isOk;
        private string errorMessage;

        public string ErrorMessage
        {
            get { return errorMessage; }
        }

        public bool IsOk
        {
            get { return isOk; }
            set { isOk = value; }
        }

        public WebPageBitmap(string url, int width, int height, bool scrollBarsEnabled, int wait)
        {
            this.width = width;
            this.height = height;

            this.url = 
                url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) ? 
                url : this.url = "http://" + url;

            try
            // needed as the script throws an exeception if the host is not found
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(this.url);
                req.AllowAutoRedirect = true;
                //req.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)"; //成功
                req.UserAgent = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
                //req.Referer = "http://www.cognifide.com";
                req.ContentType = "text/html";
                req.Accept = "*/*";
                req.KeepAlive = false;

                using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
                {
                    string x = resp.StatusDescription;
                }    
            }
            catch (Exception ex)
            {
                errorMessage = ex.Message;
                isOk = false;
                return;
            }
            isOk = true;                                                      // public, to check in program.cs if the domain is found, so the image can be saved

            webBrowser = new WebBrowser();
            webBrowser.DocumentCompleted +=
            new WebBrowserDocumentCompletedEventHandler(documentCompletedEventHandler);
            webBrowser.Size = new Size(width, height);
            webBrowser.ScrollBarsEnabled = false;
        }

        /// <summary>
        /// Fetches the image 
        /// </summary>
        /// <returns>true is the operation ended with a success</returns>
        public bool Fetch()
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.AllowAutoRedirect = true;
            //req.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)";
            req.UserAgent = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
            //req.Referer = "http://www.cognifide.com";
            req.ContentType = "text/html";
            req.AllowWriteStreamBuffering = true;
            req.AutomaticDecompression = DecompressionMethods.GZip;
            req.Method = "GET";
            req.Proxy = null;
            req.ReadWriteTimeout = 20;

            HttpStatusCode status;
            using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
            {
                status = resp.StatusCode;
            }

            if (status == HttpStatusCode.OK || status == HttpStatusCode.Moved)
            {
                webBrowser.Navigate(url);
                while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
                {
                    Application.DoEvents();

                }
                return true;
            }
            else
            {
                return false;
            }
        }

        private void documentCompletedEventHandler(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            ((WebBrowser)sender).Document.Window.Error +=
                new HtmlElementErrorEventHandler(SuppressScriptErrorsHandler);
        }

        public void SuppressScriptErrorsHandler(object sender, HtmlElementErrorEventArgs e)
        {
            e.Handled = true;
            MessageBox.Show("Error!");
        }

        internal Bitmap GetBitmap(int thumbwidth, int thumbheight)
        {
            IHTMLDocument2 rawDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
            IHTMLElement rawBody = rawDoc.body;
            IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;

            Bitmap bitmap = new Bitmap(width, height);
            Rectangle bitmapRect = new Rectangle(0, 0, width, height);

            // Interesting thing that despite using the renderer later 
            // this following line is still necessary or 
            // the background may not be painted on some websites.
            webBrowser.DrawToBitmap(bitmap, bitmapRect);

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                IntPtr graphicshdc = graphics.GetHdc();
                render.DrawToDC(graphicshdc);

                graphics.ReleaseHdc(graphicshdc);
                graphics.Dispose();

                if (thumbheight == height && thumbwidth == width)
                {
                    return bitmap;
                }
                else
                {
                    Bitmap thumbnail = new Bitmap(thumbwidth, thumbheight);
                    using (Graphics gfx = Graphics.FromImage(thumbnail))
                    {
                        // high quality image sizing
                        gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;                            
                        gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;                                                                       // make it look pretty 
                        gfx.DrawImage(bitmap, new Rectangle(0, 0, thumbwidth, thumbheight), bitmapRect, GraphicsUnit.Pixel);
                    }
                    bitmap.Dispose();
                    return thumbnail;
                }
            }
        }
    }
}

Ответы [ 3 ]

3 голосов
/ 13 июля 2009

Вы можете создать свой собственный рабочий поток и вызвать SetApartmentState , чтобы изменить его на поток STA; эта тема может выполнять работу по визуализации веб-страниц. Однако потребуется много межпотокового взаимодействия, и, как сказал Р. Бемроуз, классы System.Windows на самом деле не предназначены для использования внутри веб-приложения.

Другим подходом было бы переписать пример приложения (в виде .EXE), чтобы получить два параметра: (1) URL-адрес для загрузки и (2) расположение вывода для снимка экрана. Ваше веб-приложение может создать временный путь (для выходного файла), запустить эту программу (с Process.Start ), дождаться его завершения, загрузить созданный выходной файл, затем один раз удалить временный файл оно было отправлено клиенту или больше не было необходимости. (Разумеется, обработка ошибок должна отличаться от отображения окна сообщения, если что-то пошло не так.)

3 голосов
/ 14 июля 2009

Я успешно использовал System.Windows.Forms.WebBrowser в веб-приложении.

Просто следуйте инструкциям выше и добавьте AspCompat = "true" на странице веб-формы:

Спасибо за все ответы.

0 голосов
/ 13 июля 2009

Короткий ответ: ничего в System.Windows не предназначено для использования в веб-приложении.

System.Windows.Forms - это клиентские элементы управления. Однако веб-приложения выполняются на стороне сервера и имеют собственные элементы пользовательского интерфейса в System.Web.UI.

mshtml может быть другим камнем преткновения. Я, честно говоря, не мог сказать, будет ли это доступно из IIS.

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

...