Код выполняет HTTP-вызовы к открытому представлению дерева SVN. Затем он анализирует HTML и добавляет файлы для справки позже, чтобы извлечь их и отправить пользователю. Это делается в приложении WPF. Ниже приведен код вместе с изображением, показывающим структуру каталогов.
private readonly String _baseScriptURL = @"https://xxxxxxxxxx/svn/repos/xxxxxxxxxx/trunk/scripts/vbs/web/";
private void FindScripts(String url, ref ICollection 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 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;
}
Прежде всего, приносим свои извинения за длинный блок кода; однако я хотел убедиться, что весь метод был понят. Существующая проблема применима только при использовании сгенерированного исполняемого файла Release вне среды IDE. Если сборка Release выполняется в среде IDE, она работает без каких-либо проблем.
Кроме того, проблема не возникает при выполнении сгенерированной сборки Debug вне среды IDE или внутри среды IDE; он работает надлежащим образом в обоих сценариях.
Проблема в том, что рекурсивные вызовы останавливают продолжение кода после метода рекурсии. В потоке не возникает никаких исключений; все просто останавливается перед перемещением в каждый каталог, как это происходит в других сборках.
Строки журнала сборки 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]
Допрос [одноразовые /]
Поиск в каталоге [одноразовые /]
Исходный запрос [ https: // xxxxxxxxx / svn / repos / xxxxxxxxx / trunk / scripts / vbs / web / beq / one-offs /]
Получен ответ на запрос [ https: // xxxxxxxxx / svn / repos / xxxxxxxxx / trunk / scripts / vbs / web / beq / one-offs /]
Рекурсивный поиск скриптов занял [6] с. [140] мс для [1]
Анализ метаданных потребовалось [0] м [0] с [906] мс для [1]
Общее время заняло [0] м [7] с [46] мс
ОБНОВЛЕНИЕ:
После добавления примерно 3 дополнительных строк журнала во время отладки, теперь он работает должным образом. Возникающий вопрос: почему? Попытка изолировать проблемный код в отдельном приложении не дает отрицательных результатов.
Есть идеи, почему это могло произойти?
ОБНОВЛЕНИЕ:
Изменение строк журнала для вызова искусственного метода дало те же результаты. Я добавил вызовы метода faux и метода faux в приведенном выше источнике, 1 у входа в метод и 3 внизу. Сами звонки закомментированы, чтобы их было легче найти; они НЕ прокомментированы в реальном коде.
Если я закомментирую любой из 4 добавленных ложных вызовов метода, он перестанет работать. Опять же, это только в выпуске через CTRL + F5 или за пределами IDE полностью.
ОБНОВЛЕНИЕ:
Добавлен .close () в экземпляры HtmlDocument
для каждого fubaar ; такое же поведение по-прежнему проявляется.
ОБНОВЛЕНИЕ:
Добавлены явные вызовы GC для каждого fubaar; такое же поведение все еще наблюдается.