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的显式调用; 同样的行为仍在展示中.
我注意到您没有在您正在创建的 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 对象覆盖),这很可能就是问题所在。