Я пытаюсь интегрировать некоторый новый код, который я написал для программного взаимодействия с Exchange 2010 через Remote Powershell в существующее приложение WinForms. Мой код работает в изолированном тестовом приложении, но когда я запускаю код в контексте моего приложения, вызов в Runspace.Open()
блокируется в течение очень долгого времени - за минусом OpenTimeout
значение 60 секунд, которое я указываю в примере WSManConnectionInfo
. Для меня это говорит о том, что в нашем коде приложения есть что-то, что создает проблему, но у меня возникают проблемы с сужением возможных причин. Приложение многопоточное и использует как BackgroundThreadWorker
, так и ThreadPool
; на самом деле мой код работает через ThreadPool
в приложении. Но я уже пробовал имитировать это в своей тестовой жгуте, и код отлично работает, когда вызывается как обратный вызов из ThreadPool
.Почему мой вызов Runspace.Open() не возвращается?
Вот код (с обработкой ошибок удаляются и постоянные определения поставить рядом):
const string EXCHANGE_PS_URI_FORMAT = "http://{0}/PowerShell/";
string uriString = string.Format(EXCHANGE_PS_URI_FORMAT, HostName);
Uri connectionUri = new Uri(uriString);
PSCredential creds = new PSCredential(username, securePwd);
const string EXCHANGE_PS_SCHEMA_URL =
"http://schemas.microsoft.com/powershell/Microsoft.Exchange";
WSManConnectionInfo connectionInfo =
new WSManConnectionInfo(connectionUri, EXCHANGE_PS_SCHEMA_URL, creds);
const int DEFAULT_OPEN_TIMEOUT = 1 * 60 * 1000; // 1 minute
connectionInfo.OpenTimeout = DEFAULT_OPEN_TIMEOUT;
const int DEFAULT_OPERATION_TIMEOUT = 4 * 60 * 1000; // 4 minutes
connectionInfo.OperationTimeout = DEFAULT_OPERATION_TIMEOUT;
using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo))
{
// BUGBUG: WHY IS THIS FAILING TO RETURN?
rs.Open(); // <-- HANGS HERE
ICollection<PSObject> newReqResults = null;
PipelineReader<object> newReqErrors = null;
try
{
using (Pipeline pipeline = rs.CreatePipeline())
{
// cmd instance is already instantiated with cmdlet info, params, etc.
pipeline.Commands.Add(cmd);
//Invoke the command and return the results and errors
newReqResults = pipeline.Invoke();
newReqErrors = pipeline.Error;
}
}
// Code to parse results and/or errors...
Стек вызовов, когда код висит на Runspace.Open()
, кажется, показывает, что внутренний код .NET застрял на ожидания звоните, но я не понимаю, как это сделать. Как я уже говорил ранее, этот код отлично работает в моем тестовом приложении, даже если он вызван как обратный вызов ThreadPool, поэтому мне интересно, что может быть в нашем главном коде приложения, который может вызвать это (контекст синхронизации или идентификатор потока или что-то еще?) Любая помощь будет принята с благодарностью. Пожалуйста, дайте мне знать, если я пренебрег включением некоторых релевантных сведений, и я с удовольствием включу их. Благодаря!
[In a sleep, wait, or join]
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x2f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x25 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0xd bytes
System.Management.Automation.dll!System.Management.Automation.Runspaces.AsyncResult.EndInvoke() + 0x14 bytes
System.Management.Automation.dll!System.Management.Automation.Runspaces.Internal.RunspacePoolInternal.EndOpen(System.IAsyncResult asyncResult) + 0xb2 bytes
System.Management.Automation.dll!System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal.Open() + 0x1a bytes
System.Management.Automation.dll!System.Management.Automation.Runspaces.RunspacePool.Open() + 0x48 bytes
System.Management.Automation.dll!System.Management.Automation.RemoteRunspace.Open() + 0x73 bytes
Это определенно вероятность того, что рабочий поток заблокирован из-за чего-то в том, как работает многопоточность. Я по-прежнему предпочитаю, чтобы код моего приложения был синхронным, но у меня может не быть выбора с надвигающимися сроками. Я посмотрю, что я могу прототип вокруг OpenAsync, но я действительно хотел бы понять причину здесь - в частности, что такое вызов ThreadPool.Open(), стоящий в ожидании? – Matt
ОК, я думаю, я понимаю, что происходит сейчас. Вы правы, что поток заблокирован; это потому, что в нашем приложении есть код для уменьшения максимального количества потоков ThreadPool, и это приводит к тупиковой операции Runspace.Open(). Если я увеличу максимальное количество потоков ThreadPool, вызов Runspace.Open() вернется, и мой код будет продолжать, как ожидалось. Несмотря на то, что мне не нужно было использовать OpenAsync(), я отмечаю это как ответ, потому что причина была правильной - поток был заблокирован. – Matt