2009-11-26 104 views
2

我需要在ASP.NET应用程序中使用WinForms WebBrowser控件才能截取网页截图。将WinForms WebBrowser控件作为NETWORK_SERVICE运行

我宁愿在控制台应用程序中运行它,并通过ASP.NET应用程序与应用程序通信,但它不是我的电话,我被告知它必须作为网站的一部分运行。

除了每次调用导航都会从新会话开始新鲜开始,它就像饼干没有被持久保存一样。作为一个实验,我将我的IIS应用程序池更改为以我的身份运行而不是NETWORK_SERVICE,并且一切正常。所以它作为网络服务运行是很奇怪的。

我猜测网络服务帐户没有权限跟踪ASP.NET_SessionId cookie和auth cookie,但这两个都是非持久性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页面启动,并在backgound运行
  • ,如果我在一个IIS应用程序池集运行它,它工作正常以适当的用户身份运行
  • 如果我将其作为NETWORK_SERVICE在IIS应用程序池中运行,则每个导航都会有一个新的会话,而不是在WebBrowser的生命周期中保留一个会话。
  • 我可以在ASP.NET以外的地方正常工作,但目前这不是我的选择,它必须在此ASP.NET应用程序中运行。

//更新

在我的同事,我使用模拟在后台线程在那里我创建的web浏览器,运行的本地用户的意见。这工作正常,我很满意这个解决方案。他是一个计算器用户,所以我会让他发布答案并获得信用:)

+0

你能准确地分享你开始和停止冒充的地方吗?我有它的工作(环境。UserName会返回所期望的),但浏览器仍然不会保留cookie。相反,如果我将App Pool设置为以相同用户身份运行,那么它工作正常...... – Roman 2014-05-21 05:37:24

回答

2

在后台线程中使用模拟将允许WebBrowser以具有运行IE的权限运行的用户从而存储Cookie,而不是以应用程序池用户(NETWORK_SERVICE)运行。

您可以在web.configprogramatically中设置模拟,将其限制为特定线程。

+0

我的世界现在是一个更好的地方。 – 2009-11-27 10:45:38

0

您是否在来自WebBrowser控件的请求中看到会话cookie?我找不到这个控件应该如何处理cookie - 如果它忽略它们,你会得到你所描述的行为

+0

在任何WebBrowser属性中,在它工作的情况下,以及不在其中的情况下。我认为控制基本上运行IE浏览器,所以这是有道理的,这是一些权限问题停止工作的cookie。根据我的同事的建议,我会尝试在线程中扮演角色,让其以本地用户身份运行。 – 2009-11-27 09:15:37

2

由于使用WinInet而不是正式支持。有关WinInet在服务中的限制,请参阅http://support.microsoft.com/kb/238425

+0

感谢您的链接,这解释得非常好。 – 2009-11-30 08:25:13