我正在开发一个有一些跑步者的项目,每个跑步者可以同时上传文件。任意地我会得到'流不支持并发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)<---
对于这篇长篇文章感到抱歉,但我认为信息越多对你越有好处。
我正在尝试禁用身份验证和证书以进一步隔离问题。我稍后会更新。
提前致谢。任何帮助/建议/想法都非常欢迎!!!!