Год назад я написал командлет, который обрабатывает запросы Multipart/form-data, и для этого используется класс .net класса HttpClient. Я описал его подробно здесь.
В двух словах это ядро моего командлета:
$networkCredential = New-Object -TypeName System.Net.NetworkCredential -ArgumentList @($Credential.UserName, $Credential.Password)
$httpClientHandler = New-Object -TypeName System.Net.Http.HttpClientHandler
$httpClientHandler.Credentials = $networkCredential
$httpClient = New-Object -TypeName System.Net.Http.Httpclient -ArgumentList @($httpClientHandler)
$packageFileStream = New-Object -TypeName System.IO.FileStream -ArgumentList @($packagePath, [System.IO.FileMode]::Open)
$contentDispositionHeaderValue = New-Object -TypeName System.Net.Http.Headers.ContentDispositionHeaderValue -ArgumentList @("form-data")
$contentDispositionHeaderValue.Name = "fileData"
$contentDispositionHeaderValue.FileName = $fileName
$streamContent = New-Object -TypeName System.Net.Http.StreamContent -ArgumentList @($packageFileStream)
$streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue
$streamContent.Headers.ContentType = New-Object -TypeName System.Net.Http.Headers.MediaTypeHeaderValue -ArgumentList @("application/octet-stream")
$content = New-Object -TypeName System.Net.Http.MultipartFormDataContent
$content.Add($streamContent)
try
{
$response = $httpClient.PostAsync("$EndpointUrl/package/upload/$fileName", $content).GetAwaiter().GetResult()
if (!$response.IsSuccessStatusCode)
{
$responseBody = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
$errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody
throw [System.Net.Http.HttpRequestException] $errorMessage
}
return [xml]$response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
}
catch [Exception]
{
throw
}
finally
{
if($null -ne $httpClient)
{
$httpClient.Dispose()
}
if($null -ne $response)
{
$response.Dispose()
}
}
Я использовал этот код в задаче сборки VSTS более года с успехом. В последнее время это началось с перерывами. За один проход он преуспевает, а затем следующий терпит неудачу и так далее. Я не понимаю, почему это так, и я бы воспользовался некоторой помощью.
Код не работает при вызове метода PostAsync, и следующее исключение я вижу:
2017-03-24T15:17:38.4470248Z ##[debug]System.NotSupportedException: The stream does not support concurrent IO read or write operations.
2017-03-24T15:17:38.4626512Z ##[debug] at System.Net.ConnectStream.InternalWrite(Boolean async, Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
2017-03-24T15:17:38.4626512Z ##[debug] at System.Net.ConnectStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
2017-03-24T15:17:38.4626512Z ##[debug] at System.Net.Http.StreamToStreamCopy.TryStartWriteSync(Int32 bytesRead)
2017-03-24T15:17:38.4626512Z ##[debug] at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)
2017-03-24T15:17:38.4626512Z ##[debug]--- End of stack trace from previous location where exception was thrown ---
2017-03-24T15:17:38.4626512Z ##[debug] at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
2017-03-24T15:17:38.4626512Z ##[debug] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
2017-03-24T15:17:38.4626512Z ##[debug] at CallSite.Target(Closure , CallSite , Object )
2017-03-24T15:17:38.4939015Z ##[error]The stream does not support concurrent IO read or write operations.
Я попытался выполнить это на разных серверах сборки, на размещенном агенте и т.д., но результат тот же. Также, если я попытаюсь выполнить этот код из интерактивного сеанса на моем сервере сборки из ISE, я не могу скомпрометировать код. Я задал аналогичный вопрос в проекте задачи сборки VSTS здесь, но до сих пор не повезло.
Есть ли у кого-нибудь предложение или тест, который я могу сделать, чтобы понять, что происходит и почему это не удается?
Буду признателен за любой совет.
ОБНОВЛЕНИЕ 1:
Я выполнил свой код, запустив его как фоновое задание с помощью командлета Start-Job, и я не могу заставить его сбой. Поэтому это должно быть связано с тем, как агент VSTS выполняет мой код. Я буду рыть. Если у вас есть какие-либо предложения, они по-прежнему приветствуются.