递归HTTP调用在IDE与已部署的可执行文件中表现出不同的行为

Aar*_*ver 8 .net c# wpf recursion http

代码正在对SVN树的公开表示进行HTTP调用.然后解析HTML并添加文件以供稍后参考,以便下拉并推送给用户.这是在WPF应用程序中完成的.下面是代码以及显示目录结构的图像.

    private readonly String _baseScriptURL = @"https://xxxxxxxxxx/svn/repos/xxxxxxxxxx/trunk/scripts/vbs/web/";

    private void FindScripts(String url, ref ICollection<String> files)
    {
        //MyFauxMethod();
        StringBuilder output = new StringBuilder();

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Credentials = new Credentials().GetCredentialCache(url);

        _logger.Log("Initiating request [" + url + "]", EventType.Debug);

        try
        {
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            using (Stream stream = response.GetResponseStream())
            {
                _logger.Log("Response received for request [" + url + "]", EventType.Debug);

                int count = 0;
                byte[] buffer = new byte[256];
                while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    if (count < 256)
                    {
                        List<byte> trimmedBuffer = buffer.ToList();
                        trimmedBuffer.RemoveRange(count, 256 - count);

                        String data = Encoding.ASCII.GetString(trimmedBuffer.ToArray());
                        output.Append(data);
                    }
                    else
                    {
                        String data = Encoding.ASCII.GetString(buffer);
                        output.Append(data);
                    }
                }
            }

            String html = output.ToString();

            HTMLDocument doc = new HTMLDocumentClass();
            IHTMLDocument2 doc2 = (IHTMLDocument2)doc;
            doc2.write(new object[] { html });

            IHTMLElementCollection ul = doc.getElementsByTagName("li");
            doc2.close();
            doc.close();                

            foreach (IHTMLElement item in ul)
            {
                if (item != null &&
                    item.innerText != null)
                {
                    String element = item.innerText.Trim().Replace(" ", "%20");

                    //nothing to do with going up a dir
                    if (element == "..")
                        continue;

                    _logger.Log("Interrogating [" + element + "]", EventType.Debug);

                    String filename = System.IO.Path.GetFileName(element);
                    if (String.IsNullOrEmpty(filename))
                    {
                        //must be a directory; recursively search if honored dir
                        if (!_ignoredDirectories.Contains(element))
                        {
                            _logger.Log("Searching directory [" + element + "]", EventType.Debug);
                            FindScripts(url + System.IO.Path.GetDirectoryName(element) + "/", ref files);
                        }
                        else
                            _logger.Log("Ignoring directory [" + element + "]", EventType.Debug);
                    }
                    else
                    {
                        //add honored files to list for parsing meta data later
                        if (_honoredExtensions.Contains(System.IO.Path.GetExtension(filename)))
                        {
                            files.Add(url + filename);
                            _logger.Log("Added file [" + (url + filename) + "]", EventType.Debug);
                        }
                    }
                    //MyFauxMethod();
                }
                //MyFauxMethod();
            }

        }
        catch (Exception e)
        {
            _logger.Log(e);
        }
        //MyFauxMethod();
    }


    private void MyFauxMethod()
    {
        int one = 1;
        int two = 2;
        int three = one + two;
    }
Run Code Online (Sandbox Code Playgroud)

目录结构

首先为漫长的代码块道歉; 但我想确定完整的方法是理解的.存在的问题仅适用于在IDE外部使用生成的Release可执行文件.如果在IDE中运行Release版本,则它的运行没有任何问题.

此外,在IDE外部或IDE内执行生成的Debug构建时,问题不存在; 它在两种情况下都能正常运行.

问题是递归调用会停止代码继续递过递归方法.线程中没有抛出异常; 一切都在移动到每个目录之前停止,就像在其他构建中一样.

Release版本的日志行如下所示......

发起请求[ https:// xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web /]
收到请求的响应[ https:// xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web /]
询问[beq /]
搜索目录[beq /]
发起请求[ https:// xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq /]
收到请求的响应[ https:// xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq /]
询问[core /]
搜索目录[core /]
发起请求[ https:// xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq/core /]
收到请求的响应[ https:// xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq/core /]
询问[BEQ-Core%20Library.vbs]
添加文件[ https:/ /xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq/core/BEQ-Core%20Library.vbs]
询问[one-offs /]
搜索目录[one-offs /]
发起请求[ https://xxxxxxxxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq/one-offs /]
收到请求的响应[ https:// xxxxxx xxx/svn/repos/xxxxxxxxx/trunk/scripts/vbs/web/beq/one-offs /]
递归查找脚本花了[6] s [140] ms [1]
解析元数据花了[0] m [0] s [906] ms为[1]
总时间为[0] m [7] s [46] ms

更新:

在调试期间添加大约3个额外的日志行后,它现在正常运行.突出的问题是为什么?尝试在单独的应用程序中隔离问题代码不会产生负面结果.

关于为什么会发生这种情况的任何想法?

更新:

更改日志行以调用虚假方法会产生相同的结果.我在上面的源代码中添加了对faux方法和faux方法的调用,方法入口处为1,底部附近为3.调用本身的注释使其更容易定位; 它们没有在实际代码中注释.

如果我注释掉4个添加的虚假方法调用中的任何一个,它将恢复为无法运行.再次,这是仅在推出通过CTRL + F5或外其全部的IDE.

更新:

HtmlDocument每个fubaar 的实例上添加了.close(); 同样的行为仍在展示中.

更新:

每个fubaar添加了对GC的显式调用; 同样的行为仍在展示中.

fub*_*aar 1

我注意到您没有在您正在创建的 HtmlDocument 实例上调用 .close() - 这将是我要尝试的第一件事,以确保 mshtml 在 write() 之后正确清理。

您还可以尝试从 Html 构建文件名列表,并在递归到文件名列表之前释放 HtmlDocument - 这样您就不会创建越来越多的 HtmlDocument 实例 - 在纯 .NET 世界中,这只是一个内存问题,但是当您涉及 mshtml 并因此涉及 COM 互操作时,根据我们的经验,通常值得更加小心地对待。

添加为编辑,因为评论太长:

在我们的 Wpf 应用程序中,我们在处理大量 HtmlDocument 实例时遇到了问题,其中 Wpf 不会定期从 COM 泵送初始化/终止消息。在我们的实现中,这导致了内存泄漏和最终的 COM 错误。这显然不是您所看到的行为,但我想知道 COM 互操作是否存在无法正确清理的问题。可能值得尝试的是在完成(并完全释放)COM 对象后添加这些行:

GC.Collect()
GC.WaitForPendingFinalizers()
Run Code Online (Sandbox Code Playgroud)

这会将任何 COM 互操作对象添加到终结器队列(.Collect 调用),并导致 .NET 泵送任何 COM 消息(WaitForPendingFinalizers 调用的副作用)。

我知道这有点在黑暗中刺伤,但这些东西本质上是 COM 互操作(即使它被 .NET 对象覆盖),这很可能就是问题所在。