HttpClient和流问题

Mar*_*ica 10 powershell multithreading stream dotnet-httpclient

一年前,我编写了一个处理Multipart/form-data请求的cmdlet,并且正在利用.net类HttpClient来实现.我在这里详细描述了它.

简而言之,这是我的cmdlet的核心:

$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()
    }
}
Run Code Online (Sandbox Code Playgroud)

我在VSTS Build任务中使用此代码超过一年成功.最近它开始间歇性地失败了.在一次运行中它成功然后下一次失败,依此类推.我不明白为什么会这样,我会用一些帮助.

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.
Run Code Online (Sandbox Code Playgroud)

我试图在不同的构建服务器,托管代理等上执行此操作,但结果是一样的.此外,如果我尝试从ISE的构建服务器上的交互式会话中执行此代码,我就无法让代码失败.我提出在VSTS类似的问题建立工作项目在这里,但直到现在,没有运气.

有没有人有建议或我可以做的测试,以了解发生了什么,为什么这会失败?

我会很感激任何提示.

更新1:

我通过Start-Job cmdlet将其作为后台作业运行来执行我的代码,我无法让它失败.因此,它需要与VSTS代理执行我的代码的方式相关.我会继续挖掘.如果您有任何建议,他们仍然欢迎.

csh*_*shu 3

System.Net.Http.StreamContent并被System.IO.FileStream实例化但未被处置。

添加要调用的代码,Dispose就像在块中所做的那样finally

try
{
    # enclose the program
}
finally
{
    if($null -ne $streamContent)
    {
        $streamContent.Dispose()
    }
    if($null -ne $packageFileStream)
    {
        $packageFileStream.Dispose()
    }
}
Run Code Online (Sandbox Code Playgroud)