Запуск WinForms WebBrowser контроля как NETWORK_SERVICE - PullRequest
2 голосов
/ 26 ноября 2009

Мне нужно использовать элемент управления WinForms WebBrowser в приложении ASP.NET, чтобы делать скриншоты веб-страниц.

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

Все это в значительной степени работает независимо от того, что каждый вызов начинается заново с нового сеанса, как будто файлы cookie не сохраняются. В качестве эксперимента я изменил пул приложений IIS, чтобы он выполнялся как я, а не как NETWORK_SERVICE, и все работает нормально. Поэтому что-то странное в том, что он работает как сетевой сервис.

Я предполагаю, что учетная запись сетевой службы не имеет прав для отслеживания файла cookie ASP.NET_SessionId и файла cookie auth, но оба они являются непостоянными файлами cookie, поэтому я не знаю, почему это будет.

Вот несколько упрощенных кодов, чтобы вы могли понять суть того, что я делаю. Есть куча регистрации и хранения изображений, которые я вырезал, так что это не полный код. По сути, разработчик / тестер / администратор может запустить этот код один раз (задание запускается через веб-страницу), он будет генерировать растровые изображения каждой страницы в системе, они могут выпустить новую версию веб-сайта и затем запустить ее снова, он сообщит вам различия (новые страницы, страницы удалены, страницы изменены).

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();
    }
}

Итак, в итоге:

  • Приведенный выше код запускается страницей ASP.NET и выполняется в фоновом режиме
  • Работает нормально, если я запускаю его в пуле приложений IIS, настроенном для работы от имени пользователя
  • Если я запускаю его в пуле приложений IIS с именем NETWORK_SERVICE, то у каждой навигации будет новый сеанс, а не постоянный сеанс в течение всего срока службы веб-браузера.
  • Я могу заставить его работать нормально вне ASP.NET, но сейчас это не вариант для меня, он должен работать внутри этого приложения ASP.NET.

// Обновить

По совету моего коллеги я использую олицетворение в фоновом потоке, где я создаю WebBrowser, работающий как локальный пользователь. Это прекрасно работает, и я очень доволен этим решением. Он пользователь stackoverflow, поэтому я позволю ему опубликовать ответ и получить кредит:)

Ответы [ 3 ]

2 голосов
/ 27 ноября 2009

Использование олицетворения в фоновом потоке позволило бы WebBrowser запускаться от имени пользователя с разрешениями на запуск IE и, таким образом, сохранять файлы cookie, а не запускаться от имени пользователя пула приложений (NETWORK_SERVICE).

Вы можете настроить Олицетворение в web.config или программно , чтобы ограничить его конкретным потоком.

2 голосов
/ 29 ноября 2009

официально не поддерживается из-за использования WinInet. см. http://support.microsoft.com/kb/238425 для ознакомления с ограничениями WinInet в службе.

0 голосов
/ 26 ноября 2009

Видите ли вы файл cookie сеанса в запросах, поступающих от элемента управления WebBrowser? Я не могу найти ничего о том, как этот элемент управления должен обрабатывать куки - если он их игнорирует, вы получите поведение, которое вы описываете

...