Pregunta

Necesito usar el control WinForms WebBrowser en una aplicación ASP.NET para tomar capturas de pantalla de páginas web.

Prefiero ejecutarlo en una aplicación de consola y comunicarme con la aplicación a través de la aplicación ASP.NET, pero no es mi decisión, me han dicho que debe ejecutarse como parte del sitio web.

Todo funciona bastante bien, aparte de cada llamada, la navegación comienza de nuevo con una nueva sesión, es como si las cookies no se mantuvieran. Como experimento, cambié mi grupo de aplicaciones IIS para ejecutarme como yo en lugar de NETWORK_SERVICE, y todo funciona bien. Así que es algo extraño que se ejecute como servicio de red.

Supongo que la cuenta de servicio de red no tiene los permisos para realizar un seguimiento de la cookie ASP.NET_SessionId y la cookie de autenticación, pero ambas son cookies no persistentes, así que no sé por qué be.

Aquí hay un código simplificado para que pueda obtener la esencia de lo que estoy haciendo. Hay un montón de registro y almacenamiento de imágenes que recorté, por lo que no es un código completo. Básicamente, un desarrollador / probador / administrador puede ejecutar este código una vez (tarea iniciada a través de la página web), generará mapas de bits de cada página en el sistema, puede lanzar una nueva versión del sitio web y luego ejecutarlo nuevamente, le dirá las diferencias (nuevas páginas, páginas eliminadas, páginas cambiadas).

public void Run()
{
    var t = new Thread(RunThread);
    t.SetApartmentState(ApartmentState.STA);
    t.Start();
}

private void RunThread()
{
    try
    {
        using (var browser = new WebBrowser())
        {
            browser.DocumentCompleted += BrowserDocumentCompleted;

            if (!VisitPage(browser, "special page that sets some session flags for testing - makes content predictable")))
                throw new TestRunException("Unable to disable randomness");

            foreach (var page in pages)
            {
                VisitPage(browser, page);
            }
        }
    }
    // An unhandled exception in a background thread in ASP.NET causes the app to be recycled, so catch everything here
    catch (Exception)
    {
        Status = TestStatus.Aborted;
    }
}

private bool VisitPage(WebBrowser browser, string page)
{
    finishedEvent.Reset();

    var timeout = false;
    stopwatch = new Stopwatch();

    browser.Navigate(page);

    stopwatch.Start();

    while (!timeout && !finishedEvent.WaitOne(0))
    {
        Application.DoEvents();
        if (stopwatch.ElapsedMilliseconds > 10000)
            timeout = true;
    }
    Application.DoEvents();

    if (timeout)
    {
        if (resource != null)
            ShopData.Shop.LogPageCrawlTestLine(testRunID, resource, sequence++, (int)stopwatch.ElapsedMilliseconds, null);
    }

    browser.Stop();

    return !timeout;
}

private void BrowserDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    try
    {
        var browser = (WebBrowser)sender;

        var width = browser.Document.Body.ScrollRectangle.Width;
        var height = browser.Document.Body.ScrollRectangle.Height;
        var timeTaken = (int)stopwatch.ElapsedMilliseconds;

        if ((width == 0) || (height == 0))
        {
            return;
        }

        browser.Width = width;
        browser.Height = height;

        byte[] buffer;

        using (var bitmap = new Bitmap(width, height))
        using (var memoryStream = new MemoryStream())
        {
            browser.DrawToBitmap(bitmap, new Rectangle(0, 0, width, height));
            bitmap.Save(memoryStream, ImageFormat.Bmp);
            buffer = memoryStream.ToArray();
        }
        // stores image

    }
    finally
    {
        finishedEvent.Set();
    }
}

Así que en resumen:

  • El código anterior se inicia con una página ASP.NET y se ejecuta en el backgound
  • Funciona bien si lo ejecuto en un grupo de aplicaciones de IIS configurado para ejecutarse como un usuario adecuado
  • Si lo ejecuto en un grupo de aplicaciones IIS como NETWORK_SERVICE, cada navegación tiene una nueva sesión, en lugar de persistir una sesión durante toda la vida del WebBrowser.
  • Puedo hacerlo funcionar bien fuera de ASP.NET, pero esa no es una opción para mí actualmente, tiene que ejecutarse dentro de esta aplicación ASP.NET.

// Actualizar

Por consejo de mi colega, estoy usando la suplantación en el hilo de fondo donde estoy creando el WebBrowser, ejecutando como un usuario local. Esto funciona bien y estoy muy contento con esta solución. Es un usuario de stackoverflow, así que le dejaré que publique la respuesta y obtenga el crédito :)

¿Fue útil?

Solución

El uso de la suplantación en el subproceso en segundo plano permitiría que WebBrowser se ejecute como un usuario con permisos para ejecutar IE y, por lo tanto, almacenar cookies, en lugar de que se ejecute como usuario del grupo de aplicaciones (NETWORK_SERVICE).

Puede configurar la suplantación en web.config o programáticamente para restringirlo a un hilo específico.

Otros consejos

no es oficialmente compatible debido a su uso de WinInet. consulte http://support.microsoft.com/kb/238425 para conocer las limitaciones de WinInet en un Servicio.

¿Ve la cookie de sesión en las solicitudes provenientes del control WebBrowser? No puedo encontrar nada sobre cómo se supone que este control maneja las cookies: si las ignora, obtendrás el comportamiento que estás describiendo

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top