System.Net.HttpClient抛出上载文件:该流不支持并发IO读取或写入操作

时间:2016-06-07 22:38:52

标签: c# .net multithreading upload dotnet-httpclient

我正在开发一个有一些跑步者的项目,每个跑步者可以同时上传文件。任意地我会得到'流不支持并发IO读或写操作'错误。

我们已经看到它发生在小(5Mb~10Mb)和大文件(1Gb~2Gb)。我们甚至尝试了完全相同的文件,我们有时可以重复它。

我们的设置具有NTLM身份验证,自签名证书以及OWIN / Katana自托管。全部使用.Net编写。

它只在VM上发生(到目前为止),我们还没有发现使用物理机器的问题,尽管其中一些虚拟机非常强大

这是我的代码:

客户端

public Guid Upload(string filePath, Guid taskId)
{
    if (string.IsNullOrEmpty(filePath)) { throw new ArgumentException("Value cannot be empty.", "filePath"); }

    var key = Guid.Empty;
    var fileInfo = new System.IO.FileInfo(filePath);

    using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
    {
        var content = new StreamContent(fileStream);
        content.Headers.Add("TaskId", taskId.ToString());
        content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        content.Headers.ContentDisposition.FileName = fileInfo.Name;
        content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        content.Headers.ContentLength = fileInfo.Length;

        key = HttpClient.PostGet<Guid>(content, "https://localhost:1234/Files/Upload");
    }

    return key;
}

public T PostGet<T>(string url, HttpContent content, IDictionary<string, string> headers)
{
    using (var client = httpClient) // <-- look below to check how we build this
    {
        client.AddHeaders(headers);
        HttpResponseMessage response = null;

        try
        {
            response = client.PostAsync(url, content).Result;

            ensureSuccessStatusCode(response);

            var jsonResult = response.Content.ReadAsStringAsync().Result;
            var obj = Deserialize<T>(jsonResult);

            return obj;
        }
        finally
        {
            if (response != null)
            {
                response.Dispose();
            }
        }
    }
}

private System.Net.Http.HttpClient httpClient
{
    get
    {
        System.Net.Http.HttpClient client = null;

        if (authenticationEnabled)
        {
            if (credentials == null)
            {
                client = new System.Net.Http.HttpClient(new CertValidatingWebRequestHandler()
                {
                    UseDefaultCredentials = true
                });
            }
            else
            {
                client = new System.Net.Http.HttpClient(new CertValidatingWebRequestHandler()
                {
                    Credentials = credentials
                });
            }
        }
        else
        {
            client = new System.Net.Http.HttpClient();
        }

        client.Timeout = TimeSpan.FromMilliseconds(TimeOutInMilliseconds);
        return client;
    }
}

public class CertValidatingWebRequestHandler : WebRequestHandler
{
    public CertValidatingWebRequestHandler()
    {
        this.ServerCertificateValidationCallback = ValidateRemoteCert;
    }

    private bool ValidateRemoteCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyErrors)
    {
        return true;
    }
}

服务器

[HttpPost]
[Route("Upload")]
public async Task<IHttpActionResult> Upload()
{
    return await upload(Guid.Empty);
}

private async Task<IHttpActionResult> upload(Guid appendToKey)
{
    if (Request.Content.Headers.ContentType.MediaType.Equals("application/octet-stream", StringComparison.OrdinalIgnoreCase))
    {
        var taskId = Guid.Empty;

        if (Request.Headers.Contains("TaskId"))
        {
            var taskIdValue = Request.Headers.GetValues("TaskId").FirstOrDefault();
            taskId = new Guid(taskIdValue);
        }

        var fileName = Request.Content.Headers.ContentDisposition.FileName;
        fileName = fileName.Trim(' ', '"');

        if (string.IsNullOrEmpty(fileName))
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }

        var key = Guid.NewGuid();
        var directoryPath = string.Empty;

        if (appendToKey == Guid.Empty)
        {
            directoryPath = createStorageDirectory(key);
        }
        else
        {
            var fileInfo = fileStorage.GetFileInfo(appendToKey);

            if (fileInfo == null)
            {
                throw new Exception(string.Format("File with key {0} was not found.", appendToKey));
            }

            directoryPath = fileInfo.Path;
        }

        var filePath = fileSystem.Combine(directoryPath, fileName);

        using (var httpStream = await Request.Content.ReadAsStreamAsync())
        {
            using (var fileStream = new FileStream(filePath, FileMode.CreateNew))
            {
                await httpStream.CopyToAsync(fileStream).ContinueWith(t =>
                {
                    try
                    {
                        handleResponse(key, directoryPath, fileName, appendToKey, taskId, t);
                    }
                    catch (Exception e)
                    {
                        deleteStorageFolder(key);

                        logger.Log(LogType.Error, e);
                        throw;
                    }
                });
            }
        }

        return Ok(key);
    }
    else
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }
}

完全错误

System.AggregateException: One or more errors occurred. ---> System.NotSupportedException: The stream does not support concurrent IO read or write operations.
       at System.Net.ConnectStream.InternalWrite(Boolean async, Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
       at System.Net.ConnectStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
       at System.Net.Http.StreamToStreamCopy.TryStartWriteSync(Int32 bytesRead)
       at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)
       --- End of inner exception stack trace ---
    ---> (Inner Exception #0) System.NotSupportedException: The stream does not support concurrent IO read or write operations.
       at System.Net.ConnectStream.InternalWrite(Boolean async, Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
       at System.Net.ConnectStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
       at System.Net.Http.StreamToStreamCopy.TryStartWriteSync(Int32 bytesRead)
       at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)<---

对于这篇长篇文章感到抱歉,但我认为信息越多对你越有好处。

我正在尝试禁用身份验证和证书以进一步隔离问题。我稍后会更新。

提前致谢。任何帮助/建议/想法都非常欢迎!!!!

0 个答案:

没有答案